Skip to content

Commit 056b48e

Browse files
authored
test(gatsby): Add a memory test suite command to the memory benchmark (#34810)
* Create memory test suite for measuring multiple runs * Minor updates * Add inc suite * Increase node's heap limit * Add memory tracking * Revert "Add memory tracking" This reverts commit 539291c. * Add docker rebuild command * Rework what/how results are given * Actually use path var * Revert "Revert "Add memory tracking"" This reverts commit f28ba4a. * Use faster method for grabbing memory usage * Output fixes * Update output dir and add comments * Update readme * Update readme again * Add ability to conditionally set jemalloc as the memory allocator
1 parent 45cb1f1 commit 056b48e

File tree

9 files changed

+444
-19
lines changed

9 files changed

+444
-19
lines changed

benchmarks/memory/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
output
2+
.docker.memusage

benchmarks/memory/Dockerfile

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
11
FROM node:14-buster
2+
ARG jemalloc
23
ENV NODE_ENV=production
34
ENV CI=1
45
ENV GATSBY_CPU_COUNT=4
56
RUN apt-get update -y && apt-get upgrade -y && apt-get install git curl npm -y
67
RUN npm i -g gatsby-cli gatsby-dev-cli
7-
WORKDIR /usr/src/app
8+
9+
# set heap to 16gb just to catch all test cases
10+
ENV NODE_OPTIONS="--max-old-space-size=16368"
11+
812
RUN echo "\n\necho \"Welcome to the Gatsby Memory benchmark container!\\n - /usr/src/gatsby : Your local gatsby repo\\n - /usr/src/app : The memory benchmark gatsby site\\n\"" > /root/.bashrc
913

14+
RUN if [ "$jemalloc" = "1" ]; then \
15+
echo "Using jemalloc for memory allocation" && \
16+
apt-get update && apt-get install -y libjemalloc-dev=5.1.0-3 && \
17+
echo "/usr/lib/x86_64-linux-gnu/libjemalloc.so" >> /etc/ld.so.preload && \
18+
echo "\n\necho \"This container is using jemelloc.\\n\"" >> /root/.bashrc; \
19+
fi
20+
21+
22+
WORKDIR /usr/src/app
23+
1024
# set up gatsby-dev
1125
RUN gatsby-dev --set-path-to-repo /usr/src/gatsby
1226

benchmarks/memory/README.md

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,62 @@ Within the container, two points to your local filesystem are mounted:
1212
- /usr/src/gatsby : Your local gatsby repo
1313
- /usr/src/site : The memory benchmark gatsby site
1414

15+
If you'd like to configure `jemalloc` to run within the container, set the `JEMALLOC=1` env var when building the docker container.
16+
1517
## Commands
1618

19+
### Tests
20+
21+
#### yarn test --memory X --num-nodes Y --node-size Z
22+
23+
Runs a test build within a docker container with the given memory allotment.
24+
Within our gatsby-node, we'll create X nodes with a string property of size Y.
25+
26+
Example: running a build with 1000 nodes of 1mb each, in a docker container with 8gb of memory.
27+
28+
```
29+
$ yarn test --memory 8g --num-nodes 500 --node-size 1m
30+
```
31+
32+
#### yarn test-suite --name some-name --suite [incremental|exhaustive]
33+
34+
Runs through test suites defined in `scripts/test-suite.js` and outputs results to `output/some-name`.
35+
Output includes a `results.csv` with a summary of all builds, as well as breakdowns for each memory configuration.
36+
37+
##### incremental
38+
39+
Incremental tests run builds with a `node-size` of 1m. For each memory allotment, it will start with 100
40+
nodes in the build and increment by 100 on each success. The test will stop when all builds in a given
41+
configuration fail.
42+
See `incrementalConfig` in `scripts/test-suite.js` to customize test sets.
43+
44+
##### exhaustive
45+
46+
Exhaustive tests are just that, exhaustive. It will measure the time/success of every combination given.
47+
See `exhaustiveConfig` in `scripts/test-suite.js` to customize test sets.
48+
1749
### Docker
1850

1951
These commands are used for interfacing with docker and have built-in utilities for managing the docker container.
2052

2153
#### yarn docker:build
2254

2355
Builds the container used for testing.
56+
If you'd like to configure `jemalloc` to run within the container, set the `JEMALLOC=1` env var.
57+
58+
Example:
59+
60+
```
61+
$ JEMALLOC=1 yarn docker:build
62+
```
63+
64+
#### yarn docker:remove
65+
66+
Removes the docker image.
67+
68+
#### yarn docker:rebuild
69+
70+
Shorthand for remove + build.
2471

2572
#### yarn docker:start
2673

@@ -85,17 +132,9 @@ When starting working with this benchmark:
85132

86133
- start `yarn watch` (possibly with `--scope`) in monorepo
87134
- start `gatsby-dev` outside of docker in benchmark directory (just like with regular site)
88-
- `yarn docker:connect` to get inside docker
89-
- `npm rebuild` to rebuild binaries inside docker
135+
- `yarn test --memory 8g --num-nodes 1000 --node-size 1m`
90136

91137
And repeat as many times as you want:
92138

93139
- make changes to `gatsby` source code as you normally would
94-
- run `yarn gatsby:build` inside docker
95-
96-
## Testing
97-
98-
TODO
99-
100-
- How to configure memory limits
101-
- Where to look
140+
- run your `yarn test` command again

benchmarks/memory/gatsby-node.js

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
11
const { cpuCoreCount } = require(`gatsby-core-utils`)
22

3-
const NUM_NODES = parseInt(process.env.NUM_NODES || 300, 10)
3+
const NUM_KEYS_IN_LARGE_SIZE_OBJ = parseInt(process.env.BUILD_LARGE_OBJECT_COUNT || 1024, 10)
4+
const NUM_NODES = parseInt(process.env.BUILD_NUM_NODES || 300, 10)
5+
const LARGE_FIELD_SIZE_RAW = process.env.BUILD_STRING_NODE_SIZE || '1m'
6+
7+
// convert raw size to number
8+
const regexpSize = /([0-9]+)([kmg])?/;
9+
const match = LARGE_FIELD_SIZE_RAW.match(regexpSize);
10+
const suffixSizes = ['k', 'm', 'g'];
11+
let bytesMultiplier = 1;
12+
if (match.length > 2 && suffixSizes.indexOf(match[2]) >= 0) {
13+
bytesMultiplier = 2 ** ((suffixSizes.indexOf(match[2]) + 1) * 10)
14+
}
15+
const LARGE_FIELD_SIZE = parseInt(match[1], 10) * bytesMultiplier;
416

5-
const NUM_KEYS_IN_LARGE_SIZE_OBJ = 1024
617

718
exports.sourceNodes = async ({ actions, reporter }) => {
819
const contentDigest = Date.now().toString() // make each sourcing mark everything as dirty
@@ -25,7 +36,7 @@ exports.sourceNodes = async ({ actions, reporter }) => {
2536
number2: NUM_NODES - i,
2637
number3: i % 20,
2738
largeSizeObj,
28-
largeSizeString: `x`.repeat(1024 * 1024),
39+
largeSizeString: `x`.repeat(LARGE_FIELD_SIZE),
2940
internal: {
3041
contentDigest,
3142
type: `Test`,

benchmarks/memory/package.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,16 @@
1010
"gatsby:develop": "NODE_ENV=development yarn gatsby develop -H 0.0.0.0 -p 9000",
1111
"gatsby:build:debug": "node --nolazy --inspect-brk=0.0.0.0:9229 node_modules/.bin/gatsby build",
1212
"gatsby:develop:debug": "NODE_ENV=development node --nolazy --inspect-brk=0.0.0.0:9229 node_modules/.bin/gatsby develop -H 0.0.0.0 -p 9000",
13-
"docker:build": "docker build -t gatsby-memory .",
13+
"docker:build": "docker build -t gatsby-memory . --build-arg jemalloc=$JEMALLOC",
14+
"docker:remove": "docker image rm -f gatsby-memory",
15+
"docker:rebuild": "yarn docker:stop; yarn docker:remove && yarn docker:build",
1416
"docker:start": "./scripts/docker-start",
1517
"docker:connect": "./scripts/docker-connect",
1618
"docker:start-and-connect": "./scripts/docker-start && sleep 1 && ./scripts/docker-connect",
1719
"docker:stop": "./scripts/docker-stop",
18-
"docker:stats": "./scripts/docker-stats"
20+
"docker:stats": "./scripts/docker-stats",
21+
"test": "node scripts/test.js",
22+
"test-suite": "node scripts/test-suite.js"
1923
},
2024
"repository": {
2125
"type": "git",

benchmarks/memory/scripts/docker-start

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,21 @@ if [ -n "$DOCKER_ID" ]; then
55
return 1
66
fi
77

8+
MEMORY_LIMIT="${DOCKER_MEMORY_LIMIT:-2g}"
9+
810
DOCKER_ID=$(\
911
docker run -td \
1012
--mount type=bind,source="$(pwd)/../..",target=/usr/src/gatsby \
1113
--mount type=bind,source="$(pwd)",target=/usr/src/app \
1214
--publish 9229:9229 \
1315
--publish 9000:9000 \
14-
--memory="2g" \
15-
--memory-swap="2g" \
16+
--memory="${MEMORY_LIMIT}" \
17+
--memory-swap="${MEMORY_LIMIT}" \
1618
gatsby-memory \
1719
| head -c 12 \
1820
)
1921

20-
echo "\nStarted container id ${DOCKER_ID}! Run \`yarn docker:connect\` to connect to the container.\n"
22+
sleep 1
23+
docker exec $DOCKER_ID bash -c "/usr/src/app/scripts/docker-write-memory &"
24+
25+
echo "\nStarted container id ${DOCKER_ID} with ${MEMORY_LIMIT} of memory! Run \`yarn docker:connect\` to connect to the container.\n"
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
while true; do
2+
PROCESS="node"
3+
4+
# find all node processes
5+
PROCESS_USAGES=$(ps -eo rss,pid,euser,args:100 --sort %mem | grep -v grep | grep -i "${PROCESS}" | awk '{print $1}')
6+
7+
# sum the usage
8+
SUM_USAGE=$(echo "$PROCESS_USAGES" | awk '{s+=$1} END {printf "%.0f\n", s}')
9+
10+
# write to file
11+
echo -e "$SUM_USAGE" > /usr/src/app/.docker.memusage
12+
sleep .25
13+
done

0 commit comments

Comments
 (0)