@nestia/benchmark 14.0.1 → 14.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -27,17 +27,65 @@ import { IBenchmarkServant } from "./internal/IBenchmarkServant";
27
27
  * Additionally, if you hope to see some utilization cases, see the below
28
28
  * example tagged links.
29
29
  *
30
+ * Processing cost: Totals are split across T servants once; E events are
31
+ * aggregated with hash-based endpoint grouping. Progress notifications update
32
+ * the aggregate from one servant counter delta in constant time. Event
33
+ * statistics and rendering traverse their input populations; discovery visits
34
+ * each real directory once.
35
+ *
36
+ * Computation reuse: A master distributes distinct request budgets rather than
37
+ * replaying one effectful request. Endpoint grouping shares one event
38
+ * population across whole-run and endpoint statistics. Results are not cached
39
+ * across benchmark runs because server state and timing change.
40
+ *
41
+ * Resource ownership: Each master owns at most threads connectors and
42
+ * simultaneous function workers; connector closure is attempted on
43
+ * connection/execution success or failure; a rejected close is suppressed and
44
+ * may leave an unreleased child process. Events retained by servants/master
45
+ * scale with logged events, and memory samples with run duration. The
46
+ * independent sampler detaches its report target on stop or rejection and
47
+ * clears/wakes its owned timer. A pending caller memory getter has no
48
+ * cancellation hook, but its task retains only the sampler state/getter and
49
+ * cannot keep the master report arrays, connectors or event collections through
50
+ * that state. Its eventual result is discarded after deactivation. Returned
51
+ * reports transfer their arrays to callers.
52
+ *
53
+ * Platform boundary: WorkerConnector process mode owns Node child-process
54
+ * launch/IPC and its explicit stdio modes. Feature discovery resolves the
55
+ * caller location with native path and fs realpath/stat, follows directory
56
+ * links with realpath cycle detection and imports discovered native absolute
57
+ * paths. It does not infer filesystem case policy from OS names.
58
+ *
30
59
  * @author Jeongho Nam - https://github.com/samchon
31
60
  * @example
32
61
  * https://github.com/samchon/nestia-start/blob/master/test/benchmaark/index.ts
33
62
  *
34
63
  * @example
35
64
  * https://github.com/samchon/backend/blob/master/test/benchmark/index.ts
65
+ *
66
+ * @evidence contracts/common.md#principled-implementation The master spawns one child process per thread through tgrid's process-mode `WorkerConnector`, drives each servant over RPC, and merges the returned events; totals are split by floor plus remainder so the shares sum to the requested count and simultaneous budget.
67
+ * @evidence contracts/common.md#clear-and-simple-design One namespace is the public surface (master, servant, markdown, props, report); execution, discovery, and cleanup helpers stay private, and statistics and rendering live in their own internal namespaces.
68
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts Nothing names a server, feature, or file: the feature extension, prefix, and filter are caller inputs, and the servant path is a property rather than an assumed location.
69
+ * @evidence contracts/common.md#meaningful-documentation The namespace prose explains the two-program model, what each program does, and how to obtain markdown, with links to the member documentation and to example repositories.
36
70
  */
37
71
  export declare namespace DynamicBenchmarker {
38
- /** Properties of the master program. */
72
+ /**
73
+ * Properties of the master program.
74
+ *
75
+ * Platform boundary: The servant path uses native filesystem spelling, and
76
+ * stdio exposes Node child-process modes without imposing separator or case
77
+ * policy.
78
+ *
79
+ * @evidence contracts/common.md#principled-implementation The fields are exactly what the master needs to plan a run: totals, parallelism, how to reach the servant program, and optional hooks; the count, threads, and simultaneous constraints are enforced by `master`, which the field prose states.
80
+ * @evidence contracts/common.md#clear-and-simple-design A flat property record; optional members carry the only extension points (filter, progress, memory, stdio).
81
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts Every value is caller-supplied; no default names a target application or fixture.
82
+ * @evidence contracts/common.md#meaningful-documentation Each property documents its meaning and constraints, including how simultaneous is distributed among threads and that the filter receives a file basename.
83
+ */
39
84
  interface IMasterProps {
40
- /** Total count of the requests. */
85
+ /**
86
+ * Total number of benchmark function invocations, each of which may log
87
+ * several HTTP requests.
88
+ */
41
89
  count: number;
42
90
  /**
43
91
  * Number of threads.
@@ -72,12 +120,23 @@ export declare namespace DynamicBenchmarker {
72
120
  *
73
121
  * @param file File name (basename) of the benchmark functions
74
122
  * @returns Whether to execute the function or not.
123
+ * @evidence contracts/common.md#principled-implementation The predicate is asked for each candidate file name through the master driver before the servant imports it, so a rejected file's functions can never execute.
124
+ * @evidence contracts/common.md#clear-and-simple-design A single predicate on the file basename, with a default that accepts everything.
125
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts Selection is by the caller's predicate, not by known file names.
126
+ * @evidence contracts/common.md#meaningful-documentation The comment states the argument (basename, not function name) and that a `false` result prevents the import.
75
127
  */
76
128
  filter?: (file: string) => boolean;
77
129
  /**
78
130
  * Progress callback function.
79
131
  *
80
- * @param complete The number of completed requests.
132
+ * Progress counts completed benchmark function invocations, regardless of
133
+ * how many HTTP events each invocation logs.
134
+ *
135
+ * @param complete The number of completed benchmark function invocations.
136
+ * @evidence contracts/common.md#principled-implementation The callback receives the sum of completed invocation counts from every servant and is called once more with the requested count at the end, including when no matching functions were discovered.
137
+ * @evidence contracts/common.md#clear-and-simple-design One optional notification with a single number argument.
138
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The callback does not configure request counts or concurrency; a throw from the final callback propagates after servants have been closed rather than being hidden.
139
+ * @evidence contracts/common.md#meaningful-documentation The comment distinguishes completed benchmark function invocations from logged HTTP events.
81
140
  */
82
141
  progress?: (complete: number) => void;
83
142
  /**
@@ -88,6 +147,16 @@ export declare namespace DynamicBenchmarker {
88
147
  * Specify this property only when your backend server is running on a
89
148
  * different process, so that need to measure the memory usage of the
90
149
  * backend server from other process.
150
+ *
151
+ * The function is called once a second while the benchmark runs. If it
152
+ * rejects, the sampling stops and the report keeps the samples taken so
153
+ * far. A result still pending when execution ends is discarded when it
154
+ * settles.
155
+ *
156
+ * @evidence contracts/common.md#principled-implementation When the server under test runs in another process, the master's own `process.memoryUsage()` measures the wrong process, so the caller supplies a getter for the right one; it is sampled once a second while the run lasts.
157
+ * @evidence contracts/common.md#clear-and-simple-design One optional async getter that replaces the default sampler and nothing else.
158
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The default measures the master process itself; a caller getter is used as given, and a getter that rejects ends sampling rather than being retried or replaced.
159
+ * @evidence contracts/common.md#meaningful-documentation The comment states when to set it, the sampling cadence, and that a rejection stops the sampling and keeps earlier samples.
91
160
  */
92
161
  memory?: () => Promise<NodeJS.MemoryUsage>;
93
162
  /**
@@ -97,7 +166,18 @@ export declare namespace DynamicBenchmarker {
97
166
  */
98
167
  stdio?: undefined | "overlapped" | "pipe" | "ignore" | "inherit";
99
168
  }
100
- /** Properties of the servant program. */
169
+ /**
170
+ * Properties of the servant program.
171
+ *
172
+ * Platform boundary: The feature location and extension describe native files
173
+ * separately from the connection's protocol address; relative paths use the
174
+ * servant's working directory.
175
+ *
176
+ * @evidence contracts/common.md#principled-implementation The fields define how a servant finds benchmark functions (location, extension, prefix) and how it builds their arguments (connection and parameters), which is everything discovery and invocation need.
177
+ * @evidence contracts/common.md#clear-and-simple-design A generic property record parameterized by the tuple of function arguments, with the optional extension defaulting to the built JavaScript.
178
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The extension is declared rather than inferred from the servant's own module, which once loaded no feature at all when the library was built and the features ran from TypeScript source.
179
+ * @evidence contracts/common.md#meaningful-documentation Each property documents its role, the default extension, the file-name and function-name prefix rules, and what happens when nothing matches.
180
+ */
101
181
  interface IServantProps<Parameters extends any[]> {
102
182
  /**
103
183
  * Default connection.
@@ -105,7 +185,12 @@ export declare namespace DynamicBenchmarker {
105
185
  * Default connection to be used in the servant.
106
186
  */
107
187
  connection: IConnection;
108
- /** Location of the benchmark functions. */
188
+ /**
189
+ * Location of the benchmark functions.
190
+ *
191
+ * A relative path is resolved against the current working directory of the
192
+ * servant, the same base that lists the directory.
193
+ */
109
194
  location: string;
110
195
  /**
111
196
  * Extension of the benchmark function files to load, without the leading
@@ -128,6 +213,9 @@ export declare namespace DynamicBenchmarker {
128
213
  * would never be executed. Also, when a file name (basename) does not start
129
214
  * with the prefix, the file would never be imported either, so that every
130
215
  * function defined in the file would never be executed.
216
+ *
217
+ * When no function matches, no request is executed and the report carries
218
+ * no events.
131
219
  */
132
220
  prefix: string;
133
221
  /**
@@ -139,35 +227,102 @@ export declare namespace DynamicBenchmarker {
139
227
  *
140
228
  * @param connection Default connection instance
141
229
  * @param name Function name
230
+ * @evidence contracts/common.md#principled-implementation A function from the per-request connection and the function name to the argument tuple lets each execution receive a connection whose logger records its events.
231
+ * @evidence contracts/common.md#clear-and-simple-design One callback, called per execution, with the two inputs a caller needs to build arguments.
232
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts Arguments come only from the caller's function; the connection it receives is the servant's logging copy.
233
+ * @evidence contracts/common.md#meaningful-documentation The comment warns that the logger of the received connection must be carried into the returned parameters, the fact that decides whether events are recorded.
142
234
  */
143
235
  parameters: (connection: IConnection, name: string) => Parameters;
144
236
  }
145
- /** Benchmark report. */
237
+ /**
238
+ * Benchmark report.
239
+ *
240
+ * Times are ISO 8601 strings, durations are milliseconds, and the
241
+ * {@link statistics} and every entry of {@link endpoints} describe the same
242
+ * collected events, grouped by method and path template.
243
+ *
244
+ * @evidence contracts/common.md#principled-implementation The report is the master's merged observation: the run parameters, whole-run statistics, per-endpoint statistics, and memory samples, all derived from one event collection.
245
+ * @evidence contracts/common.md#clear-and-simple-design A flat record whose nested types (`IEndpoint`, `IStatistics`, `IMemory`) name the parts, with no behavior.
246
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts Every field is measured or copied from the request; none is a fixture value.
247
+ * @evidence contracts/common.md#meaningful-documentation The prose states the time format, the duration unit, and how statistics and endpoints relate.
248
+ */
146
249
  interface IReport {
250
+ /** Requested number of benchmark function invocations. */
147
251
  count: number;
252
+ /** Number of servant processes requested. */
148
253
  threads: number;
254
+ /** Aggregate limit on concurrent benchmark function invocations. */
149
255
  simultaneous: number;
256
+ /** ISO 8601 time when connected servants started executing. */
150
257
  started_at: string;
258
+ /** ISO 8601 time when every servant finished executing. */
151
259
  completed_at: string;
260
+ /** Statistics over all HTTP events logged by the benchmark functions. */
152
261
  statistics: IReport.IStatistics;
262
+ /** The same events grouped by HTTP method and route path template. */
153
263
  endpoints: Array<IReport.IEndpoint & IReport.IStatistics>;
264
+ /**
265
+ * Memory samples obtained during execution; failed or pending readings are
266
+ * omitted.
267
+ */
154
268
  memories: IReport.IMemory[];
155
269
  }
156
270
  namespace IReport {
271
+ /**
272
+ * Identity of an endpoint in the report: the HTTP method and the route
273
+ * path, using the path template when the route declares one.
274
+ *
275
+ * @evidence contracts/common.md#principled-implementation An endpoint is identified by method and path, the pair the master groups events by, with the template preferred so parameterized paths aggregate.
276
+ * @evidence contracts/common.md#clear-and-simple-design Two string fields with no behavior.
277
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts Grouping uses the route metadata carried by each event, without a list of known endpoints.
278
+ * @evidence contracts/common.md#meaningful-documentation The comment states which path form is used for grouping.
279
+ */
157
280
  interface IEndpoint {
281
+ /** HTTP method of the grouped requests. */
158
282
  method: string;
283
+ /** Route template, falling back to the concrete route path. */
159
284
  path: string;
160
285
  }
286
+ /**
287
+ * Statistics of a set of benchmarked requests.
288
+ *
289
+ * Durations are milliseconds from the request start to its completion.
290
+ * `mean`, `stdev`, `minimum`, and `maximum` are `null` when there are no
291
+ * events, and `stdev` is the population standard deviation. `success`
292
+ * counts the events whose executed function did not throw.
293
+ *
294
+ * @evidence contracts/common.md#principled-implementation Counts are exact, the mean and population standard deviation are computed over the same set, and `null` marks the empty set where no value is defined.
295
+ * @evidence contracts/common.md#clear-and-simple-design A flat record of six measures reused for the whole run and for each endpoint.
296
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The values are computed from the events; no measure is defaulted to a plausible number.
297
+ * @evidence contracts/common.md#meaningful-documentation The comment states the unit, the empty-set convention, the deviation kind, and what success counts.
298
+ */
161
299
  interface IStatistics {
300
+ /** Number of logged HTTP events. */
162
301
  count: number;
302
+ /** Events whose enclosing benchmark function completed without throwing. */
163
303
  success: number;
304
+ /** Mean duration in milliseconds, or null for no events. */
164
305
  mean: number | null;
306
+ /** Population standard deviation in milliseconds, or null for no events. */
165
307
  stdev: number | null;
308
+ /** Shortest duration in milliseconds, or null for no events. */
166
309
  minimum: number | null;
310
+ /** Longest duration in milliseconds, or null for no events. */
167
311
  maximum: number | null;
168
312
  }
313
+ /**
314
+ * One memory sample taken while the benchmark ran: an ISO 8601 time and the
315
+ * process memory usage read by the sampler.
316
+ *
317
+ * @evidence contracts/common.md#principled-implementation A sample pairs the instant with the usage object exactly as the getter returned it, so the report keeps Node's own fields.
318
+ * @evidence contracts/common.md#clear-and-simple-design Two fields with no behavior.
319
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The usage is the getter's return value, not a synthesized reading.
320
+ * @evidence contracts/common.md#meaningful-documentation The comment states the time format and the source of the usage.
321
+ */
169
322
  interface IMemory {
323
+ /** ISO 8601 time when the memory getter completed. */
170
324
  time: string;
325
+ /** Node memory usage fields in bytes, supplied by the selected getter. */
171
326
  usage: NodeJS.MemoryUsage;
172
327
  }
173
328
  }
@@ -179,8 +334,45 @@ export declare namespace DynamicBenchmarker {
179
334
  * Note that, {@link IMasterProps.servant} property must be the path of the
180
335
  * servant program executing the {@link servant} function.
181
336
  *
337
+ * The servants are child processes. When a servant fails to connect or to
338
+ * execute, every servant receives a close attempt before the returned promise
339
+ * rejects.
340
+ *
341
+ * Processing cost: Totals are split across T servants once; E events are
342
+ * aggregated with hash-based endpoint grouping. Progress notifications update
343
+ * the aggregate from one servant counter delta in constant time. Event
344
+ * statistics and rendering traverse their input populations; discovery visits
345
+ * each real directory once.
346
+ *
347
+ * Computation reuse: A master distributes distinct request budgets rather
348
+ * than replaying one effectful request. Endpoint grouping shares one event
349
+ * population across whole-run and endpoint statistics. Results are not cached
350
+ * across benchmark runs because server state and timing change.
351
+ *
352
+ * Resource ownership: Each master owns at most threads connectors and
353
+ * simultaneous function workers; connector closure is attempted on
354
+ * connection/execution success or failure; a rejected close is suppressed and
355
+ * may leave an unreleased child process. Events retained by servants/master
356
+ * scale with logged events, and memory samples with run duration. The
357
+ * independent sampler detaches its report target on stop or rejection and
358
+ * clears/wakes its owned timer. A pending caller memory getter has no
359
+ * cancellation hook, but its task retains only the sampler state/getter and
360
+ * cannot keep the master report arrays, connectors or event collections
361
+ * through that state. Its eventual result is discarded after deactivation.
362
+ * Returned reports transfer their arrays to callers.
363
+ *
364
+ * Platform boundary: WorkerConnector process mode owns Node child-process
365
+ * launch/IPC and its explicit stdio modes. Feature discovery resolves the
366
+ * caller location with native path and fs realpath/stat, follows directory
367
+ * links with realpath cycle detection and imports discovered native absolute
368
+ * paths. It does not infer filesystem case policy from OS names.
369
+ *
182
370
  * @param props Properties of the master program
183
371
  * @returns Benchmark report
372
+ * @evidence contracts/common.md#principled-implementation Inputs are validated as safe integers before any process starts; totals are distributed by floor plus remainder; servants execute concurrently and every event is grouped by method and path template in a hash map; closing is attempted for every spawned servant on success and on failure, and the memory sampler is deactivated when the run ends, detaching its report array and clearing/waking its owned timer immediately; a pending caller getter may settle later but cannot append.
373
+ * @evidence contracts/common.md#clear-and-simple-design One function owns the run and keeps the sequence readable: validate, spawn, sample, execute, close, aggregate; statistics come from `DynamicBenchmarkStatistics` and the closing helper is shared by the failure and success paths.
374
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts A servant that fails to close cannot alter a finished report and is not allowed to hide the run's own error, so closing failures are dropped on purpose; no other error is swallowed except a rejecting memory getter, which ends sampling as documented.
375
+ * @evidence contracts/common.md#meaningful-documentation The comment states what the master does, that the servant property must name the servant program, that servants are child processes, and that every servant receives a close attempt before a failure rejects.
184
376
  */
185
377
  const master: (props: IMasterProps) => Promise<IReport>;
186
378
  /**
@@ -188,15 +380,52 @@ export declare namespace DynamicBenchmarker {
188
380
  *
189
381
  * Creates a servant program executing the prefixed functions in parallel.
190
382
  *
383
+ * Processing cost: Each execute request discovers matching modules once, then
384
+ * runs at most simultaneous loop workers and count invocations. Event storage
385
+ * grows with actual logger calls rather than an assumed one event per
386
+ * invocation.
387
+ *
388
+ * Computation reuse: Discovery is refreshed for each execute request because
389
+ * the supplied filter and filesystem can change; requests themselves are
390
+ * effectful and cannot reuse earlier observations.
391
+ *
392
+ * Resource ownership: The returned WorkerServer transfers connection
393
+ * lifecycle to its caller. Each execute owns its discovery collections,
394
+ * workers and event arrays until it completes; the master closes its servant
395
+ * process. No discovered-module cache is retained by this namespace beyond
396
+ * Node own loader.
397
+ *
398
+ * Platform boundary: WorkerConnector process mode owns Node child-process
399
+ * launch/IPC and its explicit stdio modes. Feature discovery resolves the
400
+ * caller location with native path and fs realpath/stat, follows directory
401
+ * links with realpath cycle detection and imports discovered native absolute
402
+ * paths. It does not infer filesystem case policy from OS names.
403
+ *
191
404
  * @param props Properties of the servant program
192
405
  * @returns Servant program as a worker server
406
+ * @evidence contracts/common.md#principled-implementation A servant opens a `WorkerServer` that exposes one `execute` operation; the master decides counts and budgets, so the servant only needs the location and naming rules to find functions.
407
+ * @evidence contracts/common.md#clear-and-simple-design A thin adapter over the worker server whose behavior lives in the private `execute` and `iterate` helpers.
408
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts Discovery is driven by the caller's location, extension, and prefix, and by the master's filter; no file or function name is assumed.
409
+ * @evidence contracts/common.md#meaningful-documentation The comment states that it creates the servant program and returns it as a worker server.
193
410
  */
194
411
  const servant: <Parameters extends any[]>(props: IServantProps<Parameters>) => Promise<WorkerServer<null, IBenchmarkServant, IBenchmarkMaster>>;
195
412
  /**
196
413
  * Convert the benchmark report to markdown content.
197
414
  *
415
+ * Processing cost: Rendering delegates to the reporter and scales with report
416
+ * endpoints, samples and output bytes; host metadata is obtained through Node
417
+ * os APIs.
418
+ *
419
+ * Platform boundary: The wrapper obtains host information through Node os
420
+ * APIs and passes those facts to the pure renderer without constructing
421
+ * native file paths or shell commands.
422
+ *
198
423
  * @param report Benchmark report
199
424
  * @returns Markdown content
425
+ * @evidence contracts/common.md#principled-implementation Rendering is a pure function of the report and a few host facts, delegated to the reporter so the report type and its presentation stay separate.
426
+ * @evidence contracts/common.md#clear-and-simple-design The wrapper captures three native host facts and delegates rendering, giving users one entry point without exposing the internal reporter.
427
+ * @evidence contracts/common.md#prohibited-implementation-shortcuts The function observes native host facts and formats the report without altering its measurements.
428
+ * @evidence contracts/common.md#meaningful-documentation The comment states input and output: a report in, markdown content out.
200
429
  */
201
430
  const markdown: (report: DynamicBenchmarker.IReport) => string;
202
431
  }