@@ -77,7 +77,247 @@ The Performance Working Group uses [GitHub issues](https://github.com/expressjs/
77
77
The discussions are open to the public and anyone may participate. Also, the group uses the channel ` #express-perf-wg `
78
78
in the [ OpenJS Foundation Slack] ( https://openjsf.org/collaboration ) for realtime discussions.
79
79
80
+ ## How to Run the Load Tests
81
+
82
+ ### Requirements
83
+ - Node.js v22 (Recommended)
84
+ - Docker (for containerized runners)
85
+
86
+ ### Quick Start
87
+
88
+ 1 . ** Install dependencies**
89
+ ``` bash
90
+ node --run setup
91
+ ```
92
+
93
+ 2 . ** Run basic test with vanilla Node.js**
94
+ ``` bash
95
+ node --run test:load
96
+ ```
97
+
98
+ ### CLI Usage
99
+
100
+ #### CLI Options
101
+
102
+ The ` load ` command supports the following options:
103
+
104
+ | Option | Short | Default | Description |
105
+ | --------| -------| ---------| -------------|
106
+ | ` --test ` | ` -t ` | ` @expressjs/perf-load-example ` | Test module to run |
107
+ | ` --runner ` | ` -u ` | ` @expressjs/perf-runner-vanilla ` | Runner module to use |
108
+ | ` --duration ` | ` -d ` | ` 60 ` | Test duration in seconds |
109
+ | ` --node ` | ` -n ` | ` lts_latest ` | Node.js version to use |
110
+ | ` --overrides ` | ` -o ` | - | JSON string with package overrides |
111
+ | ` --cwd ` | - | Current directory | Working directory |
112
+ | ` --repo ` | - | ` https://github.com/expressjs/perf-wg.git ` | Git repository URL |
113
+ | ` --repo-ref ` | - | ` master ` | Git branch/tag to use |
114
+
115
+ #### Basic Commands
116
+
117
+ ``` bash
118
+ # Run with default vanilla Node.js runner
119
+ node --run load -- --test=" @expressjs/perf-load-example"
120
+
121
+ # Run with specific runner
122
+ node --run load -- --test=" @expressjs/perf-load-example" --runner=" @expressjs/perf-runner-nsolid"
123
+
124
+ # Run with overrides
125
+ node --run load -- --test=" @expressjs/perf-load-example" --overrides=' {"express":"5.0.0"}'
126
+
127
+ # Run with custom duration (default: 60 seconds)
128
+ node --run load -- --test=" @expressjs/perf-load-example" --duration=30
129
+
130
+ # Run with specific runner and overrides
131
+ node --run load -- --test=" @expressjs/perf-load-example" --runner=" @expressjs/perf-runner-nsolid" --overrides=' {"express":"5.0.0"}'
132
+
133
+ # Run with specific runner, overrides, and custom duration
134
+ node --run load -- --test=" @expressjs/perf-load-example" --runner=" @expressjs/perf-runner-nsolid" --overrides=' {"express":"5.0.0"}' --duration=120
135
+
136
+ # Run with specific runner and overrides and pass api key env
137
+ NSOLID_SAAS=" XXX" node --run load -- --test=" @expressjs/perf-load-example" --runner=" @expressjs/perf-runner-nsolid" --overrides=' {"express":"5.0.0"}'
138
+
139
+ # Compare results
140
+ node --run compare -- result-A.json result-B.json
141
+ ```
142
+
143
+ #### Runner-Specific Examples
144
+
145
+ ``` bash
146
+ # Vanilla Node.js (baseline performance)
147
+ node --run load -- --test=" @expressjs/perf-load-example" --runner=" @expressjs/perf-runner-vanilla"
148
+
149
+ # N|Solid with built-in monitoring
150
+ node --run load -- --test=" @expressjs/perf-load-example" --runner=" @expressjs/perf-runner-nsolid"
151
+
152
+ # Node.js with Datadog APM (when available)
153
+ node --run load -- --test=" @expressjs/perf-load-example" --runner=" @expressjs/perf-runner-datadog"
154
+
155
+ # Node.js with New Relic APM (when available)
156
+ node --run load -- --test=" @expressjs/perf-load-example" --runner=" @expressjs/perf-runner-newrelic"
157
+ ```
158
+ ### Programmatic Usage
159
+
160
+ #### Basic Import and Usage
161
+
162
+ ``` javascript
163
+ // Import specific runner
164
+ import vanillaRunner from ' @expressjs/perf-runner-vanilla' ;
165
+ import nsolidRunner from ' @expressjs/perf-runner-nsolid' ;
166
+
167
+ // Run single test
168
+ const results = await vanillaRunner ({
169
+ test: ' @expressjs/perf-load-example' ,
170
+ overrides: { express: ' 5.0.0' }
171
+ });
172
+
173
+ console .log (` Requests/sec: ${ results .clientResults .requests .mean } ` );
174
+ ```
175
+
176
+ #### Performance Comparison Script
177
+
178
+ ``` javascript
179
+ import vanillaRunner from ' @expressjs/perf-runner-vanilla' ;
180
+ import nsolidRunner from ' @expressjs/perf-runner-nsolid' ;
181
+
182
+ async function compareRuntimes () {
183
+ const testConfig = {
184
+ test: ' @expressjs/perf-load-example' ,
185
+ overrides: { express: ' latest' }
186
+ };
187
+
188
+ console .log (' Running performance comparison...' );
189
+
190
+ // Run tests in parallel
191
+ const [vanillaResults , nsolidResults ] = await Promise .all ([
192
+ vanillaRunner (testConfig),
193
+ nsolidRunner (testConfig)
194
+ ]);
195
+
196
+ // Compare results
197
+ const vanillaRPS = vanillaResults .clientResults .requests .mean ;
198
+ const nsolidRPS = nsolidResults .clientResults .requests .mean ;
199
+ const overhead = ((vanillaRPS - nsolidRPS) / vanillaRPS * 100 ).toFixed (2 );
200
+
201
+ console .log (' Performance Comparison:' );
202
+ console .log (` Vanilla Node.js: ${ vanillaRPS .toFixed (0 )} req/sec` );
203
+ console .log (` N|Solid: ${ nsolidRPS .toFixed (0 )} req/sec` );
204
+ console .log (` Overhead: ${ overhead} %` );
205
+ }
206
+
207
+ compareRuntimes ().catch (console .error );
208
+ ```
209
+
210
+ #### Advanced Configuration
211
+
212
+ ``` javascript
213
+ import { createRunner } from ' @expressjs/perf-runner-shared' ;
214
+
215
+ // Create custom runner configuration
216
+ const customRunner = createRunner ({
217
+ type: ' custom' ,
218
+ runtime: ' node.js' ,
219
+ apm: ' custom-monitoring' ,
220
+ capabilities: [' profiling' , ' tracing' ],
221
+ env: {
222
+ RUNTIME_TYPE : ' custom' ,
223
+ CUSTOM_CONFIG : ' enabled'
224
+ }
225
+ });
226
+
227
+ // Use with abort controller for cancellation
228
+ const controller = new AbortController ();
229
+ const results = await customRunner ({
230
+ test: ' @expressjs/perf-load-example' ,
231
+ signal: controller .signal
232
+ });
233
+ ```
234
+
235
+ ### Available Runners
236
+
237
+ | Runner | Description | Use Case | Status |
238
+ | --------| -------------| ----------| --------|
239
+ | ` @expressjs/perf-runner-vanilla ` | Standard Node.js runtime | Baseline performance measurements | Available |
240
+ | ` @expressjs/perf-runner-nsolid ` | N| Solid runtime with built-in monitoring | Enterprise monitoring capabilities | Available |
241
+ | ` @expressjs/perf-runner-datadog ` | Node.js + Datadog APM agent | Datadog APM overhead analysis | Coming soon |
242
+ | ` @expressjs/perf-runner-newrelic ` | Node.js + New Relic APM agent | New Relic APM overhead analysis | Coming soon |
243
+
244
+ ### Performance Analysis Examples
245
+
246
+ #### CLI-based Comparison
247
+
248
+ ``` bash
249
+ # Step 1: Run baseline test
250
+ node --run load -- --test=" @expressjs/perf-load-example" --runner=" @expressjs/perf-runner-vanilla"
251
+ # Output: results/vanilla-result-123456789.json
252
+
253
+ # Step 2: Run N|Solid test
254
+ node --run load -- --test=" @expressjs/perf-load-example" --runner=" @expressjs/perf-runner-nsolid"
255
+ # Output: results/nsolid-result-123456790.json
256
+
257
+ # Step 3: Compare results
258
+ node --run compare -- results/vanilla-result-123456789.json results/nsolid-result-123456790.json
259
+ ```
260
+
261
+ #### Programmatic Analysis
262
+
263
+ ``` javascript
264
+ import fs from ' node:fs/promises' ;
265
+
266
+ async function runPerformanceAnalysis () {
267
+ // Test configuration
268
+ const tests = [
269
+ { name: ' Express Hello World' , test: ' @expressjs/perf-load-example' },
270
+ { name: ' Express with Query' , test: ' @expressjs/perf-load-extended-query' }
271
+ ];
272
+
273
+ const runners = [
274
+ { name: ' Vanilla' , runner: vanillaRunner },
275
+ { name: ' N|Solid' , runner: nsolidRunner }
276
+ ];
277
+
278
+ const results = {};
279
+
280
+ // Run all combinations
281
+ for (const test of tests) {
282
+ results[test .name ] = {};
283
+
284
+ for (const { name , runner } of runners) {
285
+ console .log (` Running ${ test .name } with ${ name} ...` );
286
+
287
+ const result = await runner ({ test: test .test });
288
+ results[test .name ][name] = {
289
+ requestsPerSec: result .clientResults .requests .mean ,
290
+ latencyP95: result .clientResults .latency .p95 ,
291
+ memoryUsage: result .serverMetadata .memory
292
+ };
293
+ }
294
+ }
295
+
296
+ // Save comprehensive report
297
+ await fs .writeFile (' performance-report.json' , JSON .stringify (results, null , 2 ));
298
+ console .log (' Performance analysis complete. Results saved to performance-report.json' );
299
+ }
300
+
301
+ ### Runner Development
302
+
303
+ To create a new runner , extend the shared runner infrastructure:
304
+
305
+ ` ` ` javascript
306
+ // packages/runner-custom/index.mjs
307
+ import { createRunner } from '@expressjs/perf-runner-shared';
308
+
309
+ export default createRunner({
310
+ type: 'custom',
311
+ runtime: 'node.js',
312
+ apm: 'custom-apm',
313
+ capabilities: ['custom-profiling'],
314
+ env: {
315
+ RUNTIME_TYPE: 'custom',
316
+ CUSTOM_SETTING: 'enabled'
317
+ }
318
+ });
319
+ ` ` `
320
+
80
321
## Code of Conduct
81
322
82
323
The [Express Project' s CoC](https://github.com/expressjs/.github/blob/master/CODE_OF_CONDUCT.md) applies to this repo.
83
-
0 commit comments