From 097bf87e418e0f4242a6d0a8f90c09104d02fadf Mon Sep 17 00:00:00 2001 From: Pierre-Yves B Date: Sun, 22 Mar 2020 20:45:53 +0100 Subject: [PATCH] Make it easier to benchmark and profile the code (#4780) * Make it easier to benchmark and profile the code * Remove unnecessary escape * Clarify that the backend server is started without the frontend * Add missing NODE_CONFIG_ENV environment variable * Add error message when user has not included console.time statements * Fix lint issue * Handle multiple console.time statements * Switch NODE_CONFIG_ENV to test * Switch to const as variable never re-assigned --- .gitignore | 3 ++ config/custom-environment-variables.yml | 3 -- config/default.yml | 3 -- core/base-service/base-static.js | 12 +---- core/server/server.js | 4 -- doc/flamegraph.png | Bin 0 -> 30746 bytes doc/performance-testing.md | 45 +++++++++++++++++ package.json | 2 + scripts/benchmark-performance.js | 26 ++++++++++ scripts/benchmark-performance.sh | 11 ----- scripts/capture-timings.js | 61 ++++++++++++++++++++++++ 11 files changed, 138 insertions(+), 32 deletions(-) create mode 100644 doc/flamegraph.png create mode 100644 doc/performance-testing.md create mode 100644 scripts/benchmark-performance.js delete mode 100755 scripts/benchmark-performance.sh create mode 100644 scripts/capture-timings.js diff --git a/.gitignore b/.gitignore index fbed1f5ac3..e398cad1c8 100644 --- a/.gitignore +++ b/.gitignore @@ -113,3 +113,6 @@ service-definitions.yml # Rendered API docs /api-docs/ + +# Flamebearer +flamegraph.html diff --git a/config/custom-environment-variables.yml b/config/custom-environment-variables.yml index 468c4bf5de..effec83c27 100644 --- a/config/custom-environment-variables.yml +++ b/config/custom-environment-variables.yml @@ -48,9 +48,6 @@ public: authorizedOrigins: 'TEAMCITY_ORIGINS' trace: 'TRACE_SERVICES' - profiling: - makeBadge: 'PROFILE_MAKE_BADGE' - cacheHeaders: defaultCacheLengthSeconds: 'BADGE_MAX_AGE_SECONDS' diff --git a/config/default.yml b/config/default.yml index 7adbce874e..405670561c 100644 --- a/config/default.yml +++ b/config/default.yml @@ -23,9 +23,6 @@ public: intervalSeconds: 200 trace: false - profiling: - makeBadge: false - cacheHeaders: defaultCacheLengthSeconds: 120 diff --git a/core/base-service/base-static.js b/core/base-service/base-static.js index ae1ab70229..c932b317bc 100644 --- a/core/base-service/base-static.js +++ b/core/base-service/base-static.js @@ -13,9 +13,6 @@ const { prepareRoute, namedParamsForMatch } = require('./route') module.exports = class BaseStaticService extends BaseService { static register({ camp, metricInstance }, serviceConfig) { - const { - profiling: { makeBadge: shouldProfileMakeBadge }, - } = serviceConfig const { regex, captureNames } = prepareRoute(this.route) const metricHelper = MetricHelper.create({ @@ -52,16 +49,9 @@ module.exports = class BaseStaticService extends BaseService { const format = (match.slice(-1)[0] || '.svg').replace(/^\./, '') badgeData.format = format - if (shouldProfileMakeBadge) { - console.time('makeBadge total') - } - const svg = makeBadge(badgeData) - if (shouldProfileMakeBadge) { - console.timeEnd('makeBadge total') - } - setCacheHeadersForStaticResource(ask.res) + const svg = makeBadge(badgeData) makeSend(format, ask.res, end)(svg) metricHandle.noteResponseSent() diff --git a/core/server/server.js b/core/server/server.js index b4843e420b..3f4f5a4238 100644 --- a/core/server/server.js +++ b/core/server/server.js @@ -123,9 +123,6 @@ const publicConfigSchema = Joi.object({ teamcity: defaultService, trace: Joi.boolean().required(), }).required(), - profiling: { - makeBadge: Joi.boolean().required(), - }, cacheHeaders: { defaultCacheLengthSeconds: Joi.number() .integer() @@ -341,7 +338,6 @@ class Server { { handleInternalErrors: config.public.handleInternalErrors, cacheHeaders: config.public.cacheHeaders, - profiling: config.public.profiling, fetchLimitBytes: bytes(config.public.fetchLimit), rasterUrl: config.public.rasterUrl, private: config.private, diff --git a/doc/flamegraph.png b/doc/flamegraph.png new file mode 100644 index 0000000000000000000000000000000000000000..e7611aedb5057ff37991487a22804b65ed0b9ec5 GIT binary patch literal 30746 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

Z}qWQBIWt@ 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 cdg1@HS { + try { + await main() + } catch (e) { + console.error(e) + process.exit(1) + } +})() diff --git a/scripts/benchmark-performance.sh b/scripts/benchmark-performance.sh deleted file mode 100755 index ea77308c62..0000000000 --- a/scripts/benchmark-performance.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -PROFILE_MAKE_BADGE=1 node server 1111 >perftest.log & -sleep 2 -for ((i=0;i<10000;i++)); do - curl -s http://localhost:1111/badge/coverage-"$i"%-green.svg >/dev/null -done -kill $(jobs -p) - warmupIterations * labelsCount) { + const label = match[1] + const time = parseFloat(match[2]) + times[label] = time + (times[label] || 0) + } + ++timingsCount + } + } + return { times, iterations: timingsCount / labelsCount } +} + +function logResults({ times, iterations, warmupIterations }) { + if (isNaN(iterations)) { + console.log( + `No timings captured. Have you included console.time statements in the badge creation code path?` + ) + } else { + const timedIterations = iterations - warmupIterations + for (const [label, time] of Object.entries(times)) { + const averageTime = time / timedIterations + console.log( + `Average '${label}' time over ${timedIterations} iterations: ${averageTime}ms` + ) + } + } +} + +async function main() { + const args = minimist(process.argv) + const warmupIterations = parseInt(args['warmup-iterations']) || 100 + const { times, iterations } = await captureTimings(warmupIterations) + logResults({ times, iterations, warmupIterations }) +} + +;(async () => { + try { + await main() + } catch (e) { + console.error(e) + process.exit(1) + } +})()