Repository: FredTingaud/quick-bench-back-end Branch: main Commit: f733445bfc8d Files: 40 Total size: 79.5 KB Directory structure: gitextract_cr8vpt3v/ ├── .github/ │ └── workflows/ │ └── ci.yml ├── .gitignore ├── LICENSE ├── README.md ├── about-container ├── app-build.js ├── app-quick.js ├── deploy ├── kill-docker ├── list-containers ├── package.json ├── pull-docker ├── quick-benchd ├── run-docker ├── run-docker-builder ├── seccomp.js ├── src/ │ ├── docker.js │ ├── libbuild.js │ ├── libquick.js │ └── tools.js ├── system-test/ │ ├── build/ │ │ └── test.cpp │ ├── build.js │ ├── env/ │ │ └── version.cpp │ ├── env.js │ ├── quick/ │ │ ├── test.cpp │ │ └── test.func │ └── quick.js └── test/ ├── clean-filename.test.js ├── code.test.js ├── containers-list.test.js ├── getFunctions.test.js ├── getv1.test.js ├── getv2.test.js ├── getv3.test.js ├── getv4.test.js ├── getv5.test.js ├── id.test.js ├── options.test.js ├── test.func └── url-name.test.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/workflows/ci.yml ================================================ name: CI on: push: branches: [ main ] pull_request: branches: [ main ] jobs: test: name: Test on node ${{ matrix.node }} and ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: matrix: node: [18] os: [ubuntu-latest] steps: - uses: actions/checkout@v4 - name: Use node ${{ matrix.node }} uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} - name: Build run: npm install - name: Test run: npm test ================================================ FILE: .gitignore ================================================ # Logs logs *.log npm-debug.log* # Runtime data pids *.pid *.seed # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage # nyc test coverage .nyc_output # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) .grunt # node-waf configuration .lock-wscript # Compiled binary addons (http://nodejs.org/api/addons.html) build/Release # Dependency directories node_modules jspm_packages # Optional npm cache directory .npm # Optional REPL history .node_repl_history public/vs # Visual Studio files .vs/ visual/ bin obj *.sln *.njsproj ================================================ FILE: LICENSE ================================================ BSD 2-Clause License Copyright (c) 2017, Fred Tingaud All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: README.md ================================================ # quick-bench-back-end Back end side of quick-bench ================================================ FILE: about-container ================================================ #!/bin/bash docker run --rm -t fredtingaud/quick-bench:"$1" /bin/bash -c ./about-me ================================================ FILE: app-build.js ================================================ #!/usr/bin/env node import express from 'express'; import cors from 'cors'; import path from 'path'; import url from 'url'; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); const app = express(); app.use(express.static(path.join(__dirname, 'quick-bench-front-end', 'build-bench', 'build'))); import bodyParser from 'body-parser'; import multer from 'multer'; import * as libbuild from './src/libbuild.js'; import * as docker from './src/docker.js'; const PORT = process.env.BB_PORT | 4000; const upload = multer(); app.use(bodyParser.json()); app.use(cors()); libbuild.updateAvailableContainersList(); app.get('/build-env', upload.array(), function (req, res) { res.json(libbuild.getEnv()); }); app.post('/build', upload.array(), function (req, res) { Promise.resolve(libbuild.benchmark(req.body, req.headers)) .then((done) => res.json(libbuild.makeBuildGraphResult(done))) .catch((err) => res.json({ messages: [err] })); }); app.get('/build/:id', upload.array(), function (req, res) { console.log('Get ' + req.params.id + ' ' + JSON.stringify(req.headers)); Promise.resolve(libbuild.reload(req.params.id)) .then((done) => res.json(libbuild.getRequestAndResult(done))) .catch(() => res.json({ messages: [`Could not load ${req.params.id}`] })); }); app.get('/containers/', upload.array(), function (req, res) { if (process.env.ALLOW_CONTAINER_DOWNLOAD) { Promise.resolve(docker.getTags()).then(t => res.json({ "tags": t })); } else { res.status(403).send({ message: 'Access Forbidden' }); } }); app.post('/containers/', upload.array(), function (req, res) { if (process.env.ALLOW_CONTAINER_DOWNLOAD) { Promise.resolve(docker.loadContainers(req.body.tags)) .then(() => libbuild.updateAvailableContainersList()) .then(() => res.json(libbuild.getEnv())) .catch(e => res.status(500).send('Could not load containers')); } else { res.status(403).send({ message: 'Access Forbidden' }); } }); app.delete('/containers/', upload.array(), function (req, res) { if (process.env.ALLOW_CONTAINER_DOWNLOAD) { Promise.resolve(docker.deleteContainers(req.body.tags)) .then(() => libbuild.updateAvailableContainersList()) .then(() => res.json(libbuild.getEnv())) .catch(e => res.status(500).send('Could not delete containers')); } else { res.status(403).send({ message: 'Access Forbidden' }); } }); app.get('/:id', upload.array(), function (req, res) { res.redirect(`/b/${req.params.id}`); }); app.get('/b/:id', upload.array(), function (req, res) { res.sendFile(path.join(__dirname, 'quick-bench-front-end', 'build-bench', 'build', 'index.html')); }); app.listen(PORT, function () { console.log(`Listening to commands on port ${PORT}`); }); ================================================ FILE: app-quick.js ================================================ #!/usr/bin/env node import express from 'express'; import cors from 'cors'; import path from 'path'; import url from 'url'; const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); const app = express(); app.use(express.static(path.join(__dirname, 'quick-bench-front-end', 'quick-bench', 'build'))); import bodyParser from 'body-parser'; import multer from 'multer'; import * as libquick from './src/libquick.js'; import * as docker from './src/docker.js'; const PORT = process.env.QB_PORT | 4000; const POST_LIMIT = process.env.QB_POST_LIMIT | (100 * 1024); const upload = multer(); app.use(bodyParser.json({limit: POST_LIMIT})); app.use(bodyParser.urlencoded({ limit: POST_LIMIT, extended: true })); app.use(cors()); libquick.updateAvailableContainersList(); app.get('/quick-env', upload.array(), function (req, res) { res.json(libquick.getEnv()); }); app.post('/quick', upload.array(), function (req, res) { Promise.resolve(libquick.benchmark(req.body, req.headers)) .then((done) => res.json(libquick.makeGraphResult(done.res ? JSON.parse(done.res) : null, done.stdout, done.id, done.annotation, done.disassemblyOption))) .catch((err) => res.json({ message: err })); }); app.get('/quick/:id', upload.array(), function (req, res) { console.log('Get ' + req.params.id + ' ' + JSON.stringify(req.headers)); Promise.resolve(libquick.reload(req.params.id)) .then((done) => res.json(libquick.getRequestAndResult(done))) .catch(() => res.json({ message: 'Could not load given id' })); }); app.get('/containers/', upload.array(), function (req, res) { if (process.env.ALLOW_CONTAINER_DOWNLOAD) { Promise.resolve(docker.getTags()).then(t => res.json({ "tags": t })); } else { res.status(403).send({ message: 'Access Forbidden' }); } }); app.post('/containers/', upload.array(), function (req, res) { if (process.env.ALLOW_CONTAINER_DOWNLOAD) { Promise.resolve(docker.loadContainers(req.body.tags)) .then(() => libquick.updateAvailableContainersList()) .then(() => res.json(libquick.getEnv())) .catch(e => res.status(500).send('Could not load containers')); } else { res.status(403).send({ message: 'Access Forbidden' }); } }); app.delete('/containers/', upload.array(), function (req, res) { if (process.env.ALLOW_CONTAINER_DOWNLOAD) { Promise.resolve(docker.deleteContainers(req.body.tags)) .then(() => libquick.updateAvailableContainersList()) .then(() => res.json(libquick.getEnv())) .catch(e => res.status(500).send('Could not delete containers')); } else { res.status(403).send({ message: 'Access Forbidden' }); } }); app.get('/q/:id', upload.array(), function (req, res) { res.sendFile(path.join(__dirname, 'quick-bench-front-end', 'quick-bench', 'build', 'index.html')); }); app.get('/:id', upload.array(), function (req, res) { res.redirect(`/q/${req.params.id}`); }); app.listen(PORT, function () { console.log(`Listening to commands on port ${PORT}`); }); ================================================ FILE: deploy ================================================ #!/bin/bash sudo yum update -y sudo yum install -y docker procmail sudo curl --silent --location https://rpm.nodesource.com/setup_8.x | sudo bash - sudo yum install -y nodejs cd /srv/quick-bench-back-end/ sudo service docker start sudo useradd -M -s /sbin/nologin -r -G docker quick-bench mkdir -m 777 -p $(printf "/data/%02x " $(seq 0 255)) sudo ./pull-docker sudo cp quick-benchd /etc/init.d/. sudo npm install sudo ./seccomp.js sudo sysctl -w kernel.perf_event_paranoid=1 sudo service quick-benchd start ================================================ FILE: kill-docker ================================================ #!/bin/bash FILE=$1.cid CONTAINERFILE=$1.cont if [ -f "$FILE" ]; then docker kill "$(cat "$FILE")" rm "$1".out rm "$1".build rm -f "$1".perf rm "$FILE" docker rm -f "$(cat "$CONTAINERFILE")" fi rm -f "$1".lock ================================================ FILE: list-containers ================================================ #!/bin/bash docker images fredtingaud/quick-bench --format "{{.Tag}}" ================================================ FILE: package.json ================================================ { "name": "quick-bench-server", "version": "1.0.0", "description": "Server side of Quick-Bench", "main": "index.js", "directories": { "test": "test" }, "scripts": { "test": "mocha --exit", "system-test": "mocha system-test --exit" }, "repository": { "type": "git", "url": "gitolite3@ns377538.ip-91-121-210.eu:quick-bench-server" }, "keywords": [ "C++", "benchmark" ], "author": "Fred Tingaud", "license": "ISC", "dependencies": { "body-parser": "^1.20.2", "child_process": "^1.0.2", "cors": "^2.8.5", "express": "^4.18.2", "multer": "^1.4.5-lts.1", "node-fetch": "^3.3.2", "sha1": "^1.1.1" }, "devDependencies": { "chai": "^4.3.8", "mocha": "^10.2.0" }, "type": "module" } ================================================ FILE: pull-docker ================================================ #!/bin/bash docker pull -a fredtingaud/quick-bench ================================================ FILE: quick-benchd ================================================ #!/bin/sh ### BEGIN INIT INFO # Provides: # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start daemon at boot time # Description: Enable service provided by daemon. ### END INIT INFO dir="/srv/quick-bench-back-end" cmd="NODE_ENV=production ./app.js" user="quick-bench" name=$(basename "$0") pid_file="/var/run/$name.pid" stdout_log="/var/log/$name.log" stderr_log="/var/log/$name.err" get_pid() { cat "$pid_file" } is_running() { [ -f "$pid_file" ] && ps "$(get_pid)" > /dev/null 2>&1 } case "$1" in start) if is_running; then echo "Already started" else echo "Starting $name" cd "$dir" if [ -z "$user" ]; then sudo "$cmd" >> "$stdout_log" 2>> "$stderr_log" & else sudo -u "$user" "$cmd" >> "$stdout_log" 2>> "$stderr_log" & fi echo $! > "$pid_file" if ! is_running; then echo "Unable to start, see $stdout_log and $stderr_log" exit 1 fi fi ;; stop) if is_running; then echo -n "Stopping $name.." kill "$(get_pid)" for i in {1..10} do if ! is_running; then break fi echo -n "." sleep 1 done echo if is_running; then echo "Not stopped; may still be shutting down or shutdown may have failed" exit 1 else echo "Stopped" if [ -f "$pid_file" ]; then rm "$pid_file" fi fi else echo "Not running" fi ;; restart) $0 stop if is_running; then echo "Unable to stop, will not attempt to start" exit 1 fi $0 start ;; status) if is_running; then echo "Running" else echo "Stopped" exit 1 fi ;; *) echo "Usage: $0 {start|stop|restart|status}" exit 1 ;; esac exit 0 ================================================ FILE: run-docker ================================================ #!/bin/bash set -e LOCAL_FILE=$(realpath "$1") COMPILER=$2 OPTIM_FLAG=$3 VERSION_FLAG=$4 ASM_FORMAT=$5 CLEAN_CACHE=$6 LIB_VERSION=$7 ADDITIONAL_FLAGS=${*:8} if ! [[ $COMPILER == "clang-"?*"."? || $COMPILER == "gcc-"?*"."? ]] ; then >&2 echo "Unknown compiler" exit 1 fi if [ "$OPTIM_FLAG" == 0 ]; then OPTIM="" elif [ "$OPTIM_FLAG" == 1 ]; then OPTIM="-O1" elif [ "$OPTIM_FLAG" == 2 ]; then OPTIM="-O2" elif [ "$OPTIM_FLAG" == 3 ]; then OPTIM="-O3" elif [ "$OPTIM_FLAG" == "S" ]; then OPTIM="-Os" elif [ "$OPTIM_FLAG" == "G" ]; then OPTIM="-Og" elif [ "$OPTIM_FLAG" == "F" ]; then OPTIM="-Ofast" else >&2 echo "Unsupported optimization flag ${OPTIM_FLAG}" exit 1 fi if [[ $VERSION_FLAG =~ c\+\+[0-9][0-9a-z] ]]; then VERSION="-std=${VERSION_FLAG}" else >&2 echo "Unknown STD version" exit 1 fi if [[ $ADDITIONAL_FLAGS =~ \B(?!\-f) ]]; then >&2 echo "Unsupported flag" exit 1 fi if [[ $ASM_FORMAT =~ ^(?!(no|att|intel).)*$ ]]; then >&2 echo "Unsupported ASM format" exit 1 fi LOCK=$LOCAL_FILE.lock lockfile "$LOCK" INFILE=$LOCAL_FILE.cpp OUTFILE=$LOCAL_FILE.out CIDFILE=$LOCAL_FILE.cid PERFFILE=$LOCAL_FILE.perf FUNCFILE=$LOCAL_FILE.func CONTAINERFILE=$LOCAL_FILE.cont if [ "$CLEAN_CACHE" = true ] && [ -f "$OUTFILE" ]; then rm "$OUTFILE" rm -f "$PERFFILE" fi if [ -f "$OUTFILE" ] && [[ "$RECORD_PERF" = false || -f "$PERFFILE" ]]; then >&2 echo "Showing cached results" else touch "$OUTFILE" chmod 666 "$OUTFILE" if [ -z "$UNLIMITED_RESOURCES" ]; then MEMORY_LIMITS='--memory=500m --cpu-period=100000 --cpu-quota=25000' fi if [ "${ASM_FORMAT}" != "no" ]; then touch "$PERFFILE" chmod 666 "$PERFFILE" ANNOTATE="--security-opt seccomp=seccomp.json" ANNOTATE_CMD=" && ./annotate -M${ASM_FORMAT}" ANNOTATE_RECORD="perf record -g" ANNOTATE_IN="docker cp $FUNCFILE \$CONTAINER:/home/builder/bench.func" ANNOTATE_OUT="docker cp \$CONTAINER:/home/builder/bench.perf $PERFFILE" fi if [[ $LIB_VERSION == llvm ]] && [[ $COMPILER == clang* ]]; then BUILD_COMMAND=build-libcxx else BUILD_COMMAND=build fi CONTAINER=$(docker create $ANNOTATE $MEMORY_LIMITS --cidfile="$CIDFILE" -t fredtingaud/quick-bench:"$COMPILER" /bin/bash -c "./$BUILD_COMMAND $OPTIM $VERSION $ADDITIONAL_FLAGS && $ANNOTATE_RECORD ./run $ANNOTATE_CMD") echo "$CONTAINER" > "$CONTAINERFILE" docker cp "$INFILE" "$CONTAINER":/home/builder/bench-file.cpp eval $ANNOTATE_IN docker start -a "$CONTAINER" docker cp "$CONTAINER":/home/builder/bench.out "$OUTFILE" eval $ANNOTATE_OUT docker rm "$CONTAINER" rm "$CONTAINERFILE" rm "$CIDFILE" fi rm -f "$LOCK" ================================================ FILE: run-docker-builder ================================================ #!/bin/bash set -e LOCAL_FILE=$(realpath "$1") COMPILER=$2 OPTIM_FLAG=$3 VERSION_FLAG=$4 CLEAN_CACHE=$6 LIB_VERSION=$7 FILE_NAME=$8.cpp RECORD_ASM=$9 RECORD_PP=${10} ADDITIONAL_FLAGS=${*:11} if ! [[ $COMPILER == "clang-"?*"."? || $COMPILER == "gcc-"?*"."? ]] ; then >&2 echo "Unknown compiler" exit 1 fi if [ "$OPTIM_FLAG" == 0 ]; then OPTIM="" elif [ "$OPTIM_FLAG" == 1 ]; then OPTIM="-O1" elif [ "$OPTIM_FLAG" == 2 ]; then OPTIM="-O2" elif [ "$OPTIM_FLAG" == 3 ]; then OPTIM="-O3" elif [ "$OPTIM_FLAG" == "S" ]; then OPTIM="-Os" elif [ "$OPTIM_FLAG" == "G" ]; then OPTIM="-Og" elif [ "$OPTIM_FLAG" == "F" ]; then OPTIM="-Ofast" else >&2 echo "Unsupported optimization flag ${OPTIM_FLAG}" exit 1 fi if [[ $VERSION_FLAG =~ c\+\+[0-9][0-9a-z] ]]; then VERSION="-std=${VERSION_FLAG}" else >&2 echo "Unknown STD version" exit 1 fi if [[ $ADDITIONAL_FLAGS =~ \B(?!\-f) ]]; then >&2 echo "Unsupported flag" exit 1 fi LOCK=$LOCAL_FILE.lock lockfile "$LOCK" INFILE=$LOCAL_FILE.cpp OUTFILE=$LOCAL_FILE.build INCLUDES=$LOCAL_FILE.inc ASM=$LOCAL_FILE.s PP=$LOCAL_FILE.i CIDFILE=$LOCAL_FILE.cid CONTAINERFILE=$LOCAL_FILE.cont if [ "$CLEAN_CACHE" = true ] && [ -f "$OUTFILE" ]; then rm "$OUTFILE" rm -f "$INCLUDES" rm -f "$ASM" rm -f "$PP" fi if [ -f "$OUTFILE" ]; then >&2 echo "Showing cached results" else touch "$OUTFILE" chmod 666 "$OUTFILE" touch "$INCLUDES" chmod 666 "$INCLUDES" if [ -z "$UNLIMITED_RESOURCES" ]; then MEMORY_LIMITS='--memory=500m --cpu-period=100000 --cpu-quota=25000' fi if [[ $LIB_VERSION == llvm ]] && [[ $COMPILER == clang* ]]; then BUILD_COMMAND=time-build-libcxx PREBUILD_COMMAND=prebuild-libcxx else BUILD_COMMAND=time-build PREBUILD_COMMAND=prebuild fi if [ "$RECORD_PP" = true ]; then touch "$PP" chmod 666 "$PP" PP_OUT="docker cp \$CONTAINER:/home/builder/bench.i $PP" fi if [ "$RECORD_ASM" != "none" ]; then touch "$ASM" chmod 666 "$ASM" ASM_OUT="docker cp \$CONTAINER:/home/builder/bench.s $ASM" fi PREBUILD_PARAMS="$RECORD_PP $RECORD_ASM" if [ -z ${BB_TIMEOUT+x} ]; then ENV_PARAMS="-e BB_TIMEOUT=$BB_TIMEOUT" fi if [ -z ${BB_MAX_ITERATION+x} ]; then ENV_PARAMS="$ENV_PARAMS -e BB_MAX=$BB_MAX_ITERATION" fi CONTAINER=$(docker create $ANNOTATE $MEMORY_LIMITS \ --cidfile="$CIDFILE" \ $ENV_PARAMS \ fredtingaud/quick-bench:"$COMPILER" /bin/bash -c "./$PREBUILD_COMMAND $FILE_NAME $PREBUILD_PARAMS $OPTIM $VERSION $ADDITIONAL_FLAGS && ./$BUILD_COMMAND $FILE_NAME $OPTIM $VERSION $ADDITIONAL_FLAGS" ) echo "$CONTAINER" > "$CONTAINERFILE" docker cp "$INFILE" "$CONTAINER":/home/builder/"$FILE_NAME" docker start -a "$CONTAINER" docker cp "$CONTAINER":/home/builder/bench.out "$OUTFILE" docker cp "$CONTAINER":/home/builder/bench.inc "$INCLUDES" eval $PP_OUT eval $ASM_OUT docker rm "$CONTAINER" rm "$CONTAINERFILE" rm "$CIDFILE" fi rm -f "$LOCK" ================================================ FILE: seccomp.js ================================================ #!/usr/bin/env node import fs from 'fs'; import https from 'https'; const req = https.request('https://raw.githubusercontent.com/moby/moby/master/profiles/seccomp/default.json', function (res) { res.setEncoding('utf-8'); let body = ''; res.on('data', function (chunk) { body = body + chunk; }); res.on('end', () => { let source = JSON.parse(body); source.syscalls[0].names.push('perf_event_open'); fs.writeFileSync('seccomp.json', JSON.stringify(source, null, 2)); }); }).on('error', (e) => { console.error('Error while getting seccomp.js:\n' + e); }); req.end(); ================================================ FILE: src/docker.js ================================================ import { exec } from 'child_process'; import fetch from 'node-fetch'; const getToken = async () => { const response = await fetch('https://auth.docker.io/token?service=registry.docker.io&scope=repository:fredtingaud/quick-bench:pull'); const auth = await response.json(); return auth['token']; }; const getTags = async () => { const token = await getToken(); const response = await fetch('https://registry-1.docker.io/v2/fredtingaud/quick-bench/tags/list', { method: "GET", headers: { "Authorization": `Bearer ${token}`, "Content-type": "application/json", "Accept": "application/json", "Accept-Charset": "utf-8" } }); const json = await response.json(); return json['tags'].sort(sortContainers); }; /* * We sort clang containers before gcc containers. * If both are from the same compiler, we want the highest version (numerically, not alphabetically) first. */ function sortContainers(c1, c2) { if (c1.startsWith('clang')) { if (c2.startsWith('clang')) { let v1 = Number.parseFloat(c1.substr('clang-'.length)); let v2 = Number.parseFloat(c2.substr('clang-'.length)); return v2 - v1; } else { return -1; } } else { if (c2.startsWith('gcc')) { let v1 = Number.parseFloat(c1.substr('gcc-'.length)); let v2 = Number.parseFloat(c2.substr('gcc-'.length)); return v2 - v1; } else { return 1; } } } function describeContainer(name) { return new Promise((resolve, reject) => { return exec('./about-container ' + name, {}, (err, stdout, stderr) => { if (err) { reject(`Couldn't describe container for ${name}:\n${stderr}`); } else { let result = {name: name}; let title = ''; for (const l of stdout.split('\n')) { const line = l.trim(); if (line === "") { continue; } if (line.startsWith('[') && line.endsWith(']')){ title = line.substring(1, line.length - 1); result[title] = []; } else { result[title].push(line) } } resolve(result); }; }); }); } function readContainersList(stdout) { return stdout.split('\n').filter(Boolean).sort(sortContainers); } function listContainers(target) { return new Promise((resolve, reject) => { return exec('./list-containers', {}, (err, stdout, stderr) => { if (err) { reject(stderr); } else { resolve(stdout); } }); }).then(stdout => { return Promise.all(readContainersList(stdout).map(c => describeContainer(c))); }).then(m => { console.log(JSON.stringify(m)); target.push(...m); }).catch(e => console.log(e)); } function loadOneContainer(container) { return new Promise((resolve, reject) => { return exec('docker pull fredtingaud/quick-bench:' + container, {}, function (err, stdout, stderr) { if (err) { reject(stderr); } else { resolve(); } }); }); } function deleteOneContainer(container) { return new Promise((resolve, reject) => { return exec('docker rmi fredtingaud/quick-bench:' + container, {}, function (err, stdout, stderr) { if (err) { reject(stderr); } else { resolve(); } }); }); } async function loadContainers(targetList) { await Promise.all(targetList.map(t => loadOneContainer(t))); } async function deleteContainers(targetList) { await Promise.all(targetList.map(t => deleteOneContainer(t))); } export { listContainers, readContainersList, getTags, loadContainers, deleteContainers }; ================================================ FILE: src/libbuild.js ================================================ import { exec } from 'child_process'; import fs from 'fs'; import * as tools from './tools.js'; import sha1 from 'sha1'; import * as docker from './docker.js'; var AVAILABLE_CONTAINERS = []; const MAX_CODE_LENGTH = process.env.BB_CODE_LIMIT || 20000; const TIMEOUT = parseInt(process.env.BB_TIMEOUT, 10) < 0 ? 0 : (parseInt(process.env.BB_TIMEOUT, 10) + 10 || 70); const ALLOW_CONTAINER_DOWNLOAD = process.env.ALLOW_CONTAINER_DOWNLOAD; const WRITE_PATH = '/data'; class BenchError extends Error{ constructor(message) { super(message); this.name = "BenchError"; } } async function listContainers() { AVAILABLE_CONTAINERS = []; await docker.listContainers(AVAILABLE_CONTAINERS); } function cleanFilename(text) { if (text === '') return '_'; return text.replace(/[^\w-]/gi, '_'); } function runDockerCommand(fileName, request, force) { return `./run-docker-builder ${fileName} ${request.compiler} ${request.optim} ${request.cppVersion} ${(request.isAnnotated || false)} ${(force || false)} ${(request.lib || 'gnu')} ${cleanFilename(request.title)} ${(request.asm || 'none')} ${(request.withPP || false)} ${request.flags.join(' ')}`; } function optionsToString(request, protocolVersion) { let options = { "protocolVersion": protocolVersion, "compiler": request.compiler, "optim": request.optim, "cppVersion": request.cppVersion, "lib": request.lib, "asm": request.asm, "preprocessed": request.withPP, "flags": request.flags }; return JSON.stringify(options); } function execute(fileName, request, protocolVersion, force) { let options = { timeout: TIMEOUT * 1000, killSignal: 'SIGKILL' }; return new Promise((resolve, reject) => { console.time(fileName); return exec(runDockerCommand(fileName, request, force), options, function (err, stdout, stderr) { if (err) { console.timeEnd(fileName); console.log('Bench failed ' + fileName); exec("./kill-docker " + fileName); reject(new BenchError("\u001b[0m\u001b[0;1;31mError or timeout\u001b[0m\u001b[1m
" + stdout + "
" + stderr)); } else { console.timeEnd(fileName); console.log('Bench done ' + fileName + (stderr.indexOf('cached results') > -1 ? ' from cache' : '')); resolve({ res: fs.readFileSync(fileName + '.build', 'utf8'), includes: fs.readFileSync(fileName + '.inc', 'utf8'), asm: request.asm && request.asm.length > 0 ? fs.readFileSync(fileName + '.s', 'utf8') : null, preprocessed: request.withPP ? fs.readFileSync(fileName + '.i', 'utf8') : null, stdout: stderr, id: tools.encodeName(makeCodeName(request, protocolVersion)), title: request.title }); } }); }); } function loadOptions(optionString) { let options = JSON.parse(optionString); if (options.cppVersion.length === 2) { options.cppVersion = 'c++' + options.cppVersion; } if (!options.flags) { options.flags = []; } return options; } function groupResults(results, id, name) { let code = results[0]; let options = results[1]; let graph = results[2]; let includes = results[3]; let preprocessed = results[4]; let asm = results[5]; return { code: code, options: loadOptions(options), graph: graph, id: id, title: name, includes: includes, preprocessed: preprocessed, asm: asm }; } function makeCodeName(tab, protocolVersion) { if (protocolVersion === 4) { return sha1(tab.code + tab.compiler + tab.optim + tab.cppVersion + tab.lib + tab.withPP + tab.asm + protocolVersion); } return sha1(tab.code + tab.compiler + tab.optim + tab.cppVersion + tab.lib + tab.withPP + tab.asm + protocolVersion + tab.flags.join(' ')); } function makeName(request) { return sha1(request.tabs.reduce(u, curr => u + makeCodeName(curr, request.protocolVersion)) + request.protocolVersion); } function filename(name) { let dir = WRITE_PATH + '/' + name.substr(0, 2); return dir + '/' + name; } async function benchmarkOneBuild(tab, protocolVersion, force) { try { if (MAX_CODE_LENGTH > 0 && tab.code.length > MAX_CODE_LENGTH) { return Promise.reject(`\u001b[0m\u001b[0;1;31mError: Unauthorized code length in {$unit.title}.\u001b[0m\u001b[1m`); } let name = makeCodeName(tab, protocolVersion); console.log('Bench ' + name + ' < ' + optionsToString(tab, protocolVersion)); let fileName = filename(name); await tools.write(fileName + '.cpp', tab.code); await tools.write(fileName + '.opt', optionsToString(tab, protocolVersion)); return await execute(fileName, tab, protocolVersion, force); } catch (e) { if (e instanceof BenchError) { return { stdout: e.message }; } else { console.log(e); return Promise.reject('Unexpected error while processing the benchmark, please contact the website owner'); } } } async function benchmark(request, header) { return await Promise.all(request.tabs.map(u => benchmarkOneBuild(u, request.protocolVersion, request.force))); } async function reloadOne(id, name) { const fileName = filename(id); const values = await Promise.all([tools.read(fileName + '.cpp'), tools.read(fileName + '.opt'), tools.read(fileName + '.build'), tools.read(fileName + '.inc'), tools.read(fileName + '.i', true), tools.read(fileName + '.s', true)]); return groupResults(values, id, name); } async function reload(encodedName) { let fileName = filename(tools.decodeName(encodedName)); const ids = await tools.read(fileName + '.res'); return await Promise.all(ids.split("\n").map(s => { const info = s.split("\t"); return reloadOne(tools.decodeName(info[0]), info[1]); })); } function readBuildResults(values) { if (!values.res) return {}; let results = values.res.split('\n'); let times = []; let memories = []; let inputs = []; let outputs = []; let pagefaults = []; for (let i = 0; i < results.length; i++) { let s = results[i].split('\t'); if (s.length === 7) { times.push({ user: s[0], kernel: s[1] }); memories.push(s[2]); inputs.push(s[3]); outputs.push(s[4]); pagefaults.push({ major: s[5], minor: s[6] }); } } return { times: times, memories: memories, inputs: inputs, outputs: outputs, pagefaults: pagefaults }; } function makeBuildGraphResult(values) { let result = values.map(v => readBuildResults(v)); let messages = values.map(v => v.stdout); let includes = values.map(v => v.includes); let asm = values.map(v => v.asm); let preprocessed = values.map(v => v.preprocessed); let idsList = values.map(v => `${v.id}\t${v.title}`).reduce((r, v) => r + '\n' + v); let id = sha1(idsList); tools.write(filename(id) + '.res', idsList); return { result: result, messages: messages, includes: includes, asm: asm, preprocessed: preprocessed, id: tools.encodeName(id) }; } function makeOneRequest(done) { return { code: done.code, compiler: done.options.compiler, optim: done.options.optim, cppVersion: done.options.cppVersion, lib: done.options.lib, protocolVersion: done.options.protocolVersion, title: done.title, flags: done.options.flags, }; } function getRequestAndResult(done) { return Object.assign({ tabs: done.map(d => makeOneRequest(d)) }, makeBuildGraphResult(done.map(d => { return { res: d.graph, stdout: '', includes: d.includes, asm: d.asm, preprocessed: d.preprocessed, id: tools.encodeName(d.id) }; }))); } function getEnv() { return { maxCodeLength: MAX_CODE_LENGTH, timeout: TIMEOUT, containers: AVAILABLE_CONTAINERS, containerDl: ALLOW_CONTAINER_DOWNLOAD }; } export { listContainers as updateAvailableContainersList, makeName, groupResults, optionsToString, execute, cleanFilename, makeBuildGraphResult, benchmark, reload, getRequestAndResult, getEnv }; ================================================ FILE: src/libquick.js ================================================ import { exec } from 'child_process'; import sha1 from 'sha1'; import fs from 'fs'; import * as tools from './tools.js'; import * as docker from './docker.js'; const MAX_CODE_LENGTH = process.env.QB_CODE_LIMIT || 20000; const TIMEOUT = parseInt(process.env.QB_TIMEOUT, 10) < 0 ? 0 : (parseInt(process.env.QB_TIMEOUT, 10) || 120); const ALLOW_CONTAINER_DOWNLOAD = process.env.ALLOW_CONTAINER_DOWNLOAD; const WRITE_PATH = '/data'; const PREFIX_CODE_1 = `#include `; const SUFFIX_CODE_1 = ` static void Noop(benchmark::State& state) { while (state.KeepRunning()); } BENCHMARK(Noop); BENCHMARK_MAIN()`; const PREFIX_CODE_2 = `#include `; const SUFFIX_CODE_2 = ` static void Noop(benchmark::State& state) { for (auto _ : state) benchmark::DoNotOptimize(0); } BENCHMARK(Noop); BENCHMARK_MAIN()`; const SUFFIX_CODE_3 = ` static void Noop(benchmark::State& state) { for (auto _ : state) benchmark::DoNotOptimize(0); } BENCHMARK(Noop); BENCHMARK_MAIN();`; var AVAILABLE_CONTAINERS = []; class BenchError extends Error{ constructor(message) { super(message); this.name = "BenchError"; } } async function listContainers() { AVAILABLE_CONTAINERS = []; await docker.listContainers(AVAILABLE_CONTAINERS); } function runDockerCommand(fileName, request) { return './run-docker ' + fileName + ' ' + request.options.compiler + ' ' + request.options.optim + ' ' + request.options.cppVersion + ' ' + (request.disassemblyOption || 'no') + ' ' + (request.force || false) + ' ' + (request.options.lib || 'gnu') + request.options.flags.join(' '); } function optionsToString(request) { let options = { protocolVersion: request.protocolVersion, disassemblyOption: request.disassemblyOption, compiler: request.options.compiler, optim: request.options.optim, cppVersion: request.options.cppVersion, lib: request.options.lib, flags: request.options.flags, }; return JSON.stringify(options); } function execute(fileName, request) { let options = { timeout: TIMEOUT * 1000, killSignal: 'SIGKILL' }; return new Promise((resolve, reject) => { console.time(fileName); return exec(runDockerCommand(fileName, request), options, function (err, stdout, stderr) { if (err) { console.timeEnd(fileName); console.log('Bench failed ' + fileName); exec("./kill-docker " + fileName); reject(new BenchError("\u001b[0m\u001b[0;1;31mError or timeout\u001b[0m\u001b[1m
" + stdout + "
" + stderr)); } else { console.timeEnd(fileName); console.log('Bench done ' + fileName + (stderr.indexOf('cached results') > -1 ? ' from cache' : '')); const perfRecorded = !request.disassemblyOption.match("no") resolve({ res: fs.readFileSync(fileName + '.out'), stdout: stderr, id: tools.encodeName(makeName(request)), annotation: perfRecorded? fs.readFileSync(fileName + '.perf', 'utf8') : null, disassemblyOption: request.disassemblyOption, }); } }); }); } function parseOptions(optionsString) { let options = JSON.parse(optionsString); if (options.cppVersion.length === 2) { options.cppVersion = 'c++' + options.cppVersion; } if (!options.flags) { options.flags = []; } return options; } function groupResults(results) { let code = unwrapCode(results[0]); let options = results[1]; let graph = results[2]; let annotation = results[3]; let parsedOptions = parseOptions(options); let disassemblyOption = "no" if (parsedOptions.disassemblyOption) { disassemblyOption = parsedOptions.disassemblyOption; delete parsedOptions.disassemblyOption; } else if (parsedOptions.isAnnotated) { disassemblyOption = "att"; delete parsedOptions.isAnnotated; } return { code: code, options: parsedOptions, graph: JSON.parse(graph), annotation: annotation, disassemblyOption: disassemblyOption }; } function makeName(request) { if (request.protocolVersion === 1) return sha1(request.code + request.compiler + request.optim + request.cppVersion + request.protocolVersion); if (request.protocolVersion === 2) return sha1(request.code + request.compiler + request.optim + request.cppVersion + request.isAnnotated + request.protocolVersion); if (request.protocolVersion === 3) return sha1(request.code + request.compiler + request.optim + request.cppVersion + request.isAnnotated + request.protocolVersion + request.lib); if (request.protocolVersion === 4) return sha1(request.code + request.options.compiler + request.options.optim + request.options.cppVersion + request.isAnnotated + request.protocolVersion + request.options.lib); return sha1(request.code + request.options.compiler + request.options.optim + request.options.cppVersion + request.disassemblyOption + request.protocolVersion + request.options.lib + request.options.flags.join(' ')); } function wrapCode(inputCode) { return PREFIX_CODE_2 + inputCode + SUFFIX_CODE_3; } function unwrapCode(inputCode) { if (inputCode.startsWith(PREFIX_CODE_1)) { inputCode = inputCode.slice(PREFIX_CODE_1.length); } if (inputCode.endsWith(SUFFIX_CODE_1)) { inputCode = inputCode.slice(0, -SUFFIX_CODE_1.length); } if (inputCode.startsWith(PREFIX_CODE_2)) { inputCode = inputCode.slice(PREFIX_CODE_2.length); } if (inputCode.endsWith(SUFFIX_CODE_2)) { inputCode = inputCode.slice(0, -SUFFIX_CODE_2.length); } if (inputCode.endsWith(SUFFIX_CODE_3)) { inputCode = inputCode.slice(0, -SUFFIX_CODE_3.length); } return inputCode; } function getFunctions(code) { const RE = /BENCHMARK\s*\(\s*([A-Za-z0-9_]+)\s*\)/g; let content = ''; let res; while ((res = RE.exec(code)) !== null) { content += res[1] + '\n'; } return content; } async function benchmark(request, header) { try { if (MAX_CODE_LENGTH > 0 && request.code.length > MAX_CODE_LENGTH) { return Promise.reject('\u001b[0m\u001b[0;1;31mError: Unauthorized code length.\u001b[0m\u001b[1m'); } let name = makeName(request); console.log('Bench ' + name + ' ' + JSON.stringify(header) + ' < ' + optionsToString(request)); var dir = WRITE_PATH + '/' + name.substr(0, 2); var fileName = dir + '/' + name; await tools.write(fileName + '.cpp', wrapCode(request.code)); await tools.write(fileName + '.func', getFunctions(request.code)); await tools.write(fileName + '.opt', optionsToString(request)); return await execute(fileName, request); } catch (e) { if (e instanceof BenchError) { return { stdout: e.message }; } else { console.log(e); return Promise.reject('Unexpected error while processing the benchmark, please contact the website owner'); } } } async function reload(encodedName) { let name = tools.decodeName(encodedName); var dir = WRITE_PATH + '/' + name.substr(0, 2); var fileName = dir + '/' + name; let values = await Promise.all([tools.read(fileName + '.cpp'), tools.read(fileName + '.opt'), tools.read(fileName + '.out'), tools.read(fileName + '.perf', true)]) return groupResults(values); } function makeGraphResult(values, message, id, annotation, disassemblyOption) { let result = {}; if (values) { result = { context: values.context }; const noopTime = values.benchmarks[values.benchmarks.length - 1].cpu_time; result.benchmarks = values.benchmarks.map(obj => { return { name: obj.name, cpu_time: obj.cpu_time / noopTime }; }); } return { result: result, message: message, id: id, annotation: annotation, disassemblyOption: disassemblyOption}; } function makeRequest(done) { return { code: done.code, options: { compiler: done.options.compiler, optim: done.options.optim, cppVersion: done.options.cppVersion, lib: done.options.lib, flags: done.options.flags }, disassemblyOption: done.options.disassemblyOption, protocolVersion: done.options.protocolVersion }; } function getRequestAndResult(done) { const request = makeRequest(done); return Object.assign({ tab: request }, makeGraphResult(done.graph, '', tools.encodeName(makeName(request)), done.annotation, done.disassemblyOption)); } function getEnv() { return { maxCodeLength: MAX_CODE_LENGTH, timeout: TIMEOUT, containers: AVAILABLE_CONTAINERS, containerDl: ALLOW_CONTAINER_DOWNLOAD }; } export { listContainers as updateAvailableContainersList, makeName, wrapCode, unwrapCode, groupResults, getFunctions, optionsToString, execute, benchmark, makeGraphResult, reload, makeRequest, getRequestAndResult, getEnv }; ================================================ FILE: src/tools.js ================================================ import fs from 'fs'; function write(fileName, code) { return new Promise((resolve, reject) => { fs.writeFile(fileName, code, (err) => { if (err) { reject(err); } else { resolve(); } }); }); } function read(fileName, acceptMissing) { return new Promise((resolve, reject) => { fs.readFile(fileName, 'utf8', (err, data) => { if (err) { if (acceptMissing && err.code === 'ENOENT') { resolve(null); } else { reject(err); } } else { resolve(data); } }); }); } function encodeName(id) { let short = Buffer.from(id, 'hex').toString('base64'); short = short.replace(new RegExp('/', 'g'), '-').replace(new RegExp('\\+', 'g'), '_'); return short.slice(0, -1); } function decodeName(short) { short = short.replace(new RegExp('\\-', 'g'), '/').replace(new RegExp('_', 'g'), '+ ') + '='; return Buffer.from(short, 'base64').toString('hex'); } export {read, write, encodeName, decodeName}; ================================================ FILE: system-test/build/test.cpp ================================================ #include int main() { puts("Hello World"); return 0; } ================================================ FILE: system-test/build.js ================================================ import * as libbuild from '../src/libbuild.js'; import { expect } from 'chai'; import fs from 'fs'; const version = process.env.QB_VERSION; function removeIfExists(path) { try { fs.unlinkSync(path); } catch (ignore) { //ignore } } describe('run build-bench', function () { before(function () { removeIfExists('./system-test/build/test.lock'); }); it('should have build results', async () => { const request = { compiler: version, optim: 3, cppVersion: 'c++1z', lib: "gnu", title: "cstdio", asm: "att", withPP: true, flags: [] }; expect(version).to.be.ok; const done = await libbuild.execute('system-test/build/test', request, 3, true); // Time results are rows of 7 elements separated by tabs expect(done.res.split('\n')).to.have.lengthOf.above(1); expect(done.res.split('\n')[0].split('\t')).to.have.length(7); // There should be includes expect(done.includes.split('\n')).to.have.lengthOf.above(1); expect(done.includes).to.have.string('cstdio'); // There should be assembly expect(done.asm.split('\n')).to.have.lengthOf.above(1); expect(done.asm).to.have.string('cstdio'); // There should be preprocessed code expect(done.preprocessed.split('\n')).to.have.lengthOf.above(1); expect(done.preprocessed).to.have.string('cstdio'); expect(done.title).to.equal('cstdio'); }).timeout(120000); after(function () { removeIfExists('./system-test/build/test.build'); removeIfExists('./system-test/build/test.i'); removeIfExists('./system-test/build/test.inc'); removeIfExists('./system-test/build/test.s'); }); }); ================================================ FILE: system-test/env/version.cpp ================================================ #include int main() { #ifdef __clang__ std::cout << "clang-" << __clang_major__ << "." << __clang_minor__; #else std::cout << "gcc-" << __GNUC__ << "." << __GNUC_MINOR__; #endif return 0; } ================================================ FILE: system-test/env.js ================================================ import { expect } from 'chai'; import { exec } from 'child_process'; import { fileURLToPath } from 'url'; import { dirname } from 'path'; const version = process.env.QB_VERSION; const __dirname = dirname(fileURLToPath(import.meta.url)); describe('check compiler version inside docker', function () { it('should have the same version', async () => { let options = { timeout: 60000, killSignal: 'SIGKILL' }; const result = await new Promise((resolve, reject) => exec(`docker run --rm -v ${__dirname}/env/version.cpp:/home/builder/bench-file.cpp -t fredtingaud/quick-bench:${version} /bin/bash -c "./build && ./run"`, options, (err, stdout, stderr) => { if (err) { reject(stderr); } else { resolve(stdout); } })); expect(result).to.eql(version); }).timeout(60000); }); describe('check available flags', function () { it('should contain multiple standards', async () => { let options = { timeout: 60000, killSignal: 'SIGKILL' }; const result = await new Promise((resolve, reject) => exec(`docker run --rm -t fredtingaud/quick-bench:${version} /bin/bash -c "./about-me"`, options, (err, stdout, stderr) => { if (err) { reject(stdout); } else { resolve(stdout); } })); // No idea why but despite the whole chain being unix talking to unix, we get a bunch of \r in chai results. expect(result.replaceAll('\r', '')).to.be.a('string').and.satisfy(msg => msg.startsWith('[version]\n1\n[std]')); expect(result).to.have.string('c++11'); expect(result).to.have.string('[experimental]'); }).timeout(60000); }) ================================================ FILE: system-test/quick/test.cpp ================================================ #include #include #include #include static void BM_StringCreation(benchmark::State& state) { std::vector a = {4, 5, 0, 1, -5}; while (state.KeepRunning()) { auto v = a; std::sort( v.begin(), v.end() ); } } // Register the function as a benchmark BENCHMARK(BM_StringCreation); // Define another benchmark static void BM_StringCopy(benchmark::State& state) { std::vector a = {4, 5, 0, 1, -5}; while (state.KeepRunning()) { auto v = a; ranges::sort( v ); } } BENCHMARK(BM_StringCopy); BENCHMARK_MAIN(); ================================================ FILE: system-test/quick/test.func ================================================ BM_StringCreation BM_StringCopy ================================================ FILE: system-test/quick.js ================================================ import * as libquick from '../src/libquick.js'; import { expect } from 'chai'; import fs from 'fs'; const version = process.env.QB_VERSION; function removeIfExists(path) { try { fs.unlinkSync(path); } catch (ignore) { //ignore } } describe('run docker with version', function () { before(function () { removeIfExists('./system-test/quick/test.lock'); }); it('should have benchmark results', async () => { const request = { options: { compiler: version, optim: 3, cppVersion: "c++1z", lib: "gnu", flags: [] }, disassemblyOption: "att", force: "true" }; expect(version).to.be.ok; const done = await libquick.execute('system-test/quick/test', request); const parsed = JSON.parse(done.res); expect(parsed.benchmarks).to.have.length(2); expect(done.annotation).to.be.ok; expect(done.annotation.split('\n')).to.have.lengthOf.above(7); expect(done.annotation).to.have.string('BM_StringCreation'); expect(done.annotation).to.have.string('BM_StringCopy'); // expect(done.stdout).to.be.empty; // Removed because of a Docker message on my Ubuntu version. console.log(done.stdout); expect(done.annotation).to.be.ok; }).timeout(120000); if (version.startsWith('clang')) { it('should have benchmark results with libcxx', async () => { const request = { options: { compiler: version, optim: 3, cppVersion: "c++1z", lib: "llvm", flags: [] }, disassemblyOption: "att", force: "true" }; expect(version).to.be.ok; const done = await libquick.execute('system-test/quick/test', request); const parsed = JSON.parse(done.res); expect(parsed.benchmarks).to.have.length(2); expect(done.annotation).to.be.ok; expect(done.annotation.split('\n')).to.have.lengthOf.above(7); expect(done.annotation).to.have.string('BM_StringCreation'); expect(done.annotation).to.have.string('BM_StringCopy'); // expect(done.stdout).to.be.empty; // Removed because of a Docker message on my Ubuntu version. console.log(done.stdout); expect(done.annotation).to.be.ok; }).timeout(120000); } after(function () { removeIfExists('./system-test/quick/test.out'); removeIfExists('./system-test/quick/test.perf'); }); }); ================================================ FILE: test/clean-filename.test.js ================================================ import * as app from '../src/libbuild.js'; import assert from 'assert'; describe('clean unwanted characters', function () { it('should keep words', function () { assert.equal(app.cleanFilename('cstdio'), 'cstdio'); }); it('should keep - and _', function () { assert.equal(app.cleanFilename('c_str-1'), 'c_str-1'); }); it('should not keep unwanted characters', function () { assert.equal(app.cleanFilename('c/test\t\nunwanted./**/$^%'), 'c_test__unwanted________'); }); it('should not keep emojis', function () { assert.equal(app.cleanFilename('😊'), '__'); }); it('should have a name', function () { assert.equal(app.cleanFilename(''), '_'); }); }); ================================================ FILE: test/code.test.js ================================================ import * as libquick from '../src/libquick.js'; import assert from 'assert'; const startCode = `static void BM_StringCreation(benchmark::State& state) { while (state.KeepRunning()) std::string empty_string; } // Register the function as a benchmark BENCHMARK(BM_StringCreation); static void BM_StringCopy(benchmark::State& state) { std::string x = "hello"; while (state.KeepRunning()) std::string copy(x); } BENCHMARK(BM_StringCopy); `; const code1 = `#include static void BM_StringCreation(benchmark::State& state) { while (state.KeepRunning()) std::string empty_string; } // Register the function as a benchmark BENCHMARK(BM_StringCreation); static void BM_StringCopy(benchmark::State& state) { std::string x = "hello"; while (state.KeepRunning()) std::string copy(x); } BENCHMARK(BM_StringCopy); static void Noop(benchmark::State& state) { while (state.KeepRunning()); } BENCHMARK(Noop); BENCHMARK_MAIN()`; const code2 = `#include static void BM_StringCreation(benchmark::State& state) { while (state.KeepRunning()) std::string empty_string; } // Register the function as a benchmark BENCHMARK(BM_StringCreation); static void BM_StringCopy(benchmark::State& state) { std::string x = "hello"; while (state.KeepRunning()) std::string copy(x); } BENCHMARK(BM_StringCopy); static void Noop(benchmark::State& state) { for (auto _ : state) benchmark::DoNotOptimize(0); } BENCHMARK(Noop); BENCHMARK_MAIN()`; const code3 = `#include static void BM_StringCreation(benchmark::State& state) { while (state.KeepRunning()) std::string empty_string; } // Register the function as a benchmark BENCHMARK(BM_StringCreation); static void BM_StringCopy(benchmark::State& state) { std::string x = "hello"; while (state.KeepRunning()) std::string copy(x); } BENCHMARK(BM_StringCopy); static void Noop(benchmark::State& state) { for (auto _ : state) benchmark::DoNotOptimize(0); } BENCHMARK(Noop); BENCHMARK_MAIN();`; describe('symetrical', function () { it('should return initial value when wrapping then unwrapping', function () { assert.equal(libquick.unwrapCode(libquick.wrapCode(startCode)), startCode); }); it('should return initial value when unwrapping a v1 code', function () { assert.equal(libquick.unwrapCode(code1), startCode); }); it('should return initial value when unwrapping a v2 code', function () { assert.equal(libquick.unwrapCode(code2), startCode); }); it('should return initial value when unwrapping a v3 code', function () { assert.equal(libquick.unwrapCode(code3), startCode); }); }) ================================================ FILE: test/containers-list.test.js ================================================ import * as app from '../src/docker.js'; import assert from 'assert'; describe('list containers list', function () { it('should support empty list', function () { assert.deepEqual(app.readContainersList(''), []); }); it('should parse one value', function () { assert.deepEqual(app.readContainersList('clang-10.1'), ['clang-10.1']); }); it('should order by decreasing version', function () { assert.deepEqual(app.readContainersList('clang-10.1\nclang-8.1\nclang-9.0'), ['clang-10.1', 'clang-9.0', 'clang-8.1']); }); it('should sort clang first and gcc next', function () { assert.deepEqual(app.readContainersList('clang-10.1\ngcc-9.1\nclang-9.0\ngcc-12.7'), ['clang-10.1', 'clang-9.0', 'gcc-12.7', 'gcc-9.1']); }); }); ================================================ FILE: test/getFunctions.test.js ================================================ import * as libquick from '../src/libquick.js'; import assert from 'assert'; const startCode = `static void BM_StringCreation(benchmark::State& state) { while (state.KeepRunning()) std::string empty_string; } // Register the function as a benchmark BENCHMARK(BM_StringCreation); static void BM_StringCopy(benchmark::State& state) { std::string x = "hello"; while (state.KeepRunning()) std::string copy(x); } BENCHMARK(BM_StringCopy); `; const repeatCode = ` static void CopyStrings(benchmark::State& state) { while (state.KeepRunning()) benchmark::DoNotOptimize(std::string(state.range(0), 'x')); } BENCHMARK(CopyStrings)->Arg(5)->Arg(10)->Arg(15)->Arg(16)->Arg(20)->Arg(25); `; const spacesCode = ` BENCHMARK( A); BENCHMARK(B ); BENCHMARK( C ); BENCHMARK( D D ); BENCHMARK (E); ` describe('Find functions', function () { it('should find simple functions', function () { assert.equal(libquick.getFunctions(startCode), 'BM_StringCreation\nBM_StringCopy\n'); }); it('should find repeated benchmarks', function () { assert.equal(libquick.getFunctions(repeatCode), 'CopyStrings\n'); }); it('should support spaces arround name', function () { assert.equal(libquick.getFunctions(spacesCode), 'A\nB\nC\nE\n'); }); }) ================================================ FILE: test/getv1.test.js ================================================ import * as libquick from '../src/libquick.js'; import assert from 'assert'; const OPTIONS = '{"protocolVersion":1,"compiler":"clang++-3.8","optim":"1","cppVersion":"17"}'; const OUTPUT = `{ "context": { "date": "2017-06-03 16:27:30", "num_cpus": 1, "mhz_per_cpu": 2400, "cpu_scaling_enabled": false, "library_build_type": "release" }, "benchmarks": [ { "name": "BM_StringCreation", "iterations": 110509442, "real_time": 25, "cpu_time": 6, "time_unit": "ns" }, { "name": "BM_StringCopy", "iterations": 32549672, "real_time": 86, "cpu_time": 22, "time_unit": "ns" }, { "name": "Noop", "iterations": 250612168, "real_time": 11, "cpu_time": 3, "time_unit": "ns" } ] }`; const INPUT = `#include static void BM_StringCreation(benchmark::State& state) { while (state.KeepRunning()) std::string empty_string; } // Register the function as a benchmark BENCHMARK(BM_StringCreation); static void BM_StringCopy(benchmark::State& state) { std::string x = "hello"; while (state.KeepRunning()) std::string copy(x); } BENCHMARK(BM_StringCopy); static void Noop(benchmark::State& state) { while (state.KeepRunning()); } BENCHMARK(Noop); BENCHMARK_MAIN()`; const EXPECTED = { code: `static void BM_StringCreation(benchmark::State& state) { while (state.KeepRunning()) std::string empty_string; } // Register the function as a benchmark BENCHMARK(BM_StringCreation); static void BM_StringCopy(benchmark::State& state) { std::string x = "hello"; while (state.KeepRunning()) std::string copy(x); } BENCHMARK(BM_StringCopy); `, graph: { benchmarks: [ { "cpu_time": 6, "iterations": 110509442, "name": "BM_StringCreation", "real_time": 25, "time_unit": "ns" }, { "cpu_time": 22, "iterations": 32549672, "name": "BM_StringCopy", "real_time": 86, "time_unit": "ns", }, { "cpu_time": 3, "iterations": 250612168, "name": "Noop", "real_time": 11, "time_unit": "ns" }, ], context: { cpu_scaling_enabled: false, date: "2017-06-03 16:27:30", library_build_type: "release", mhz_per_cpu: 2400, num_cpus: 1 } }, options: { compiler: "clang++-3.8", cppVersion: "c++17", optim: "1", flags: [], protocolVersion: 1 }, disassemblyOption: "no", annotation: undefined }; describe('Return v1 stored file', function () { it('should return a stable message with protocol 1', function () { return assert.deepEqual(libquick.groupResults([INPUT, OPTIONS, OUTPUT]), EXPECTED); }); }); ================================================ FILE: test/getv2.test.js ================================================ import * as libquick from '../src/libquick.js'; import assert from 'assert'; const OPTIONS = '{"protocolVersion":2,"compiler":"clang++-3.8","optim":"1","cppVersion":"17","isAnnotated":true}'; const OUTPUT = `{ "context": { "date": "2017-06-03 16:27:30", "num_cpus": 1, "mhz_per_cpu": 2400, "cpu_scaling_enabled": false, "library_build_type": "release" }, "benchmarks": [ { "name": "BM_StringCreation", "iterations": 110509442, "real_time": 25, "cpu_time": 6, "time_unit": "ns" }, { "name": "BM_StringCopy", "iterations": 32549672, "real_time": 86, "cpu_time": 22, "time_unit": "ns" }, { "name": "Noop", "iterations": 250612168, "real_time": 11, "cpu_time": 3, "time_unit": "ns" } ] }`; const ANNOTATION = 'Some annotations.'; const INPUT = `#include static void BM_StringCreation(benchmark::State& state) { while (state.KeepRunning()) std::string empty_string; } // Register the function as a benchmark BENCHMARK(BM_StringCreation); static void BM_StringCopy(benchmark::State& state) { std::string x = "hello"; while (state.KeepRunning()) std::string copy(x); } BENCHMARK(BM_StringCopy); static void Noop(benchmark::State& state) { while (state.KeepRunning()); } BENCHMARK(Noop); BENCHMARK_MAIN()`; const EXPECTED = { code: `static void BM_StringCreation(benchmark::State& state) { while (state.KeepRunning()) std::string empty_string; } // Register the function as a benchmark BENCHMARK(BM_StringCreation); static void BM_StringCopy(benchmark::State& state) { std::string x = "hello"; while (state.KeepRunning()) std::string copy(x); } BENCHMARK(BM_StringCopy); `, graph: { benchmarks: [ { "cpu_time": 6, "iterations": 110509442, "name": "BM_StringCreation", "real_time": 25, "time_unit": "ns" }, { "cpu_time": 22, "iterations": 32549672, "name": "BM_StringCopy", "real_time": 86, "time_unit": "ns", }, { "cpu_time": 3, "iterations": 250612168, "name": "Noop", "real_time": 11, "time_unit": "ns" }, ], context: { cpu_scaling_enabled: false, date: "2017-06-03 16:27:30", library_build_type: "release", mhz_per_cpu: 2400, num_cpus: 1 } }, options: { compiler: "clang++-3.8", cppVersion: "c++17", optim: "1", flags: [], protocolVersion: 2 }, disassemblyOption: "att", annotation: "Some annotations." }; describe('Return v2 stored file', function () { it('should return a stable message with protocol 2', function () { return assert.deepEqual(libquick.groupResults([INPUT, OPTIONS, OUTPUT, ANNOTATION]), EXPECTED); }); }); ================================================ FILE: test/getv3.test.js ================================================ import * as libquick from '../src/libquick.js'; import assert from 'assert'; const OPTIONS = '{"protocolVersion":3,"compiler":"clang-9.1","optim":"1","cppVersion":"17","isAnnotated":true,"lib":"llvm"}'; const OUTPUT = `{ "context": { "date": "2017-06-03 16:27:30", "num_cpus": 1, "mhz_per_cpu": 2400, "cpu_scaling_enabled": false, "library_build_type": "release" }, "benchmarks": [ { "name": "BM_StringCreation", "iterations": 110509442, "real_time": 25, "cpu_time": 6, "time_unit": "ns" }, { "name": "BM_StringCopy", "iterations": 32549672, "real_time": 86, "cpu_time": 22, "time_unit": "ns" }, { "name": "Noop", "iterations": 250612168, "real_time": 11, "cpu_time": 3, "time_unit": "ns" } ] }`; const ANNOTATION = 'Some annotations.'; const INPUT = `#include static void BM_StringCreation(benchmark::State& state) { while (state.KeepRunning()) std::string empty_string; } // Register the function as a benchmark BENCHMARK(BM_StringCreation); static void BM_StringCopy(benchmark::State& state) { std::string x = "hello"; while (state.KeepRunning()) std::string copy(x); } BENCHMARK(BM_StringCopy); static void Noop(benchmark::State& state) { while (state.KeepRunning()); } BENCHMARK(Noop); BENCHMARK_MAIN()`; const EXPECTED = { code: `static void BM_StringCreation(benchmark::State& state) { while (state.KeepRunning()) std::string empty_string; } // Register the function as a benchmark BENCHMARK(BM_StringCreation); static void BM_StringCopy(benchmark::State& state) { std::string x = "hello"; while (state.KeepRunning()) std::string copy(x); } BENCHMARK(BM_StringCopy); `, graph: { benchmarks: [ { "cpu_time": 6, "iterations": 110509442, "name": "BM_StringCreation", "real_time": 25, "time_unit": "ns" }, { "cpu_time": 22, "iterations": 32549672, "name": "BM_StringCopy", "real_time": 86, "time_unit": "ns", }, { "cpu_time": 3, "iterations": 250612168, "name": "Noop", "real_time": 11, "time_unit": "ns" }, ], context: { cpu_scaling_enabled: false, date: "2017-06-03 16:27:30", library_build_type: "release", mhz_per_cpu: 2400, num_cpus: 1 } }, options: { compiler: "clang-9.1", cppVersion: "c++17", optim: "1", lib: "llvm", flags: [], protocolVersion: 3 }, disassemblyOption: "att", annotation: "Some annotations." }; describe('Return v3 stored file', function () { it('should return a stable message with protocol 3', function () { return assert.deepEqual(libquick.groupResults([INPUT, OPTIONS, OUTPUT, ANNOTATION]), EXPECTED); }); }); ================================================ FILE: test/getv4.test.js ================================================ import * as libquick from '../src/libquick.js'; import assert from 'assert'; const OPTIONS = '{"protocolVersion":4, "compiler":"clang-9.0","optim":"3","cppVersion":"17","lib":"llvm","isAnnotated":true}'; const OUTPUT = `{ "context": { "date": "2017-06-03 16:27:30", "num_cpus": 1, "mhz_per_cpu": 2400, "cpu_scaling_enabled": false, "library_build_type": "release" }, "benchmarks": [ { "name": "BM_StringCreation", "iterations": 110509442, "real_time": 25, "cpu_time": 6, "time_unit": "ns" }, { "name": "BM_StringCopy", "iterations": 32549672, "real_time": 86, "cpu_time": 22, "time_unit": "ns" }, { "name": "Noop", "iterations": 250612168, "real_time": 11, "cpu_time": 3, "time_unit": "ns" } ] }`; const ANNOTATION = 'Some annotations.'; const INPUT = `#include static void BM_StringCreation(benchmark::State& state) { while (state.KeepRunning()) std::string empty_string; } // Register the function as a benchmark BENCHMARK(BM_StringCreation); static void BM_StringCopy(benchmark::State& state) { std::string x = "hello"; while (state.KeepRunning()) std::string copy(x); } BENCHMARK(BM_StringCopy); static void Noop(benchmark::State& state) { while (state.KeepRunning()); } BENCHMARK(Noop); BENCHMARK_MAIN()`; const EXPECTED = { code: `static void BM_StringCreation(benchmark::State& state) { while (state.KeepRunning()) std::string empty_string; } // Register the function as a benchmark BENCHMARK(BM_StringCreation); static void BM_StringCopy(benchmark::State& state) { std::string x = "hello"; while (state.KeepRunning()) std::string copy(x); } BENCHMARK(BM_StringCopy); `, graph: { benchmarks: [ { "cpu_time": 6, "iterations": 110509442, "name": "BM_StringCreation", "real_time": 25, "time_unit": "ns" }, { "cpu_time": 22, "iterations": 32549672, "name": "BM_StringCopy", "real_time": 86, "time_unit": "ns", }, { "cpu_time": 3, "iterations": 250612168, "name": "Noop", "real_time": 11, "time_unit": "ns" }, ], context: { cpu_scaling_enabled: false, date: "2017-06-03 16:27:30", library_build_type: "release", mhz_per_cpu: 2400, num_cpus: 1 } }, options: { compiler: "clang-9.0", cppVersion: "c++17", optim: "3", lib: "llvm", flags: [], protocolVersion: 4 }, disassemblyOption: "att", annotation: "Some annotations." }; describe('Return v4 stored file', function () { it('should return a stable message with protocol 4', function () { return assert.deepEqual(libquick.groupResults([INPUT, OPTIONS, OUTPUT, ANNOTATION]), EXPECTED); }); }); ================================================ FILE: test/getv5.test.js ================================================ import * as libquick from '../src/libquick.js'; import * as libbuild from '../src/libbuild.js'; import assert from 'assert'; const OPTIONS = '{"protocolVersion":5, "compiler":"clang-17.0","optim":"3","cppVersion":"c++17","lib":"llvm","flags":["-ftest"],"disassemblyOption":"att"}'; const OUTPUT = `{ "context": { "date": "2017-06-03 16:27:30", "num_cpus": 1, "mhz_per_cpu": 2400, "cpu_scaling_enabled": false, "library_build_type": "release" }, "benchmarks": [ { "name": "BM_StringCreation", "iterations": 110509442, "real_time": 25, "cpu_time": 6, "time_unit": "ns" }, { "name": "BM_StringCopy", "iterations": 32549672, "real_time": 86, "cpu_time": 22, "time_unit": "ns" }, { "name": "Noop", "iterations": 250612168, "real_time": 11, "cpu_time": 3, "time_unit": "ns" } ] }`; const ANNOTATION = 'Some annotations.'; const INPUT = `#include static void BM_StringCreation(benchmark::State& state) { while (state.KeepRunning()) std::string empty_string; } // Register the function as a benchmark BENCHMARK(BM_StringCreation); static void BM_StringCopy(benchmark::State& state) { std::string x = "hello"; while (state.KeepRunning()) std::string copy(x); } BENCHMARK(BM_StringCopy); static void Noop(benchmark::State& state) { while (state.KeepRunning()); } BENCHMARK(Noop); BENCHMARK_MAIN()`; const PREPROCESSED = ` .text .file "cstdio.cpp" .globl main # -- Begin function main .p2align 4, 0x90 .type main,@function main: # @main .cfi_startproc`; const GRAPH = `0.01 0.01 75492 856 8 6 3975 0.01 0.01 74984 600 8 4 3966 0.03 0.00 75608 600 8 4 3975 0.03 0.00 75752 600 8 4 3985 0.01 0.01 75428 600 8 4 3972`; const INCLUDES = `. /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/cstdio .. /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/x86_64-linux-gnu/c++/11/bits/c++config.h ... /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/x86_64-linux-gnu/c++/11/bits/os_defines.h .... /usr/include/features.h ..... /usr/include/features-time64.h ...... /usr/include/x86_64-linux-gnu/bits/wordsize.h ...... /usr/include/x86_64-linux-gnu/bits/timesize.h ....... /usr/include/x86_64-linux-gnu/bits/wordsize.h ..... /usr/include/stdc-predef.h ..... /usr/include/x86_64-linux-gnu/sys/cdefs.h ...... /usr/include/x86_64-linux-gnu/bits/wordsize.h ...... /usr/include/x86_64-linux-gnu/bits/long-double.h ..... /usr/include/x86_64-linux-gnu/gnu/stubs.h ...... /usr/include/x86_64-linux-gnu/gnu/stubs-64.h ... /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/x86_64-linux-gnu/c++/11/bits/cpu_defines.h ... /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/pstl/pstl_config.h .. /usr/include/stdio.h`; const EXPECTED = { code: `static void BM_StringCreation(benchmark::State& state) { while (state.KeepRunning()) std::string empty_string; } // Register the function as a benchmark BENCHMARK(BM_StringCreation); static void BM_StringCopy(benchmark::State& state) { std::string x = "hello"; while (state.KeepRunning()) std::string copy(x); } BENCHMARK(BM_StringCopy); `, graph: { benchmarks: [ { "cpu_time": 6, "iterations": 110509442, "name": "BM_StringCreation", "real_time": 25, "time_unit": "ns" }, { "cpu_time": 22, "iterations": 32549672, "name": "BM_StringCopy", "real_time": 86, "time_unit": "ns", }, { "cpu_time": 3, "iterations": 250612168, "name": "Noop", "real_time": 11, "time_unit": "ns" }, ], context: { cpu_scaling_enabled: false, date: "2017-06-03 16:27:30", library_build_type: "release", mhz_per_cpu: 2400, num_cpus: 1 } }, options: { compiler: "clang-17.0", cppVersion: "c++17", optim: "3", lib: "llvm", flags: ["-ftest"], protocolVersion: 5 }, disassemblyOption: "att", annotation: "Some annotations." }; const EXPECTED_BB = { code: `#include static void BM_StringCreation(benchmark::State& state) { while (state.KeepRunning()) std::string empty_string; } // Register the function as a benchmark BENCHMARK(BM_StringCreation); static void BM_StringCopy(benchmark::State& state) { std::string x = "hello"; while (state.KeepRunning()) std::string copy(x); } BENCHMARK(BM_StringCopy); static void Noop(benchmark::State& state) { while (state.KeepRunning()); } BENCHMARK(Noop); BENCHMARK_MAIN()`, graph: GRAPH, includes: INCLUDES, options: { compiler: "clang-17.0", cppVersion: "c++17", optim: "3", lib: "llvm", flags: ["-ftest"], disassemblyOption: "att", protocolVersion: 5 }, preprocessed: PREPROCESSED, asm: "Some annotations.", id: "id", title: "filename" }; describe('Return v5 stored file', function () { it('QB: should return a stable message with protocol 5', function () { return assert.deepEqual(libquick.groupResults([INPUT, OPTIONS, OUTPUT, ANNOTATION]), EXPECTED); }); it('BB: should return a stable message with protocol 5', function () { return assert.deepEqual(libbuild.groupResults([INPUT, OPTIONS, GRAPH, INCLUDES, PREPROCESSED, ANNOTATION], 'id', 'filename'), EXPECTED_BB); }); }); ================================================ FILE: test/id.test.js ================================================ import * as libquick from '../src/libquick.js'; import assert from 'assert'; const startCode = `static void BM_StringCreation(benchmark::State& state) { while (state.KeepRunning()) std::string empty_string; } // Register the function as a benchmark BENCHMARK(BM_StringCreation); static void BM_StringCopy(benchmark::State& state) { std::string x = "hello"; while (state.KeepRunning()) std::string copy(x); } BENCHMARK(BM_StringCopy); `; const compiler = 'clang++-3.8'; const cppVersion = 17; const optim = 1; describe('id version 1', function () { it('should return a stable id', function () { assert.equal(libquick.makeName({ code: startCode, compiler: compiler, optim: optim, cppVersion: cppVersion, protocolVersion: 1 }), '630d398cbd8e8c9d76bd3fb17ede3b77abe4302e'); }); it('should return different id on optim change', function () { assert.equal(libquick.makeName({ code: startCode, compiler: compiler, optim: "0", cppVersion: cppVersion, protocolVersion: 1 }), '1fc0b826d2aaf85cceb587ba9960638b0d36ed74'); }); it('should return different id on code change', function () { assert.equal(libquick.makeName({ code: 'hello', compiler: compiler, optim: optim, cppVersion: cppVersion, protocolVersion: 1 }), 'e7b57d1778e7b38505a3581971eb8435bced36ae'); }); it('should return different id on compiler change', function () { assert.equal(libquick.makeName({ code: startCode, compiler: 'clang++-4.0', optim: optim, cppVersion: cppVersion, protocolVersion: 1 }), '5dee5060303d5a795b2154d76f87718f8aa7dbdf'); }); it('should return different id on cppVersion change', function () { assert.equal(libquick.makeName({ code: startCode, compiler: compiler, optim: optim, cppVersion: '98', protocolVersion: 1 }), '1aa1a9c43024dd01eb50f8b42832218f8d4299d9'); }); }) describe('id version 2', function () { it('should return different id on protocolVersion change', function () { assert.equal(libquick.makeName({ code: startCode, compiler: compiler, optim: optim, cppVersion: cppVersion, isAnnotated: true, protocolVersion: 2 }), '79521ea600940e871ab08a602b355849706871de'); }); it('should return different id on optim change', function () { assert.equal(libquick.makeName({ code: startCode, compiler: compiler, optim: "0", cppVersion: cppVersion, isAnnotated: true, protocolVersion: 2 }), 'a60edbed043f9271eb8f2ac33e48ba836d33f6eb'); }); it('should return different id on code change', function () { assert.equal(libquick.makeName({ code: 'hello', compiler: compiler, optim: optim, cppVersion: cppVersion, isAnnotated: true, protocolVersion: 2 }), '878de5d52c012f1c6469af9273510412a3607ab8'); }); it('should return different id on compiler change', function () { assert.equal(libquick.makeName({ code: startCode, compiler: 'clang++-4.0', optim: optim, cppVersion: cppVersion, isAnnotated: true, protocolVersion: 2 }), '02da5f0e209d2370f0546b5919c754d577a67af9'); }); it('should return different id on cppVersion change', function () { assert.equal(libquick.makeName({ code: startCode, compiler: compiler, optim: optim, cppVersion: '98', isAnnotated: true, protocolVersion: 2 }), 'c2c8ca7553725f561c05120804638d44318825f6'); }); it('should return different id on annotation change', function () { assert.equal(libquick.makeName({ code: startCode, compiler: compiler, optim: optim, cppVersion: cppVersion, isAnnotated: false, protocolVersion: 2 }), '5ccde87699ed42859925307950ec7ce2c2197ddc'); }); }) describe('id version 3', function () { it('should return different id on protocolVersion change', function () { assert.equal(libquick.makeName({ code: startCode, compiler: compiler, optim: optim, cppVersion: cppVersion, isAnnotated: true, lib: 'gnu', protocolVersion: 3 }), 'a53c5b14856c39c55439218c10320bef4a49257c'); }); it('should return different id on optim change', function () { assert.equal(libquick.makeName({ code: startCode, compiler: compiler, optim: "0", cppVersion: cppVersion, isAnnotated: true, lib: 'gnu', protocolVersion: 3 }), '6b208fee183ba8884aa62a025f9e07308c6aa757'); }); it('should return different id on code change', function () { assert.equal(libquick.makeName({ code: 'hello', compiler: compiler, optim: optim, cppVersion: cppVersion, isAnnotated: true, lib: 'gnu', protocolVersion: 3 }), 'b1a20c68ed6ccf1f68c5cae88ca96b559d260dc4'); }); it('should return different id on compiler change', function () { assert.equal(libquick.makeName({ code: startCode, compiler: 'clang++-4.0', optim: optim, cppVersion: cppVersion, isAnnotated: true, lib: 'gnu', protocolVersion: 3 }), '0b17798be35cd859202da65dee74301ae048cf2f'); }); it('should return different id on cppVersion change', function () { assert.equal(libquick.makeName({ code: startCode, compiler: compiler, optim: optim, cppVersion: '98', isAnnotated: true, lib: 'gnu', protocolVersion: 3 }), '77aff1de87af423078b44330ce0e002b53a8ae24'); }); it('should return different id on annotation change', function () { assert.equal(libquick.makeName({ code: startCode, compiler: compiler, optim: optim, cppVersion: cppVersion, isAnnotated: false, lib: 'gnu', protocolVersion: 3 }), '390203c96b49407964a8973bb51f5ee87156b045'); }); it('should return different id on lib change', function () { assert.equal(libquick.makeName({ code: startCode, compiler: compiler, optim: optim, cppVersion: cppVersion, isAnnotated: true, lib: 'llvm', protocolVersion: 3 }), '4bd647bcab41dd4b40022af2c88a86e0529611b0'); }); }) ================================================ FILE: test/options.test.js ================================================ import * as libquick from '../src/libquick.js'; import assert from 'assert'; const startCode = `static void BM_StringCreation(benchmark::State& state) { while (state.KeepRunning()) std::string empty_string; } // Register the function as a benchmark BENCHMARK(BM_StringCreation); static void BM_StringCopy(benchmark::State& state) { std::string x = "hello"; while (state.KeepRunning()) std::string copy(x); } BENCHMARK(BM_StringCopy); `; const request = { code: startCode, options: { compiler: 'clang-5.0', optim: 3, cppVersion: 17, lib: 'llvm', flags: ['-ftesting'] }, disassemblyOption: "att", protocolVersion: 5 }; describe('Save options', function () { const firstName = libquick.makeName(request); const saved = libquick.optionsToString(request); let loaded = {}; loaded.options = JSON.parse(saved); loaded.code = startCode; const built = libquick.makeRequest(loaded); it('should save enough to reload the request', function () { assert.equal(libquick.makeName(built), firstName); }); }); ================================================ FILE: test/test.func ================================================ BM_StringCreation BM_StringCopy ================================================ FILE: test/url-name.test.js ================================================ import * as tools from '../src/tools.js'; import sha1 from 'sha1'; import assert from 'assert'; const refId = '630d398cbd8e8c9d76bd3fb17ede3b77abe4302e'; const refUrl = 'Yw05jL2OjJ12vT_xft47d6vkMC4'; const twoSlashes = 'hbkmjh-0uSQKrYlQ-qNjLpgDEto'; const twoSlashedId = '85b9268e1ff4b9240aad8950fea3632e980312da'; const twoPluses = 'hbkmjh_0uSQKrYlQ_qNjLpgDEto'; const twoPlusesId = '85b9268e1fb4b9240aad8950faa3632e980312da'; describe('default codes', function () { it('should return a stable encoding', function () { assert.equal(tools.encodeName(refId), refUrl); }); it('should return a stable decoding', function () { assert.equal(tools.decodeName(refUrl), refId); }); }) describe('bijective', function () { it('should be bijective', function () { const name = sha1('Hello World!'); assert.equal(tools.decodeName(tools.encodeName(name)), name); }); }) describe('URL safe', function () { it('should give URL safe names', function () { [...Array(10).keys()].map((val) => tools.encodeName(sha1(val))).forEach((val) => assert.equal(val, encodeURIComponent(val))); }); it('should escape multiple slashes', function () { assert.equal(tools.decodeName(twoSlashes), twoSlashedId); assert.equal(tools.encodeName(twoSlashedId), twoSlashes); }) it('should escape multiple plusses', function () { assert.equal(tools.decodeName(twoPluses), twoPlusesId); assert.equal(tools.encodeName(twoPlusesId), twoPluses); }) })