From 097bf87e418e0f4242a6d0a8f90c09104d02fadf Mon Sep 17 00:00:00 2001
From: Pierre-Yves B <PyvesDev@gmail.com>
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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
R*$fN}44$rjF6*2UngFZre`f#y

literal 0
HcmV?d00001

diff --git a/doc/performance-testing.md b/doc/performance-testing.md
new file mode 100644
index 0000000000..8e48fd0610
--- /dev/null
+++ b/doc/performance-testing.md
@@ -0,0 +1,45 @@
+# Performance testing
+
+Shields has some basic tooling available to help you get started with
+performance testing.
+
+## Benchmarking the badge generation
+
+Want to micro-benchmark a section of the code responsible for generating the
+static badges? Follow these two simple steps:
+
+1. Surround the code you want to time with `console.time` and `console.timeEnd`
+   statements. For example:
+
+```
+console.time('makeBadge')
+const svg = makeBadge(badgeData)
+console.timeEnd('makeBadge')
+```
+
+2. Run `npm run benchmark:badge` in your terminal. An average timing will
+   be displayed!
+
+If you want to change the number of iterations in the benchmark, you can modify
+the values specified by the `benchmark:badge` script in _package.json_. If
+you want to benchmark a specific code path not covered by the static badge, you
+can modify the badge URL in _scripts/benchmark-performance.js_.
+
+## Profiling the full code
+
+Want to have an overview of how the entire application is performing? Simply
+run `npm run profile:server` in your terminal. This will start the
+backend server (i.e. without the frontend) in profiling mode and any requests
+you make on `localhost:8080` will generate data in a file with a name
+similar to _isolate-00000244AB6ED3B0-11920-v8.log_.
+
+You can then make use of this profiling data in various tools, for example
+[flamebearer](https://github.com/mapbox/flamebearer):
+
+```
+npm install -g flamebearer
+node --prof-process --preprocess -j isolate-00000244AB6ED3B0-11920-v8.log | flamebearer
+```
+
+An example output is the following:
+![](https://raw.github.com/badges/shields/master/doc/flamegraph.png)
diff --git a/package.json b/package.json
index e1bb13324a..0b0b61b6eb 100644
--- a/package.json
+++ b/package.json
@@ -106,6 +106,8 @@
     "start:server:e2e-on-build": "node server 8080",
     "start:server": "cross-env NODE_CONFIG_ENV=development nodemon server 8080",
     "debug:server": "cross-env NODE_CONFIG_ENV=development nodemon --inspect server.js 8080",
+    "profile:server": "cross-env NODE_CONFIG_ENV=development node --prof server 8080",
+    "benchmark:badge": "cross-env NODE_CONFIG_ENV=test node scripts/benchmark-performance.js --iterations 10100 | node scripts/capture-timings.js --warmup-iterations 100",
     "prestart": "run-s --silent depcheck defs features",
     "start": "concurrently --names server,frontend \"npm run start:server\" \"cross-env GATSBY_BASE_URL=http://localhost:8080 gatsby develop --port 3000\"",
     "e2e": "start-server-and-test start http://localhost:3000 test:e2e",
diff --git a/scripts/benchmark-performance.js b/scripts/benchmark-performance.js
new file mode 100644
index 0000000000..7686138f7c
--- /dev/null
+++ b/scripts/benchmark-performance.js
@@ -0,0 +1,26 @@
+'use strict'
+
+const config = require('config').util.toObject()
+const got = require('got')
+const minimist = require('minimist')
+const Server = require('../core/server/server')
+
+async function main() {
+  const server = new Server(config)
+  await server.start()
+  const args = minimist(process.argv)
+  const iterations = parseInt(args.iterations) || 10000
+  for (let i = 0; i < iterations; ++i) {
+    await got(`${server.baseUrl}badge/coverage-${i}-green.svg`)
+  }
+  await server.stop()
+}
+
+;(async () => {
+  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)
-<perftest.log grep 'makeBadge total' | \
-  grep -Eo '[0-9\.]+' | \
-  awk '{s+=$1;n++} END {print s/n}'
diff --git a/scripts/capture-timings.js b/scripts/capture-timings.js
new file mode 100644
index 0000000000..fee8bf24a2
--- /dev/null
+++ b/scripts/capture-timings.js
@@ -0,0 +1,61 @@
+'use strict'
+
+const readline = require('readline')
+const minimist = require('minimist')
+
+async function captureTimings(warmupIterations) {
+  const rl = readline.createInterface({
+    input: process.stdin,
+  })
+
+  const times = {}
+  let timingsCount = 0
+  let labelsCount = 0
+  const timing = /^(.+): ([0-9.]+)ms$/i
+
+  for await (const line of rl) {
+    const match = timing.exec(line)
+    if (match) {
+      labelsCount = Object.keys(times).length
+      if (timingsCount > 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)
+  }
+})()
-- 
GitLab