From 3b491007cbc7db596566c03d139c17fb7c842005 Mon Sep 17 00:00:00 2001 From: 0PrashantYadav0 Date: Mon, 21 Sep 2026 22:13:16 +0530 Subject: [PATCH 1/3] feat: add C benchmark harness to `@stdlib/bench` Signed-off-by: 0PrashantYadav0 --- lib/node_modules/@stdlib/bench/README.md | 355 ++++++++++++++ .../@stdlib/bench/examples/c/Makefile | 146 ++++++ .../@stdlib/bench/examples/c/example.c | 64 +++ .../@stdlib/bench/include/stdlib/bench.h | 443 ++++++++++++++++++ lib/node_modules/@stdlib/bench/manifest.json | 36 ++ lib/node_modules/@stdlib/bench/package.json | 1 + .../zindex-of-truthy/benchmark/c/Makefile | 14 +- .../benchmark/c/benchmark.length.c | 157 ++----- .../ext/base/zindex-of-truthy/manifest.json | 3 +- tools/scripts/compile_c_benchmark | 34 +- tools/snippets/benchmark/c/native/Makefile | 14 +- 11 files changed, 1136 insertions(+), 131 deletions(-) create mode 100644 lib/node_modules/@stdlib/bench/examples/c/Makefile create mode 100644 lib/node_modules/@stdlib/bench/examples/c/example.c create mode 100644 lib/node_modules/@stdlib/bench/include/stdlib/bench.h create mode 100644 lib/node_modules/@stdlib/bench/manifest.json diff --git a/lib/node_modules/@stdlib/bench/README.md b/lib/node_modules/@stdlib/bench/README.md index d2ef2dc837ba..6bc58d9bb67f 100644 --- a/lib/node_modules/@stdlib/bench/README.md +++ b/lib/node_modules/@stdlib/bench/README.md @@ -64,6 +64,359 @@ This function is an alias for [@stdlib/bench/harness][@stdlib/bench/harness]. + + +* * * + +
+ +## C APIs + + + +
+ +The C harness is a header-only library of macros and `static inline` helpers which emit the same [Test Anything Protocol][tap] (TAP) output as hand-written stdlib C benchmarks, so that a benchmark file contains only the code being measured. + +
+ + + + + +
+ +### Usage + +```c +#include "stdlib/bench.h" +``` + +#### STDLIB_BENCH_NAME + +Benchmark name. The macro is **not** defined by the header. The build tooling defines it from the enclosing package name (e.g., `-DSTDLIB_BENCH_NAME="@stdlib/math/base/special/abs"`), and a benchmark file should define a fallback: + +```c +#ifndef STDLIB_BENCH_NAME +#define STDLIB_BENCH_NAME "abs" +#endif +``` + +#### STDLIB_BENCH { ... } + +Macro for defining the main execution sequence. The macro seeds the C standard library pseudorandom number generator, prints the TAP version, runs the block, and prints the TAP summary. + +```c +STDLIB_BENCH { + STDLIB_BENCH_PREAMBLE( 3, 1000000 ) { + STDLIB_BENCH_PRINT_NAME(); + STDLIB_RUN_BENCHMARK( benchmark ); + } +} +``` + +#### STDLIB_BENCH_PREAMBLE( repeats, iterations ) { ... } + +Macro for running a block `repeats` times with a fixed number of iterations. Within the block, `len` is defined and equal to `0`. + +```c +STDLIB_BENCH_PREAMBLE( 3, 1000000 ) { + STDLIB_BENCH_PRINT_NAME(); + STDLIB_RUN_BENCHMARK( benchmark ); +} +``` + +#### STDLIB_BENCH_LENGTH_PREAMBLE( repeats, iterations, min, max ) { ... } + +Macro for running a block `repeats` times for each array length `10^min`, `10^(min+1)`, ..., `10^max`. Within the block, `len` is defined and equal to the current array length. The number of iterations for a given length is `iterations / 10^(exponent-1)`. + +```c +STDLIB_BENCH_LENGTH_PREAMBLE( 3, 10000000, 1, 6 ) { + STDLIB_BENCH_PRINT_NAME_F( "len=%d", len ); + STDLIB_RUN_BENCHMARK( benchmark ); +} +``` + +#### STDLIB_BENCH_PRINT_NAME() + +Macro for printing a benchmark name (`# c::`). + +```c +STDLIB_BENCH_PRINT_NAME(); +``` + +#### STDLIB_BENCH_PRINT_NAME_F( fmt, ... ) + +Macro for printing a benchmark name with a formatted suffix (`# c:::`). At least one format argument must be provided. + +```c +STDLIB_BENCH_PRINT_NAME_F( "len=%d", len ); +``` + +#### STDLIB_RUN_BENCHMARK( fn ) + +Macro for running a benchmark function defined via `STDLIB_BENCHMARK` and printing its results. Must be used within a `STDLIB_BENCH_PREAMBLE` or `STDLIB_BENCH_LENGTH_PREAMBLE` block. + +```c +STDLIB_RUN_BENCHMARK( benchmark ); +``` + +#### STDLIB_BENCHMARK( fn ) { ... } + +Macro for defining a benchmark function. Within the block, `iterations` and `len` are defined. The block must contain `STDLIB_BENCHMARK_LOOP_PREAMBLE`, `STDLIB_BENCHMARK_LOOP_EPILOGUE`, and `STDLIB_BENCHMARK_EPILOGUE`, in that order. + +```c +STDLIB_BENCHMARK( benchmark ) { + double y = 0.0; + + STDLIB_BENCHMARK_UNUSED( len ); + + STDLIB_BENCHMARK_LOOP_PREAMBLE { + y = sqrt( stdlib_bench_random_uniform( 0.0, 100.0 ) ); + if ( y != y ) { + printf( "should not return NaN\n" ); + break; + } + } + STDLIB_BENCHMARK_LOOP_EPILOGUE; + if ( y != y ) { + printf( "should not return NaN\n" ); + } + STDLIB_BENCHMARK_EPILOGUE; +} +``` + +#### STDLIB_BENCHMARK_UNUSED( x ) + +Macro for marking a benchmark function parameter as intentionally unused. Scalar benchmarks which do not use `len` should mark it unused to keep compilation clean under `-Wextra`. + +```c +STDLIB_BENCHMARK_UNUSED( len ); +``` + +#### STDLIB_BENCHMARK_LOOP_PREAMBLE { ... } + +Macro for starting a benchmark timer and beginning the benchmark loop. Within the block, `i` is defined and equal to the current iteration. + +#### STDLIB_BENCHMARK_LOOP_EPILOGUE + +Macro for stopping a benchmark timer. Teardown code (e.g., freeing arrays) should follow this macro. + +#### STDLIB_BENCHMARK_EPILOGUE + +Macro for returning the elapsed time from a benchmark function. + +#### STDLIB_BENCHMARK_MALLOC_ARRAY( type, x, n ) + +Macro for declaring a pointer `x` and allocating an array of `n` elements of type `type`. + +```c +STDLIB_BENCHMARK_MALLOC_ARRAY( double, x, 100 ); +``` + +#### STDLIB_BENCHMARK_MALLOC_ARRAY_FLOAT64( x, n ) + +Macro for declaring a pointer `x` and allocating a double-precision floating-point array of `n` elements. + +```c +STDLIB_BENCHMARK_MALLOC_ARRAY_FLOAT64( x, 100 ); +``` + +#### STDLIB_BENCHMARK_MALLOC_ARRAY_FLOAT32( x, n ) + +Macro for declaring a pointer `x` and allocating a single-precision floating-point array of `n` elements. + +```c +STDLIB_BENCHMARK_MALLOC_ARRAY_FLOAT32( x, 100 ); +``` + +#### STDLIB_BENCHMARK_FILL_ARRAY( x, n, value ) + +Macro for filling an array with a value. The value expression is evaluated once per element. + +```c +STDLIB_BENCHMARK_FILL_ARRAY( x, 100, stdlib_bench_random_uniform( -10.0, 10.0 ) ); +``` + +#### STDLIB_BENCHMARK_FREE( x ) + +Macro for freeing an array allocated via `STDLIB_BENCHMARK_MALLOC_ARRAY*`. + +```c +STDLIB_BENCHMARK_FREE( x ); +``` + +#### stdlib_bench_print_version() + +Prints the TAP version. + +```c +stdlib_bench_print_version(); +``` + +```c +void stdlib_bench_print_version( void ); +``` + +#### stdlib_bench_print_summary( total, passing ) + +Prints the TAP summary. + +```c +stdlib_bench_print_summary( 3, 3 ); +``` + +The function accepts the following arguments: + +- **total**: `[in] int` total number of tests. +- **passing**: `[in] int` total number of passing tests. + +```c +void stdlib_bench_print_summary( const int total, const int passing ); +``` + +#### stdlib_bench_print_results( iterations, elapsed ) + +Prints benchmark results. + +```c +stdlib_bench_print_results( 1000000, 0.5 ); +``` + +The function accepts the following arguments: + +- **iterations**: `[in] int` number of iterations. +- **elapsed**: `[in] double` elapsed time in seconds. + +```c +void stdlib_bench_print_results( const int iterations, const double elapsed ); +``` + +#### stdlib_bench_tic() + +Returns a clock time. + +```c +double t = stdlib_bench_tic(); +``` + +```c +double stdlib_bench_tic( void ); +``` + +#### stdlib_bench_rand_float64() + +Generates a random double-precision floating-point number on the interval `[0,1)`. + +```c +double r = stdlib_bench_rand_float64(); +``` + +```c +double stdlib_bench_rand_float64( void ); +``` + +#### stdlib_bench_rand_float32() + +Generates a random single-precision floating-point number on the interval `[0,1)`. + +```c +float r = stdlib_bench_rand_float32(); +``` + +```c +float stdlib_bench_rand_float32( void ); +``` + +#### stdlib_bench_random_uniform( min, max ) + +Generates a random double-precision floating-point number drawn from a uniform distribution on the interval `[min,max)`. + +```c +double r = stdlib_bench_random_uniform( -10.0, 10.0 ); +``` + +The function accepts the following arguments: + +- **min**: `[in] double` minimum value (inclusive). +- **max**: `[in] double` maximum value (exclusive). + +```c +double stdlib_bench_random_uniform( const double min, const double max ); +``` + +
+ + + + + +
+ +### Notes + +- The harness owns the following identifiers, which are visible to benchmark code: `len`, `iterations`, and `i`. Every other identifier introduced by the harness is prefixed with `stdlib_bench_` (functions and variables) or `STDLIB_BENCH_` / `STDLIB_BENCHMARK_` (macros), with `STDLIB_RUN_BENCHMARK` as the one exception (its name follows the JavaScript harness's `bench()`/`benchmark()` pairing). +- `STDLIB_BENCH` must appear after every `STDLIB_BENCHMARK` function it runs, as `STDLIB_RUN_BENCHMARK` calls the function directly. +- The header depends only on the C standard library. +- The `stdlib_bench_print_*` and `stdlib_bench_tic` helpers are invoked by the harness macros; benchmark code does not normally call them directly. + +
+ + + + + +
+ +### Examples + +```c +#include "stdlib/bench.h" +#include +#include + +#ifndef STDLIB_BENCH_NAME +#define STDLIB_BENCH_NAME "sqrt" +#endif + +#define ITERATIONS 1000000 +#define REPEATS 3 + +STDLIB_BENCHMARK( benchmark ) { + double y = 0.0; + + STDLIB_BENCHMARK_UNUSED( len ); + + STDLIB_BENCHMARK_LOOP_PREAMBLE { + y = sqrt( stdlib_bench_random_uniform( 0.0, 100.0 ) ); + if ( y != y ) { + printf( "should not return NaN\n" ); + break; + } + } + STDLIB_BENCHMARK_LOOP_EPILOGUE; + if ( y != y ) { + printf( "should not return NaN\n" ); + } + STDLIB_BENCHMARK_EPILOGUE; +} + +STDLIB_BENCH { + STDLIB_BENCH_PREAMBLE( REPEATS, ITERATIONS ) { + STDLIB_BENCH_PRINT_NAME(); + STDLIB_RUN_BENCHMARK( benchmark ); + } +} +``` + +
+ + + +
+ + +
@@ -92,6 +445,8 @@ This function is an alias for [@stdlib/bench/harness][@stdlib/bench/harness]. [@stdlib/bench/harness]: https://github.com/stdlib-js/stdlib/tree/develop/lib/node_modules/%40stdlib/bench/harness +[tap]: https://testanything.org/ + [@stdlib/utils/timeit]: https://github.com/stdlib-js/stdlib/tree/develop/lib/node_modules/%40stdlib/utils/timeit diff --git a/lib/node_modules/@stdlib/bench/examples/c/Makefile b/lib/node_modules/@stdlib/bench/examples/c/Makefile new file mode 100644 index 000000000000..c8f8e9a1517b --- /dev/null +++ b/lib/node_modules/@stdlib/bench/examples/c/Makefile @@ -0,0 +1,146 @@ +#/ +# @license Apache-2.0 +# +# Copyright (c) 2026 The Stdlib Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#/ + +# VARIABLES # + +ifndef VERBOSE + QUIET := @ +else + QUIET := +endif + +# Determine the OS ([1][1], [2][2]). +# +# [1]: https://en.wikipedia.org/wiki/Uname#Examples +# [2]: http://stackoverflow.com/a/27776822/2225624 +OS ?= $(shell uname) +ifneq (, $(findstring MINGW,$(OS))) + OS := WINNT +else +ifneq (, $(findstring MSYS,$(OS))) + OS := WINNT +else +ifneq (, $(findstring CYGWIN,$(OS))) + OS := WINNT +else +ifneq (, $(findstring Windows_NT,$(OS))) + OS := WINNT +endif +endif +endif +endif + +# Define the program used for compiling C source files: +ifdef C_COMPILER + CC := $(C_COMPILER) +else + CC := gcc +endif + +# Define the command-line options when compiling C files: +CFLAGS ?= \ + -std=c99 \ + -O3 \ + -Wall \ + -pedantic + +# Determine whether to generate position independent code ([1][1], [2][2]). +# +# [1]: https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#Code-Gen-Options +# [2]: http://stackoverflow.com/questions/5311515/gcc-fpic-option +ifeq ($(OS), WINNT) + fPIC ?= +else + fPIC ?= -fPIC +endif + +# List of includes (e.g., `-I /foo/bar -I /beep/boop/include`): +INCLUDE ?= + +# List of source files: +SOURCE_FILES ?= + +# List of libraries (e.g., `-lopenblas -lpthread`): +LIBRARIES ?= + +# List of library paths (e.g., `-L /foo/bar -L /beep/boop`): +LIBPATH ?= + +# List of C targets: +c_targets := example.out + + +# RULES # + +#/ +# Compiles source files. +# +# @param {string} [C_COMPILER] - C compiler (e.g., `gcc`) +# @param {string} [CFLAGS] - C compiler options +# @param {(string|void)} [fPIC] - compiler flag determining whether to generate position independent code (e.g., `-fPIC`) +# @param {string} [INCLUDE] - list of includes (e.g., `-I /foo/bar -I /beep/boop/include`) +# @param {string} [SOURCE_FILES] - list of source files +# @param {string} [LIBPATH] - list of library paths (e.g., `-L /foo/bar -L /beep/boop`) +# @param {string} [LIBRARIES] - list of libraries (e.g., `-lopenblas -lpthread`) +# +# @example +# make +# +# @example +# make all +#/ +all: $(c_targets) + +.PHONY: all + +#/ +# Compiles C source files. +# +# @private +# @param {string} CC - C compiler (e.g., `gcc`) +# @param {string} CFLAGS - C compiler options +# @param {(string|void)} fPIC - compiler flag determining whether to generate position independent code (e.g., `-fPIC`) +# @param {string} INCLUDE - list of includes (e.g., `-I /foo/bar`) +# @param {string} SOURCE_FILES - list of source files +# @param {string} LIBPATH - list of library paths (e.g., `-L /foo/bar`) +# @param {string} LIBRARIES - list of libraries (e.g., `-lopenblas`) +#/ +$(c_targets): %.out: %.c + $(QUIET) $(CC) $(CFLAGS) $(fPIC) $(INCLUDE) -o $@ $(SOURCE_FILES) $< $(LIBPATH) -lm $(LIBRARIES) + +#/ +# Runs compiled examples. +# +# @example +# make run +#/ +run: $(c_targets) + $(QUIET) ./$< + +.PHONY: run + +#/ +# Removes generated files. +# +# @example +# make clean +#/ +clean: + $(QUIET) -rm -f *.o *.out + +.PHONY: clean diff --git a/lib/node_modules/@stdlib/bench/examples/c/example.c b/lib/node_modules/@stdlib/bench/examples/c/example.c new file mode 100644 index 000000000000..2270dc8c35cd --- /dev/null +++ b/lib/node_modules/@stdlib/bench/examples/c/example.c @@ -0,0 +1,64 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "stdlib/bench.h" +#include +#include + +#ifndef STDLIB_BENCH_NAME +#define STDLIB_BENCH_NAME "sqrt" +#endif + +#define ITERATIONS 1000000 +#define REPEATS 3 + +/** +* Runs a benchmark. +* +* @param iterations number of iterations +* @param len array length (unused) +* @return elapsed time in seconds +*/ +STDLIB_BENCHMARK( benchmark ) { + double y = 0.0; + + STDLIB_BENCHMARK_UNUSED( len ); + + STDLIB_BENCHMARK_LOOP_PREAMBLE { + y = sqrt( stdlib_bench_random_uniform( 0.0, 100.0 ) ); + if ( y != y ) { + printf( "should not return NaN\n" ); + break; + } + } + STDLIB_BENCHMARK_LOOP_EPILOGUE; + if ( y != y ) { + printf( "should not return NaN\n" ); + } + STDLIB_BENCHMARK_EPILOGUE; +} + +/** +* Main execution sequence. +*/ +STDLIB_BENCH { + STDLIB_BENCH_PREAMBLE( REPEATS, ITERATIONS ) { + STDLIB_BENCH_PRINT_NAME(); + STDLIB_RUN_BENCHMARK( benchmark ); + } +} diff --git a/lib/node_modules/@stdlib/bench/include/stdlib/bench.h b/lib/node_modules/@stdlib/bench/include/stdlib/bench.h new file mode 100644 index 000000000000..e3ea798a46d8 --- /dev/null +++ b/lib/node_modules/@stdlib/bench/include/stdlib/bench.h @@ -0,0 +1,443 @@ +/** +* @license Apache-2.0 +* +* Copyright (c) 2026 The Stdlib Authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/** +* Benchmark harness for C benchmarks. +* +* ## Notes +* +* - The harness owns the following identifiers, which are visible to benchmark code: `len`, `iterations`, and `i`. Every other identifier introduced by the harness is prefixed with `stdlib_bench_` (functions and variables) or `STDLIB_BENCH_` / `STDLIB_BENCHMARK_` (macros), with `STDLIB_RUN_BENCHMARK` as the one exception (its name follows the JavaScript harness's `bench()`/`benchmark()` pairing). +* - `STDLIB_BENCH_NAME` must be defined as a string literal before any `STDLIB_BENCH_PRINT_NAME*` macro is used. The build tooling defines it from the enclosing package name (e.g., `-DSTDLIB_BENCH_NAME="@stdlib/math/base/special/abs"`). A benchmark file should provide a fallback: +* +* ```c +* #ifndef STDLIB_BENCH_NAME +* #define STDLIB_BENCH_NAME "abs" +* #endif +* ``` +* +* - Output follows the Test Anything Protocol (TAP) version 13 and matches the output of hand-written stdlib C benchmarks. +* - `STDLIB_BENCH` must appear after every `STDLIB_BENCHMARK` function it runs, as `STDLIB_RUN_BENCHMARK` calls the function directly. +* +* ## Examples +* +* ```c +* #include "stdlib/bench.h" +* #include +* #include +* +* #ifndef STDLIB_BENCH_NAME +* #define STDLIB_BENCH_NAME "sqrt" +* #endif +* +* STDLIB_BENCHMARK( benchmark ) { +* double y = 0.0; +* +* STDLIB_BENCHMARK_UNUSED( len ); +* +* STDLIB_BENCHMARK_LOOP_PREAMBLE { +* y = sqrt( stdlib_bench_random_uniform( 0.0, 100.0 ) ); +* if ( y != y ) { +* printf( "should not return NaN\n" ); +* break; +* } +* } +* STDLIB_BENCHMARK_LOOP_EPILOGUE; +* if ( y != y ) { +* printf( "should not return NaN\n" ); +* } +* STDLIB_BENCHMARK_EPILOGUE; +* } +* +* STDLIB_BENCH { +* STDLIB_BENCH_PREAMBLE( 3, 1000000 ) { +* STDLIB_BENCH_PRINT_NAME(); +* STDLIB_RUN_BENCHMARK( benchmark ); +* } +* } +* ``` +*/ +#ifndef STDLIB_BENCH_H +#define STDLIB_BENCH_H + +#include +#include +#include +#include +#include + +/** +* Prints the TAP version. +*/ +static inline void stdlib_bench_print_version( void ) { + printf( "TAP version 13\n" ); +} + +/** +* Prints the TAP summary. +* +* @param total total number of tests +* @param passing total number of passing tests +*/ +static inline void stdlib_bench_print_summary( const int total, const int passing ) { + printf( "#\n" ); + printf( "1..%d\n", total ); // TAP plan + printf( "# total %d\n", total ); + printf( "# pass %d\n", passing ); + printf( "#\n" ); + printf( "# ok\n" ); +} + +/** +* Prints benchmark results. +* +* @param iterations number of iterations +* @param elapsed elapsed time in seconds +*/ +static inline void stdlib_bench_print_results( const int iterations, const double elapsed ) { + double rate = (double)iterations / elapsed; + printf( " ---\n" ); + printf( " iterations: %d\n", iterations ); + printf( " elapsed: %0.9f\n", elapsed ); + printf( " rate: %0.9f\n", rate ); + printf( " ...\n" ); +} + +/** +* Returns a clock time. +* +* @return clock time +*/ +static inline double stdlib_bench_tic( void ) { + struct timeval now; + gettimeofday( &now, NULL ); + return (double)now.tv_sec + (double)now.tv_usec/1.0e6; +} + +/** +* Generates a random double-precision floating-point number on the interval [0,1). +* +* @return random number +*/ +static inline double stdlib_bench_rand_float64( void ) { + int r = rand(); + return (double)r / ( (double)RAND_MAX + 1.0 ); +} + +/** +* Generates a random single-precision floating-point number on the interval [0,1). +* +* @return random number +*/ +static inline float stdlib_bench_rand_float32( void ) { + int r = rand(); + return (float)r / ( (float)RAND_MAX + 1.0f ); +} + +/** +* Generates a random double-precision floating-point number drawn from a uniform distribution on the interval [min,max). +* +* @param min minimum value (inclusive) +* @param max maximum value (exclusive) +* @return random number +*/ +static inline double stdlib_bench_random_uniform( const double min, const double max ) { + return min + ( stdlib_bench_rand_float64() * ( max - min ) ); +} + +/** +* Macro for defining the main execution sequence. +* +* ## Notes +* +* - The macro must be immediately followed by a block (`{ ... }`) containing one or more `STDLIB_BENCH_PREAMBLE` or `STDLIB_BENCH_LENGTH_PREAMBLE` loops. +* - The macro seeds the C standard library pseudorandom number generator, prints the TAP version, runs the block, and prints the TAP summary. +* +* @example +* STDLIB_BENCH { +* STDLIB_BENCH_PREAMBLE( 3, 1000000 ) { +* STDLIB_BENCH_PRINT_NAME(); +* STDLIB_RUN_BENCHMARK( benchmark ); +* } +* } +*/ +#define STDLIB_BENCH \ + static void stdlib_bench_main( void ); \ + static int stdlib_bench_count = 0; \ + int main( void ) { \ + srand( time( NULL ) ); \ + stdlib_bench_print_version(); \ + stdlib_bench_main(); \ + stdlib_bench_print_summary( stdlib_bench_count, stdlib_bench_count ); \ + return 0; \ + } \ + static void stdlib_bench_main( void ) + +/** +* Macro for running a block `repeats` times with a fixed number of iterations. +* +* ## Notes +* +* - The macro must be immediately followed by a block (`{ ... }`). +* - Within the block, `len` is defined and equal to `0`. +* +* @param repeats number of repeats +* @param iterations number of iterations +* +* @example +* STDLIB_BENCH_PREAMBLE( 3, 1000000 ) { +* STDLIB_BENCH_PRINT_NAME(); +* STDLIB_RUN_BENCHMARK( benchmark ); +* } +*/ +#define STDLIB_BENCH_PREAMBLE( repeats, iterations ) \ + for ( int len = 0, stdlib_bench_iter = (iterations), stdlib_bench_r = 0; stdlib_bench_r < (repeats); stdlib_bench_r++ ) + +/** +* Macro for running a block `repeats` times for each array length `10^min`, `10^(min+1)`, ..., `10^max`. +* +* ## Notes +* +* - The macro must be immediately followed by a block (`{ ... }`). +* - Within the block, `len` is defined and equal to the current array length. +* - The number of iterations for a given length is `iterations / 10^(exponent-1)`. +* +* @param repeats number of repeats +* @param iterations number of iterations for the smallest array length +* @param min minimum exponent +* @param max maximum exponent +* +* @example +* STDLIB_BENCH_LENGTH_PREAMBLE( 3, 10000000, 1, 6 ) { +* STDLIB_BENCH_PRINT_NAME_F( "len=%d", len ); +* STDLIB_RUN_BENCHMARK( benchmark ); +* } +*/ +#define STDLIB_BENCH_LENGTH_PREAMBLE( repeats, iterations, min, max ) \ + for ( int stdlib_bench_exp = (min); stdlib_bench_exp <= (max); stdlib_bench_exp++ ) \ + for ( int len = (int)pow( 10, stdlib_bench_exp ), stdlib_bench_iter = (int)( (iterations) / pow( 10, stdlib_bench_exp-1 ) ), stdlib_bench_r = 0; stdlib_bench_r < (repeats); stdlib_bench_r++ ) + +/** +* Macro for printing a benchmark name. +* +* ## Notes +* +* - Requires `STDLIB_BENCH_NAME` to be defined as a string literal. +* +* @example +* STDLIB_BENCH_PRINT_NAME(); +* // => # c:: +*/ +#define STDLIB_BENCH_PRINT_NAME() \ + printf( "# c::%s\n", STDLIB_BENCH_NAME ) + +/** +* Macro for printing a benchmark name with a formatted suffix. +* +* ## Notes +* +* - Requires `STDLIB_BENCH_NAME` to be defined as a string literal. +* - At least one format argument must be provided. +* +* @param fmt `printf` format string for the suffix +* @param ... format arguments +* +* @example +* STDLIB_BENCH_PRINT_NAME_F( "len=%d", len ); +* // => # c:::len=100 +*/ +#define STDLIB_BENCH_PRINT_NAME_F( fmt, ... ) \ + printf( "# c::%s:" fmt "\n", STDLIB_BENCH_NAME, __VA_ARGS__ ) + +/** +* Macro for running a benchmark function and printing its results. +* +* ## Notes +* +* - Must be used within a `STDLIB_BENCH_PREAMBLE` or `STDLIB_BENCH_LENGTH_PREAMBLE` block. +* +* @param fn benchmark function defined via `STDLIB_BENCHMARK` +* +* @example +* STDLIB_RUN_BENCHMARK( benchmark ); +*/ +#define STDLIB_RUN_BENCHMARK( fn ) \ + do { \ + double stdlib_bench_el; \ + stdlib_bench_count += 1; \ + stdlib_bench_el = fn( stdlib_bench_iter, len ); \ + stdlib_bench_print_results( stdlib_bench_iter, stdlib_bench_el ); \ + printf( "ok %d benchmark finished\n", stdlib_bench_count ); \ + } while ( 0 ) + +/** +* Macro for defining a benchmark function. +* +* ## Notes +* +* - The macro must be immediately followed by a block (`{ ... }`). +* - Within the block, `iterations` (number of iterations) and `len` (array length, or `0`) are defined. +* - The block must contain `STDLIB_BENCHMARK_LOOP_PREAMBLE`, `STDLIB_BENCHMARK_LOOP_EPILOGUE`, and `STDLIB_BENCHMARK_EPILOGUE`, in that order. +* +* @param fn function name +* +* @example +* STDLIB_BENCHMARK( benchmark ) { +* double y = 0.0; +* +* STDLIB_BENCHMARK_UNUSED( len ); +* +* STDLIB_BENCHMARK_LOOP_PREAMBLE { +* y = sqrt( stdlib_bench_random_uniform( 0.0, 100.0 ) ); +* if ( y != y ) { +* printf( "should not return NaN\n" ); +* break; +* } +* } +* STDLIB_BENCHMARK_LOOP_EPILOGUE; +* if ( y != y ) { +* printf( "should not return NaN\n" ); +* } +* STDLIB_BENCHMARK_EPILOGUE; +* } +*/ +#define STDLIB_BENCHMARK( fn ) \ + static double fn( int iterations, int len ) + +/** +* Macro for marking a benchmark function parameter as intentionally unused. +* +* ## Notes +* +* - Benchmark functions always receive `len`. Scalar benchmarks which do not use it should mark it unused to keep compilation clean under `-Wextra`. +* +* @param x parameter +* +* @example +* STDLIB_BENCHMARK( benchmark ) { +* STDLIB_BENCHMARK_UNUSED( len ); +* // ... +* } +*/ +#define STDLIB_BENCHMARK_UNUSED( x ) \ + (void)( x ) + +/** +* Macro for starting a benchmark timer and beginning the benchmark loop. +* +* ## Notes +* +* - The macro must be immediately followed by a block (`{ ... }`). +* - Within the block, `i` is defined and equal to the current iteration. +* +* @example +* STDLIB_BENCHMARK_LOOP_PREAMBLE { +* y = sqrt( stdlib_bench_random_uniform( 0.0, 100.0 ) ); +* } +*/ +#define STDLIB_BENCHMARK_LOOP_PREAMBLE \ + double stdlib_bench_elapsed = 0.0; \ + double stdlib_bench_t = stdlib_bench_tic(); \ + for ( int i = 0; i < iterations; i++ ) + +/** +* Macro for stopping a benchmark timer. +* +* @example +* STDLIB_BENCHMARK_LOOP_EPILOGUE; +*/ +#define STDLIB_BENCHMARK_LOOP_EPILOGUE \ + stdlib_bench_elapsed = stdlib_bench_tic() - stdlib_bench_t + +/** +* Macro for returning the elapsed time from a benchmark function. +* +* @example +* STDLIB_BENCHMARK_EPILOGUE; +*/ +#define STDLIB_BENCHMARK_EPILOGUE \ + return stdlib_bench_elapsed + +/** +* Macro for declaring a pointer and allocating an array. +* +* @param type element type +* @param x variable name +* @param n number of elements +* +* @example +* STDLIB_BENCHMARK_MALLOC_ARRAY( double, x, 100 ); +*/ +#define STDLIB_BENCHMARK_MALLOC_ARRAY( type, x, n ) \ + type *x = (type *)malloc( (size_t)(n) * sizeof( type ) ) + +/** +* Macro for declaring a pointer and allocating a double-precision floating-point array. +* +* @param x variable name +* @param n number of elements +* +* @example +* STDLIB_BENCHMARK_MALLOC_ARRAY_FLOAT64( x, 100 ); +*/ +#define STDLIB_BENCHMARK_MALLOC_ARRAY_FLOAT64( x, n ) \ + STDLIB_BENCHMARK_MALLOC_ARRAY( double, x, n ) + +/** +* Macro for declaring a pointer and allocating a single-precision floating-point array. +* +* @param x variable name +* @param n number of elements +* +* @example +* STDLIB_BENCHMARK_MALLOC_ARRAY_FLOAT32( x, 100 ); +*/ +#define STDLIB_BENCHMARK_MALLOC_ARRAY_FLOAT32( x, n ) \ + STDLIB_BENCHMARK_MALLOC_ARRAY( float, x, n ) + +/** +* Macro for filling an array with a value. +* +* @param x array +* @param n number of elements +* @param value fill value (evaluated once per element) +* +* @example +* STDLIB_BENCHMARK_FILL_ARRAY( x, 100, 0.0 ); +* +* @example +* STDLIB_BENCHMARK_FILL_ARRAY( x, 100, stdlib_bench_random_uniform( -10.0, 10.0 ) ); +*/ +#define STDLIB_BENCHMARK_FILL_ARRAY( x, n, value ) \ + do { \ + for ( int stdlib_bench_k = 0; stdlib_bench_k < (n); stdlib_bench_k++ ) { \ + (x)[ stdlib_bench_k ] = (value); \ + } \ + } while ( 0 ) + +/** +* Macro for freeing an array allocated via `STDLIB_BENCHMARK_MALLOC_ARRAY*`. +* +* @param x array +* +* @example +* STDLIB_BENCHMARK_FREE( x ); +*/ +#define STDLIB_BENCHMARK_FREE( x ) \ + free( x ) + +#endif // !STDLIB_BENCH_H diff --git a/lib/node_modules/@stdlib/bench/manifest.json b/lib/node_modules/@stdlib/bench/manifest.json new file mode 100644 index 000000000000..844d692f6439 --- /dev/null +++ b/lib/node_modules/@stdlib/bench/manifest.json @@ -0,0 +1,36 @@ +{ + "options": {}, + "fields": [ + { + "field": "src", + "resolve": true, + "relative": true + }, + { + "field": "include", + "resolve": true, + "relative": true + }, + { + "field": "libraries", + "resolve": false, + "relative": false + }, + { + "field": "libpath", + "resolve": true, + "relative": false + } + ], + "confs": [ + { + "src": [], + "include": [ + "./include" + ], + "libraries": [], + "libpath": [], + "dependencies": [] + } + ] +} diff --git a/lib/node_modules/@stdlib/bench/package.json b/lib/node_modules/@stdlib/bench/package.json index 8d2db36b4d2b..855173d7aac9 100644 --- a/lib/node_modules/@stdlib/bench/package.json +++ b/lib/node_modules/@stdlib/bench/package.json @@ -20,6 +20,7 @@ "directories": { "doc": "./docs", "example": "./examples", + "include": "./include", "lib": "./lib", "test": "./test" }, diff --git a/lib/node_modules/@stdlib/blas/ext/base/zindex-of-truthy/benchmark/c/Makefile b/lib/node_modules/@stdlib/blas/ext/base/zindex-of-truthy/benchmark/c/Makefile index 0756dc7da20a..ab604614ba7d 100644 --- a/lib/node_modules/@stdlib/blas/ext/base/zindex-of-truthy/benchmark/c/Makefile +++ b/lib/node_modules/@stdlib/blas/ext/base/zindex-of-truthy/benchmark/c/Makefile @@ -81,6 +81,16 @@ LIBRARIES ?= # List of library paths (e.g., `-L /foo/bar -L /beep/boop`): LIBPATH ?= +# Benchmark name (typically resolved by the build tooling and used to define `STDLIB_BENCH_NAME`): +BENCHMARK_NAME ?= + +# Compiler definitions: +ifdef BENCHMARK_NAME + DEFINES := -DSTDLIB_BENCH_NAME='"$(BENCHMARK_NAME)"' +else + DEFINES := +endif + # List of C targets: c_targets := benchmark.length.out @@ -92,6 +102,7 @@ c_targets := benchmark.length.out # # @param {string} [C_COMPILER] - C compiler (e.g., `gcc`) # @param {string} [CFLAGS] - C compiler options +# @param {string} [BENCHMARK_NAME] - benchmark name (e.g., `@stdlib/math/base/special/abs`) # @param {(string|void)} [fPIC] - compiler flag determining whether to generate position independent code (e.g., `-fPIC`) # @param {string} [INCLUDE] - list of includes (e.g., `-I /foo/bar -I /beep/boop/include`) # @param {string} [SOURCE_FILES] - list of source files @@ -114,6 +125,7 @@ all: $(c_targets) # @private # @param {string} CC - C compiler (e.g., `gcc`) # @param {string} CFLAGS - C compiler options +# @param {(string|void)} DEFINES - compiler definitions (e.g., `-DSTDLIB_BENCH_NAME='"@stdlib/math/base/special/abs"'`) # @param {(string|void)} fPIC - compiler flag determining whether to generate position independent code (e.g., `-fPIC`) # @param {string} INCLUDE - list of includes (e.g., `-I /foo/bar`) # @param {string} SOURCE_FILES - list of source files @@ -121,7 +133,7 @@ all: $(c_targets) # @param {string} LIBRARIES - list of libraries (e.g., `-lopenblas`) #/ $(c_targets): %.out: %.c - $(QUIET) $(CC) $(CFLAGS) $(fPIC) $(INCLUDE) -o $@ $(SOURCE_FILES) $< $(LIBPATH) -lm $(LIBRARIES) + $(QUIET) $(CC) $(CFLAGS) $(DEFINES) $(fPIC) $(INCLUDE) -o $@ $(SOURCE_FILES) $< $(LIBPATH) -lm $(LIBRARIES) #/ # Runs compiled benchmarks. diff --git a/lib/node_modules/@stdlib/blas/ext/base/zindex-of-truthy/benchmark/c/benchmark.length.c b/lib/node_modules/@stdlib/blas/ext/base/zindex-of-truthy/benchmark/c/benchmark.length.c index faa1ac640b8c..1bf15521bb82 100644 --- a/lib/node_modules/@stdlib/blas/ext/base/zindex-of-truthy/benchmark/c/benchmark.length.c +++ b/lib/node_modules/@stdlib/blas/ext/base/zindex-of-truthy/benchmark/c/benchmark.length.c @@ -18,76 +18,18 @@ #include "stdlib/blas/ext/base/zindex_of_truthy.h" #include "stdlib/complex/float64/ctor.h" -#include +#include "stdlib/bench.h" #include -#include -#include -#include -#define NAME "zindex_of_truthy" +#ifndef STDLIB_BENCH_NAME +#define STDLIB_BENCH_NAME "zindex_of_truthy" +#endif + #define ITERATIONS 10000000 #define REPEATS 3 #define MIN 1 #define MAX 6 -/** -* Prints the TAP version. -*/ -static void print_version( void ) { - printf( "TAP version 13\n" ); -} - -/** -* Prints the TAP summary. -* -* @param total total number of tests -* @param passing total number of passing tests -*/ -static void print_summary( int total, int passing ) { - printf( "#\n" ); - printf( "1..%d\n", total ); // TAP plan - printf( "# total %d\n", total ); - printf( "# pass %d\n", passing ); - printf( "#\n" ); - printf( "# ok\n" ); -} - -/** -* Prints benchmarks results. -* -* @param iterations number of iterations -* @param elapsed elapsed time in seconds -*/ -static void print_results( int iterations, double elapsed ) { - double rate = (double)iterations / elapsed; - printf( " ---\n" ); - printf( " iterations: %d\n", iterations ); - printf( " elapsed: %0.9f\n", elapsed ); - printf( " rate: %0.9f\n", rate ); - printf( " ...\n" ); -} - -/** -* Returns a clock time. -* -* @return clock time -*/ -static double tic( void ) { - struct timeval now; - gettimeofday( &now, NULL ); - return (double)now.tv_sec + (double)now.tv_usec/1.0e6; -} - -/** -* Generates a random number on the interval [0,1). -* -* @return random number -*/ -static double rand_double( void ) { - int r = rand(); - return (double)r / ( (double)RAND_MAX + 1.0 ); -} - /** * Runs a benchmark. * @@ -95,21 +37,14 @@ static double rand_double( void ) { * @param len array length * @return elapsed time in seconds */ -static double benchmark1( int iterations, int len ) { - double elapsed; - double *x; - double t; - int idx; - int i; +STDLIB_BENCHMARK( benchmark1 ) { + int idx = -1; - x = (double *)malloc( (size_t)( len*2 ) * sizeof( double ) ); - for ( i = 0; i < len*2; i++ ) { - x[ i ] = 0.0; - } + STDLIB_BENCHMARK_MALLOC_ARRAY_FLOAT64( x, len*2 ); + STDLIB_BENCHMARK_FILL_ARRAY( x, len*2, 0.0 ); x[ (len*2)-1 ] = 1.0; - idx = -1; - t = tic(); - for ( i = 0; i < iterations; i++ ) { + + STDLIB_BENCHMARK_LOOP_PREAMBLE { x[ (len*2)-4 ] = (double)( i % 4 ); idx = stdlib_strided_zindex_of_truthy( len, (const stdlib_complex128_t *)x, 1 ); if ( idx < 0 ) { @@ -117,12 +52,12 @@ static double benchmark1( int iterations, int len ) { break; } } - elapsed = tic() - t; + STDLIB_BENCHMARK_LOOP_EPILOGUE; if ( idx < 0 ) { printf( "unexpected result\n" ); } - free( x ); - return elapsed; + STDLIB_BENCHMARK_FREE( x ); + STDLIB_BENCHMARK_EPILOGUE; } /** @@ -132,21 +67,14 @@ static double benchmark1( int iterations, int len ) { * @param len array length * @return elapsed time in seconds */ -static double benchmark2( int iterations, int len ) { - double elapsed; - double *x; - double t; - int idx; - int i; +STDLIB_BENCHMARK( benchmark2 ) { + int idx = -1; - x = (double *)malloc( (size_t)( len*2 ) * sizeof( double ) ); - for ( i = 0; i < len*2; i++ ) { - x[ i ] = 0.0; - } + STDLIB_BENCHMARK_MALLOC_ARRAY_FLOAT64( x, len*2 ); + STDLIB_BENCHMARK_FILL_ARRAY( x, len*2, 0.0 ); x[ (len*2)-1 ] = 1.0; - idx = -1; - t = tic(); - for ( i = 0; i < iterations; i++ ) { + + STDLIB_BENCHMARK_LOOP_PREAMBLE { x[ (len*2)-4 ] = (double)( i % 4 ); idx = stdlib_strided_zindex_of_truthy_ndarray( len, (const stdlib_complex128_t *)x, 1, 0 ); if ( idx < 0 ) { @@ -154,47 +82,24 @@ static double benchmark2( int iterations, int len ) { break; } } - elapsed = tic() - t; + STDLIB_BENCHMARK_LOOP_EPILOGUE; if ( idx < 0 ) { printf( "unexpected result\n" ); } - free( x ); - return elapsed; + STDLIB_BENCHMARK_FREE( x ); + STDLIB_BENCHMARK_EPILOGUE; } /** * Main execution sequence. */ -int main( void ) { - double elapsed; - int count; - int iter; - int len; - int i; - int j; - - // Use the current time to seed the random number generator: - srand( time( NULL ) ); - - print_version(); - count = 0; - for ( i = MIN; i <= MAX; i++ ) { - len = pow( 10, i ); - iter = ITERATIONS / pow( 10, i-1 ); - for ( j = 0; j < REPEATS; j++ ) { - count += 1; - printf( "# c::%s:len=%d\n", NAME, len ); - elapsed = benchmark1( iter, len ); - print_results( iter, elapsed ); - printf( "ok %d benchmark finished\n", count ); - } - for ( j = 0; j < REPEATS; j++ ) { - count += 1; - printf( "# c::%s:ndarray:len=%d\n", NAME, len ); - elapsed = benchmark2( iter, len ); - print_results( iter, elapsed ); - printf( "ok %d benchmark finished\n", count ); - } +STDLIB_BENCH { + STDLIB_BENCH_LENGTH_PREAMBLE( REPEATS, ITERATIONS, MIN, MAX ) { + STDLIB_BENCH_PRINT_NAME_F( "len=%d", len ); + STDLIB_RUN_BENCHMARK( benchmark1 ); + } + STDLIB_BENCH_LENGTH_PREAMBLE( REPEATS, ITERATIONS, MIN, MAX ) { + STDLIB_BENCH_PRINT_NAME_F( "ndarray:len=%d", len ); + STDLIB_RUN_BENCHMARK( benchmark2 ); } - print_summary( count, count ); } diff --git a/lib/node_modules/@stdlib/blas/ext/base/zindex-of-truthy/manifest.json b/lib/node_modules/@stdlib/blas/ext/base/zindex-of-truthy/manifest.json index 42014225e8b2..2ae7b18b92f7 100644 --- a/lib/node_modules/@stdlib/blas/ext/base/zindex-of-truthy/manifest.json +++ b/lib/node_modules/@stdlib/blas/ext/base/zindex-of-truthy/manifest.json @@ -65,7 +65,8 @@ "@stdlib/complex/float64/real", "@stdlib/complex/float64/imag", "@stdlib/math/base/assert/is-nan", - "@stdlib/strided/base/stride2offset" + "@stdlib/strided/base/stride2offset", + "@stdlib/bench" ] }, { diff --git a/tools/scripts/compile_c_benchmark b/tools/scripts/compile_c_benchmark index 13ade48240db..27e0968f3df0 100755 --- a/tools/scripts/compile_c_benchmark +++ b/tools/scripts/compile_c_benchmark @@ -35,6 +35,7 @@ # BLAS_DIR BLAS library path (if custom). # CEPHES Cephes mathematical library path. # CEPHES_SRC List of Cephes source files. +# BENCHMARK_NAME Benchmark name. Default: enclosing package name. # INCLUDE Includes (e.g., `-I /foo/bar -I /a/b`). # SOURCE_FILES Source file list. # LIBRARIES Linked libraries (e.g., `-lopenblas -lpthreads`). @@ -84,6 +85,9 @@ cephes="${CEPHES}" # List of Cephes source files: cephes_src="${CEPHES_SRC}" +# Define the benchmark name: +benchmark_name="${BENCHMARK_NAME}" + # Define a list of `include` directories (e.g., `-I /foo/bar -I /beep/boop/include`): include="${INCLUDE}" @@ -141,6 +145,22 @@ resolve_pkg_path() { echo "${pkg_path}" } +# Resolves a package name. +# +# $1 - package path +resolve_pkg_name() { + local pkg_name + local script + + # Generate the script for resolving a package name: + script='"'"var path = require('path'); console.log(require(path.join('$1','package.json')).name);"'"' + + # Resolve package name: + pkg_name=$(eval NODE_PATH="${node_path}" "${node_cmd}" -e "${script}") + + echo "${pkg_name}" +} + # Resolves a package `manifest.json`. # # $1 - package path @@ -262,8 +282,9 @@ resolve_libpaths() { # Compiles benchmark. # # $1 - source directory +# $2 - package name compile() { - cd "$1" && C_COMPILER="${c_compiler}" INCLUDE="${include}" SOURCE_FILES="${source_files}" LIBRARIES="${libraries}" LIBPATH="${libpath}" CEPHES="${cephes}" CEPHES_SRC="${cephes_src}" make 2>&1 + cd "$1" && C_COMPILER="${c_compiler}" INCLUDE="${include}" SOURCE_FILES="${source_files}" LIBRARIES="${libraries}" LIBPATH="${libpath}" CEPHES="${cephes}" CEPHES_SRC="${cephes_src}" BENCHMARK_NAME="$2" make 2>&1 if [[ "$?" -ne 0 ]]; then echo 'Error when attempting to compile benchmark.' >&2 return 1 @@ -288,6 +309,15 @@ main() { fi echo "Package path: ${pkg_path}" >&2 + if [[ -z "${benchmark_name}" ]]; then + echo 'Resolving benchmark name...' >&2 + benchmark_name=$(resolve_pkg_name "${pkg_path}") + if [[ "$?" -ne 0 ]]; then + on_error 1 + fi + echo "Benchmark name: ${benchmark_name}" >&2 + fi + echo 'Resolving package manifest...' >&2 manifest=$(resolve_pkg_manifest "${pkg_path}") if [[ "$?" -eq 0 ]]; then @@ -325,7 +355,7 @@ main() { fi echo 'Compiling benchmark...' >&2 src_dir=$(dirname "${file_path}") - compile "${src_dir}" + compile "${src_dir}" "${benchmark_name}" if [[ "$?" -ne 0 ]]; then on_error 1 fi diff --git a/tools/snippets/benchmark/c/native/Makefile b/tools/snippets/benchmark/c/native/Makefile index ab9c1fd59d99..9ba650e9f403 100644 --- a/tools/snippets/benchmark/c/native/Makefile +++ b/tools/snippets/benchmark/c/native/Makefile @@ -81,6 +81,16 @@ LIBRARIES ?= # List of library paths (e.g., `-L /foo/bar -L /beep/boop`): LIBPATH ?= +# Benchmark name (typically resolved by the build tooling and used to define `STDLIB_BENCH_NAME`): +BENCHMARK_NAME ?= + +# Compiler definitions: +ifdef BENCHMARK_NAME + DEFINES := -DSTDLIB_BENCH_NAME='"$(BENCHMARK_NAME)"' +else + DEFINES := +endif + # List of C targets: c_targets := TODO.out @@ -96,6 +106,7 @@ c_targets := TODO.out # @param {string} [LIBPATH] - list of library paths (e.g., `-L /foo/bar -L /beep/boop`) # @param {string} [C_COMPILER] - C compiler # @param {string} [CFLAGS] - C compiler flags +# @param {string} [BENCHMARK_NAME] - benchmark name (e.g., `@stdlib/math/base/special/abs`) # @param {(string|void)} [fPIC] - compiler flag indicating whether to generate position independent code # # @example @@ -118,10 +129,11 @@ all: $(c_targets) # @param {(string|void)} LIBPATH - list of library paths (e.g., `-L /foo/bar -L /beep/boop`) # @param {string} CC - C compiler # @param {string} CFLAGS - C compiler flags +# @param {(string|void)} DEFINES - compiler definitions (e.g., `-DSTDLIB_BENCH_NAME='"@stdlib/math/base/special/abs"'`) # @param {(string|void)} fPIC - compiler flag indicating whether to generate position independent code #/ $(c_targets): %.out: %.c - $(QUIET) $(CC) $(CFLAGS) $(fPIC) $(INCLUDE) -o $@ $(SOURCE_FILES) $< $(LIBPATH) -lm $(LIBRARIES) + $(QUIET) $(CC) $(CFLAGS) $(DEFINES) $(fPIC) $(INCLUDE) -o $@ $(SOURCE_FILES) $< $(LIBPATH) -lm $(LIBRARIES) #/ # Runs compiled benchmarks. From 7ec6ca9599590c77c637c372a77a85b9a4e0ec9f Mon Sep 17 00:00:00 2001 From: 0PrashantYadav0 Date: Mon, 21 Sep 2026 22:35:46 +0530 Subject: [PATCH 2/3] chore: resolve lint errors Signed-off-by: 0PrashantYadav0 --- type: pre_commit_static_analysis_report description: Results of running static analysis checks when committing changes. report: - task: lint_filenames status: passed - task: lint_editorconfig status: passed - task: lint_markdown_pkg_readmes status: na - task: lint_markdown_docs status: na - task: lint_markdown status: na - task: lint_package_json status: na - task: lint_repl_help status: na - task: lint_javascript_src status: na - task: lint_javascript_cli status: na - task: lint_javascript_examples status: na - task: lint_javascript_tests status: na - task: lint_javascript_benchmarks status: na - task: lint_python status: na - task: lint_r status: na - task: lint_c_src status: na - task: lint_c_examples status: na - task: lint_c_benchmarks status: na - task: lint_c_tests_fixtures status: na - task: lint_shell status: passed - task: lint_typescript_declarations status: passed - task: lint_typescript_tests status: na - task: lint_license_headers status: passed --- --- tools/scripts/compile_c_benchmark | 5 +++-- tools/snippets/benchmark/c/native/Makefile | 14 +------------- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/tools/scripts/compile_c_benchmark b/tools/scripts/compile_c_benchmark index 27e0968f3df0..553c195abe94 100755 --- a/tools/scripts/compile_c_benchmark +++ b/tools/scripts/compile_c_benchmark @@ -42,6 +42,8 @@ # LIBPATH Library paths (e.g., `-L /foo/bar -L /a/b`). # +# shellcheck disable=SC2181,SC2153 + # VARIABLES # @@ -299,7 +301,6 @@ compile() { # Main execution sequence. main() { local pkg_path - local manifest local src_dir echo 'Resolving package path...' >&2 @@ -319,7 +320,7 @@ main() { fi echo 'Resolving package manifest...' >&2 - manifest=$(resolve_pkg_manifest "${pkg_path}") + resolve_pkg_manifest "${pkg_path}" if [[ "$?" -eq 0 ]]; then echo 'Successfully resolved package manifest.' >&2 if [[ -z "${include}" ]]; then diff --git a/tools/snippets/benchmark/c/native/Makefile b/tools/snippets/benchmark/c/native/Makefile index 9ba650e9f403..ab9c1fd59d99 100644 --- a/tools/snippets/benchmark/c/native/Makefile +++ b/tools/snippets/benchmark/c/native/Makefile @@ -81,16 +81,6 @@ LIBRARIES ?= # List of library paths (e.g., `-L /foo/bar -L /beep/boop`): LIBPATH ?= -# Benchmark name (typically resolved by the build tooling and used to define `STDLIB_BENCH_NAME`): -BENCHMARK_NAME ?= - -# Compiler definitions: -ifdef BENCHMARK_NAME - DEFINES := -DSTDLIB_BENCH_NAME='"$(BENCHMARK_NAME)"' -else - DEFINES := -endif - # List of C targets: c_targets := TODO.out @@ -106,7 +96,6 @@ c_targets := TODO.out # @param {string} [LIBPATH] - list of library paths (e.g., `-L /foo/bar -L /beep/boop`) # @param {string} [C_COMPILER] - C compiler # @param {string} [CFLAGS] - C compiler flags -# @param {string} [BENCHMARK_NAME] - benchmark name (e.g., `@stdlib/math/base/special/abs`) # @param {(string|void)} [fPIC] - compiler flag indicating whether to generate position independent code # # @example @@ -129,11 +118,10 @@ all: $(c_targets) # @param {(string|void)} LIBPATH - list of library paths (e.g., `-L /foo/bar -L /beep/boop`) # @param {string} CC - C compiler # @param {string} CFLAGS - C compiler flags -# @param {(string|void)} DEFINES - compiler definitions (e.g., `-DSTDLIB_BENCH_NAME='"@stdlib/math/base/special/abs"'`) # @param {(string|void)} fPIC - compiler flag indicating whether to generate position independent code #/ $(c_targets): %.out: %.c - $(QUIET) $(CC) $(CFLAGS) $(DEFINES) $(fPIC) $(INCLUDE) -o $@ $(SOURCE_FILES) $< $(LIBPATH) -lm $(LIBRARIES) + $(QUIET) $(CC) $(CFLAGS) $(fPIC) $(INCLUDE) -o $@ $(SOURCE_FILES) $< $(LIBPATH) -lm $(LIBRARIES) #/ # Runs compiled benchmarks. From d97a61eb8ac642e32221910b9690319df148b2cf Mon Sep 17 00:00:00 2001 From: 0PrashantYadav0 Date: Tue, 22 Sep 2026 16:32:01 +0530 Subject: [PATCH 3/3] refactor: address review feedback Signed-off-by: 0PrashantYadav0 --- type: pre_commit_static_analysis_report description: Results of running static analysis checks when committing changes. report: - task: lint_filenames status: passed - task: lint_editorconfig status: passed - task: lint_markdown_pkg_readmes status: passed - task: lint_markdown_docs status: na - task: lint_markdown status: na - task: lint_package_json status: na - task: lint_repl_help status: na - task: lint_javascript_src status: na - task: lint_javascript_cli status: na - task: lint_javascript_examples status: na - task: lint_javascript_tests status: na - task: lint_javascript_benchmarks status: na - task: lint_python status: na - task: lint_r status: na - task: lint_c_src status: na - task: lint_c_examples status: passed - task: lint_c_benchmarks status: passed - task: lint_c_tests_fixtures status: na - task: lint_shell status: na - task: lint_typescript_declarations status: passed - task: lint_typescript_tests status: na - task: lint_license_headers status: passed --- --- lib/node_modules/@stdlib/bench/README.md | 83 ++++++--- .../@stdlib/bench/examples/c/example.c | 7 +- .../@stdlib/bench/include/stdlib/bench.h | 164 +++++++++++++----- .../zindex-of-truthy/benchmark/c/Makefile | 6 +- .../benchmark/c/benchmark.length.c | 16 +- 5 files changed, 193 insertions(+), 83 deletions(-) diff --git a/lib/node_modules/@stdlib/bench/README.md b/lib/node_modules/@stdlib/bench/README.md index 6bc58d9bb67f..35a1b5747f8a 100644 --- a/lib/node_modules/@stdlib/bench/README.md +++ b/lib/node_modules/@stdlib/bench/README.md @@ -92,19 +92,19 @@ The C harness is a header-only library of macros and `static inline` helpers whi #include "stdlib/bench.h" ``` -#### STDLIB_BENCH_NAME +#### BENCHMARK_NAME -Benchmark name. The macro is **not** defined by the header. The build tooling defines it from the enclosing package name (e.g., `-DSTDLIB_BENCH_NAME="@stdlib/math/base/special/abs"`), and a benchmark file should define a fallback: +Benchmark name. The macro is **not** defined by the header. The build tooling defines it from the enclosing package name (e.g., `-DBENCHMARK_NAME="@stdlib/math/base/special/abs"`), and a benchmark file should define a fallback: ```c -#ifndef STDLIB_BENCH_NAME -#define STDLIB_BENCH_NAME "abs" +#ifndef BENCHMARK_NAME +#define BENCHMARK_NAME "abs" #endif ``` #### STDLIB_BENCH { ... } -Macro for defining the main execution sequence. The macro seeds the C standard library pseudorandom number generator, prints the TAP version, runs the block, and prints the TAP summary. +Macro for defining the main execution sequence. The macro expands to a generated `main` function which seeds the C standard library pseudorandom number generator, prints the TAP version, runs the block (as the body of a static function `stdlib_bench_main`), and prints the TAP summary. ```c STDLIB_BENCH { @@ -117,7 +117,7 @@ STDLIB_BENCH { #### STDLIB_BENCH_PREAMBLE( repeats, iterations ) { ... } -Macro for running a block `repeats` times with a fixed number of iterations. Within the block, `len` is defined and equal to `0`. +Macro for running a block `repeats` times with a fixed number of iterations. Within the block, benchmark functions defined via `STDLIB_BENCHMARK` should be run via `STDLIB_RUN_BENCHMARK`. ```c STDLIB_BENCH_PREAMBLE( 3, 1000000 ) { @@ -128,49 +128,55 @@ STDLIB_BENCH_PREAMBLE( 3, 1000000 ) { #### STDLIB_BENCH_LENGTH_PREAMBLE( repeats, iterations, min, max ) { ... } -Macro for running a block `repeats` times for each array length `10^min`, `10^(min+1)`, ..., `10^max`. Within the block, `len` is defined and equal to the current array length. The number of iterations for a given length is `iterations / 10^(exponent-1)`. +Macro for running a block `repeats` times for each array length `10^min`, `10^(min+1)`, ..., `10^max`. Within the block, `len` is defined and equal to the current array length, and benchmark functions defined via `STDLIB_LENGTH_BENCHMARK` should be run via `STDLIB_RUN_LENGTH_BENCHMARK`. The number of iterations for a given length is `iterations / 10^(exponent-1)`. ```c STDLIB_BENCH_LENGTH_PREAMBLE( 3, 10000000, 1, 6 ) { - STDLIB_BENCH_PRINT_NAME_F( "len=%d", len ); - STDLIB_RUN_BENCHMARK( benchmark ); + STDLIB_BENCH_PRINT_NAME_FORMAT( "len=%d", len ); + STDLIB_RUN_LENGTH_BENCHMARK( benchmark ); } ``` #### STDLIB_BENCH_PRINT_NAME() -Macro for printing a benchmark name (`# c::`). +Macro for printing a benchmark name (`# c::`). ```c STDLIB_BENCH_PRINT_NAME(); ``` -#### STDLIB_BENCH_PRINT_NAME_F( fmt, ... ) +#### STDLIB_BENCH_PRINT_NAME_FORMAT( fmt, ... ) -Macro for printing a benchmark name with a formatted suffix (`# c:::`). At least one format argument must be provided. +Macro for printing a benchmark name with a formatted suffix (`# c:::`). At least one format argument must be provided. ```c -STDLIB_BENCH_PRINT_NAME_F( "len=%d", len ); +STDLIB_BENCH_PRINT_NAME_FORMAT( "len=%d", len ); ``` #### STDLIB_RUN_BENCHMARK( fn ) -Macro for running a benchmark function defined via `STDLIB_BENCHMARK` and printing its results. Must be used within a `STDLIB_BENCH_PREAMBLE` or `STDLIB_BENCH_LENGTH_PREAMBLE` block. +Macro for running a benchmark function defined via `STDLIB_BENCHMARK` and printing its results. Must be used within a `STDLIB_BENCH_PREAMBLE` block. ```c STDLIB_RUN_BENCHMARK( benchmark ); ``` +#### STDLIB_RUN_LENGTH_BENCHMARK( fn ) + +Macro for running a length-based benchmark function defined via `STDLIB_LENGTH_BENCHMARK` and printing its results. Must be used within a `STDLIB_BENCH_LENGTH_PREAMBLE` block. + +```c +STDLIB_RUN_LENGTH_BENCHMARK( benchmark ); +``` + #### STDLIB_BENCHMARK( fn ) { ... } -Macro for defining a benchmark function. Within the block, `iterations` and `len` are defined. The block must contain `STDLIB_BENCHMARK_LOOP_PREAMBLE`, `STDLIB_BENCHMARK_LOOP_EPILOGUE`, and `STDLIB_BENCHMARK_EPILOGUE`, in that order. +Macro for defining a benchmark function. Within the block, `iterations` is defined. The block must contain `STDLIB_BENCHMARK_LOOP_PREAMBLE`, `STDLIB_BENCHMARK_LOOP_EPILOGUE`, and `STDLIB_BENCHMARK_EPILOGUE`, in that order. ```c STDLIB_BENCHMARK( benchmark ) { double y = 0.0; - STDLIB_BENCHMARK_UNUSED( len ); - STDLIB_BENCHMARK_LOOP_PREAMBLE { y = sqrt( stdlib_bench_random_uniform( 0.0, 100.0 ) ); if ( y != y ) { @@ -186,12 +192,31 @@ STDLIB_BENCHMARK( benchmark ) { } ``` -#### STDLIB_BENCHMARK_UNUSED( x ) +#### STDLIB_LENGTH_BENCHMARK( fn ) { ... } -Macro for marking a benchmark function parameter as intentionally unused. Scalar benchmarks which do not use `len` should mark it unused to keep compilation clean under `-Wextra`. +Macro for defining a length-based benchmark function. Within the block, `iterations` and `len` (array length) are defined. The block must contain `STDLIB_BENCHMARK_LOOP_PREAMBLE`, `STDLIB_BENCHMARK_LOOP_EPILOGUE`, and `STDLIB_BENCHMARK_EPILOGUE`, in that order. ```c -STDLIB_BENCHMARK_UNUSED( len ); +STDLIB_LENGTH_BENCHMARK( benchmark ) { + double y = 0.0; + + STDLIB_BENCHMARK_MALLOC_ARRAY_FLOAT64( x, len ); + STDLIB_BENCHMARK_FILL_ARRAY( x, len, stdlib_bench_random_uniform( -100.0, 100.0 ) ); + + STDLIB_BENCHMARK_LOOP_PREAMBLE { + y = x[ i%len ]; + if ( y != y ) { + printf( "should not return NaN\n" ); + break; + } + } + STDLIB_BENCHMARK_LOOP_EPILOGUE; + if ( y != y ) { + printf( "should not return NaN\n" ); + } + STDLIB_BENCHMARK_FREE( x ); + STDLIB_BENCHMARK_EPILOGUE; +} ``` #### STDLIB_BENCHMARK_LOOP_PREAMBLE { ... } @@ -230,6 +255,14 @@ Macro for declaring a pointer `x` and allocating a single-precision floating-poi STDLIB_BENCHMARK_MALLOC_ARRAY_FLOAT32( x, 100 ); ``` +#### STDLIB_BENCHMARK_FILL_STRIDED_ARRAY( x, n, stride, value ) + +Macro for filling `n` indexed elements of a strided array with a value. The value expression is evaluated once per indexed element. Following stdlib strided array conventions, a negative stride fills the array starting from the last indexed element. + +```c +STDLIB_BENCHMARK_FILL_STRIDED_ARRAY( x, 50, 2, stdlib_bench_random_uniform( -10.0, 10.0 ) ); +``` + #### STDLIB_BENCHMARK_FILL_ARRAY( x, n, value ) Macro for filling an array with a value. The value expression is evaluated once per element. @@ -355,8 +388,8 @@ double stdlib_bench_random_uniform( const double min, const double max ); ### Notes -- The harness owns the following identifiers, which are visible to benchmark code: `len`, `iterations`, and `i`. Every other identifier introduced by the harness is prefixed with `stdlib_bench_` (functions and variables) or `STDLIB_BENCH_` / `STDLIB_BENCHMARK_` (macros), with `STDLIB_RUN_BENCHMARK` as the one exception (its name follows the JavaScript harness's `bench()`/`benchmark()` pairing). -- `STDLIB_BENCH` must appear after every `STDLIB_BENCHMARK` function it runs, as `STDLIB_RUN_BENCHMARK` calls the function directly. +- The harness exposes the following identifiers to benchmark code: `iterations` (within benchmark functions), `i` (within benchmark loops), and `len` (within `STDLIB_BENCH_LENGTH_PREAMBLE` blocks and length-based benchmark functions). Every other identifier introduced by the harness is prefixed with `stdlib_bench_` (functions and variables) or `STDLIB_BENCH_` / `STDLIB_BENCHMARK_` (macros), with `STDLIB_RUN_BENCHMARK` and `STDLIB_RUN_LENGTH_BENCHMARK` as the exceptions (their names follow the JavaScript harness's `bench()`/`benchmark()` pairing). +- `STDLIB_BENCH` must appear after every benchmark function it runs, as `STDLIB_RUN_BENCHMARK` and `STDLIB_RUN_LENGTH_BENCHMARK` call the function directly. - The header depends only on the C standard library. - The `stdlib_bench_print_*` and `stdlib_bench_tic` helpers are invoked by the harness macros; benchmark code does not normally call them directly. @@ -375,8 +408,8 @@ double stdlib_bench_random_uniform( const double min, const double max ); #include #include -#ifndef STDLIB_BENCH_NAME -#define STDLIB_BENCH_NAME "sqrt" +#ifndef BENCHMARK_NAME +#define BENCHMARK_NAME "sqrt" #endif #define ITERATIONS 1000000 @@ -385,8 +418,6 @@ double stdlib_bench_random_uniform( const double min, const double max ); STDLIB_BENCHMARK( benchmark ) { double y = 0.0; - STDLIB_BENCHMARK_UNUSED( len ); - STDLIB_BENCHMARK_LOOP_PREAMBLE { y = sqrt( stdlib_bench_random_uniform( 0.0, 100.0 ) ); if ( y != y ) { diff --git a/lib/node_modules/@stdlib/bench/examples/c/example.c b/lib/node_modules/@stdlib/bench/examples/c/example.c index 2270dc8c35cd..20a3523ffa29 100644 --- a/lib/node_modules/@stdlib/bench/examples/c/example.c +++ b/lib/node_modules/@stdlib/bench/examples/c/example.c @@ -20,8 +20,8 @@ #include #include -#ifndef STDLIB_BENCH_NAME -#define STDLIB_BENCH_NAME "sqrt" +#ifndef BENCHMARK_NAME +#define BENCHMARK_NAME "sqrt" #endif #define ITERATIONS 1000000 @@ -31,14 +31,11 @@ * Runs a benchmark. * * @param iterations number of iterations -* @param len array length (unused) * @return elapsed time in seconds */ STDLIB_BENCHMARK( benchmark ) { double y = 0.0; - STDLIB_BENCHMARK_UNUSED( len ); - STDLIB_BENCHMARK_LOOP_PREAMBLE { y = sqrt( stdlib_bench_random_uniform( 0.0, 100.0 ) ); if ( y != y ) { diff --git a/lib/node_modules/@stdlib/bench/include/stdlib/bench.h b/lib/node_modules/@stdlib/bench/include/stdlib/bench.h index e3ea798a46d8..d84763e3c3cf 100644 --- a/lib/node_modules/@stdlib/bench/include/stdlib/bench.h +++ b/lib/node_modules/@stdlib/bench/include/stdlib/bench.h @@ -21,17 +21,17 @@ * * ## Notes * -* - The harness owns the following identifiers, which are visible to benchmark code: `len`, `iterations`, and `i`. Every other identifier introduced by the harness is prefixed with `stdlib_bench_` (functions and variables) or `STDLIB_BENCH_` / `STDLIB_BENCHMARK_` (macros), with `STDLIB_RUN_BENCHMARK` as the one exception (its name follows the JavaScript harness's `bench()`/`benchmark()` pairing). -* - `STDLIB_BENCH_NAME` must be defined as a string literal before any `STDLIB_BENCH_PRINT_NAME*` macro is used. The build tooling defines it from the enclosing package name (e.g., `-DSTDLIB_BENCH_NAME="@stdlib/math/base/special/abs"`). A benchmark file should provide a fallback: +* - The harness exposes the following identifiers to benchmark code: `iterations` (within benchmark functions), `i` (within benchmark loops), and `len` (within `STDLIB_BENCH_LENGTH_PREAMBLE` blocks and length-based benchmark functions). Every other identifier introduced by the harness is prefixed with `stdlib_bench_` (functions and variables) or `STDLIB_BENCH_` / `STDLIB_BENCHMARK_` (macros), with `STDLIB_RUN_BENCHMARK` and `STDLIB_RUN_LENGTH_BENCHMARK` as the exceptions (their names follow the JavaScript harness's `bench()`/`benchmark()` pairing). +* - `BENCHMARK_NAME` must be defined as a string literal before any `STDLIB_BENCH_PRINT_NAME*` macro is used. The build tooling defines it from the enclosing package name (e.g., `-DBENCHMARK_NAME="@stdlib/math/base/special/abs"`). A benchmark file should provide a fallback: * * ```c -* #ifndef STDLIB_BENCH_NAME -* #define STDLIB_BENCH_NAME "abs" +* #ifndef BENCHMARK_NAME +* #define BENCHMARK_NAME "abs" * #endif * ``` * * - Output follows the Test Anything Protocol (TAP) version 13 and matches the output of hand-written stdlib C benchmarks. -* - `STDLIB_BENCH` must appear after every `STDLIB_BENCHMARK` function it runs, as `STDLIB_RUN_BENCHMARK` calls the function directly. +* - `STDLIB_BENCH` must appear after every benchmark function it runs, as `STDLIB_RUN_BENCHMARK` and `STDLIB_RUN_LENGTH_BENCHMARK` call the function directly. * * ## Examples * @@ -40,15 +40,13 @@ * #include * #include * -* #ifndef STDLIB_BENCH_NAME -* #define STDLIB_BENCH_NAME "sqrt" +* #ifndef BENCHMARK_NAME +* #define BENCHMARK_NAME "sqrt" * #endif * * STDLIB_BENCHMARK( benchmark ) { * double y = 0.0; * -* STDLIB_BENCHMARK_UNUSED( len ); -* * STDLIB_BENCHMARK_LOOP_PREAMBLE { * y = sqrt( stdlib_bench_random_uniform( 0.0, 100.0 ) ); * if ( y != y ) { @@ -165,7 +163,30 @@ static inline double stdlib_bench_random_uniform( const double min, const double * ## Notes * * - The macro must be immediately followed by a block (`{ ... }`) containing one or more `STDLIB_BENCH_PREAMBLE` or `STDLIB_BENCH_LENGTH_PREAMBLE` loops. -* - The macro seeds the C standard library pseudorandom number generator, prints the TAP version, runs the block, and prints the TAP summary. +* - The macro expands to (1) a forward declaration of a static function `stdlib_bench_main`, (2) a `main` function which seeds the C standard library pseudorandom number generator, prints the TAP version, calls `stdlib_bench_main`, and prints the TAP summary, and (3) the signature of `stdlib_bench_main`. The block following the macro is thus the body of `stdlib_bench_main`. For example, +* +* ```c +* STDLIB_BENCH { +* // ... +* } +* ``` +* +* expands to +* +* ```c +* static void stdlib_bench_main( void ); +* static int stdlib_bench_count = 0; +* int main( void ) { +* srand( time( NULL ) ); +* stdlib_bench_print_version(); +* stdlib_bench_main(); +* stdlib_bench_print_summary( stdlib_bench_count, stdlib_bench_count ); +* return 0; +* } +* static void stdlib_bench_main( void ) { +* // ... +* } +* ``` * * @example * STDLIB_BENCH { @@ -193,7 +214,7 @@ static inline double stdlib_bench_random_uniform( const double min, const double * ## Notes * * - The macro must be immediately followed by a block (`{ ... }`). -* - Within the block, `len` is defined and equal to `0`. +* - Within the block, benchmark functions defined via `STDLIB_BENCHMARK` should be run via `STDLIB_RUN_BENCHMARK`. * * @param repeats number of repeats * @param iterations number of iterations @@ -205,7 +226,7 @@ static inline double stdlib_bench_random_uniform( const double min, const double * } */ #define STDLIB_BENCH_PREAMBLE( repeats, iterations ) \ - for ( int len = 0, stdlib_bench_iter = (iterations), stdlib_bench_r = 0; stdlib_bench_r < (repeats); stdlib_bench_r++ ) + for ( int stdlib_bench_iter = (iterations), stdlib_bench_r = 0; stdlib_bench_r < (repeats); stdlib_bench_r++ ) /** * Macro for running a block `repeats` times for each array length `10^min`, `10^(min+1)`, ..., `10^max`. @@ -214,6 +235,7 @@ static inline double stdlib_bench_random_uniform( const double min, const double * * - The macro must be immediately followed by a block (`{ ... }`). * - Within the block, `len` is defined and equal to the current array length. +* - Within the block, benchmark functions defined via `STDLIB_LENGTH_BENCHMARK` should be run via `STDLIB_RUN_LENGTH_BENCHMARK`. * - The number of iterations for a given length is `iterations / 10^(exponent-1)`. * * @param repeats number of repeats @@ -223,8 +245,8 @@ static inline double stdlib_bench_random_uniform( const double min, const double * * @example * STDLIB_BENCH_LENGTH_PREAMBLE( 3, 10000000, 1, 6 ) { -* STDLIB_BENCH_PRINT_NAME_F( "len=%d", len ); -* STDLIB_RUN_BENCHMARK( benchmark ); +* STDLIB_BENCH_PRINT_NAME_FORMAT( "len=%d", len ); +* STDLIB_RUN_LENGTH_BENCHMARK( benchmark ); * } */ #define STDLIB_BENCH_LENGTH_PREAMBLE( repeats, iterations, min, max ) \ @@ -236,39 +258,39 @@ static inline double stdlib_bench_random_uniform( const double min, const double * * ## Notes * -* - Requires `STDLIB_BENCH_NAME` to be defined as a string literal. +* - Requires `BENCHMARK_NAME` to be defined as a string literal. * * @example * STDLIB_BENCH_PRINT_NAME(); -* // => # c:: +* // => # c:: */ #define STDLIB_BENCH_PRINT_NAME() \ - printf( "# c::%s\n", STDLIB_BENCH_NAME ) + printf( "# c::%s\n", BENCHMARK_NAME ) /** * Macro for printing a benchmark name with a formatted suffix. * * ## Notes * -* - Requires `STDLIB_BENCH_NAME` to be defined as a string literal. +* - Requires `BENCHMARK_NAME` to be defined as a string literal. * - At least one format argument must be provided. * * @param fmt `printf` format string for the suffix * @param ... format arguments * * @example -* STDLIB_BENCH_PRINT_NAME_F( "len=%d", len ); -* // => # c:::len=100 +* STDLIB_BENCH_PRINT_NAME_FORMAT( "len=%d", len ); +* // => # c:::len=100 */ -#define STDLIB_BENCH_PRINT_NAME_F( fmt, ... ) \ - printf( "# c::%s:" fmt "\n", STDLIB_BENCH_NAME, __VA_ARGS__ ) +#define STDLIB_BENCH_PRINT_NAME_FORMAT( fmt, ... ) \ + printf( "# c::%s:" fmt "\n", BENCHMARK_NAME, __VA_ARGS__ ) /** -* Macro for running a benchmark function and printing its results. +* Macro for running a benchmark function defined via `STDLIB_BENCHMARK` and printing its results. * * ## Notes * -* - Must be used within a `STDLIB_BENCH_PREAMBLE` or `STDLIB_BENCH_LENGTH_PREAMBLE` block. +* - Must be used within a `STDLIB_BENCH_PREAMBLE` block. * * @param fn benchmark function defined via `STDLIB_BENCHMARK` * @@ -276,6 +298,27 @@ static inline double stdlib_bench_random_uniform( const double min, const double * STDLIB_RUN_BENCHMARK( benchmark ); */ #define STDLIB_RUN_BENCHMARK( fn ) \ + do { \ + double stdlib_bench_el; \ + stdlib_bench_count += 1; \ + stdlib_bench_el = fn( stdlib_bench_iter ); \ + stdlib_bench_print_results( stdlib_bench_iter, stdlib_bench_el ); \ + printf( "ok %d benchmark finished\n", stdlib_bench_count ); \ + } while ( 0 ) + +/** +* Macro for running a benchmark function defined via `STDLIB_LENGTH_BENCHMARK` and printing its results. +* +* ## Notes +* +* - Must be used within a `STDLIB_BENCH_LENGTH_PREAMBLE` block. +* +* @param fn benchmark function defined via `STDLIB_LENGTH_BENCHMARK` +* +* @example +* STDLIB_RUN_LENGTH_BENCHMARK( benchmark ); +*/ +#define STDLIB_RUN_LENGTH_BENCHMARK( fn ) \ do { \ double stdlib_bench_el; \ stdlib_bench_count += 1; \ @@ -290,7 +333,7 @@ static inline double stdlib_bench_random_uniform( const double min, const double * ## Notes * * - The macro must be immediately followed by a block (`{ ... }`). -* - Within the block, `iterations` (number of iterations) and `len` (array length, or `0`) are defined. +* - Within the block, `iterations` (number of iterations) is defined. * - The block must contain `STDLIB_BENCHMARK_LOOP_PREAMBLE`, `STDLIB_BENCHMARK_LOOP_EPILOGUE`, and `STDLIB_BENCHMARK_EPILOGUE`, in that order. * * @param fn function name @@ -299,8 +342,6 @@ static inline double stdlib_bench_random_uniform( const double min, const double * STDLIB_BENCHMARK( benchmark ) { * double y = 0.0; * -* STDLIB_BENCHMARK_UNUSED( len ); -* * STDLIB_BENCHMARK_LOOP_PREAMBLE { * y = sqrt( stdlib_bench_random_uniform( 0.0, 100.0 ) ); * if ( y != y ) { @@ -316,25 +357,43 @@ static inline double stdlib_bench_random_uniform( const double min, const double * } */ #define STDLIB_BENCHMARK( fn ) \ - static double fn( int iterations, int len ) + static double fn( int iterations ) /** -* Macro for marking a benchmark function parameter as intentionally unused. +* Macro for defining a length-based benchmark function. * * ## Notes * -* - Benchmark functions always receive `len`. Scalar benchmarks which do not use it should mark it unused to keep compilation clean under `-Wextra`. +* - The macro must be immediately followed by a block (`{ ... }`). +* - Within the block, `iterations` (number of iterations) and `len` (array length) are defined. +* - The block must contain `STDLIB_BENCHMARK_LOOP_PREAMBLE`, `STDLIB_BENCHMARK_LOOP_EPILOGUE`, and `STDLIB_BENCHMARK_EPILOGUE`, in that order. * -* @param x parameter +* @param fn function name * * @example -* STDLIB_BENCHMARK( benchmark ) { -* STDLIB_BENCHMARK_UNUSED( len ); -* // ... +* STDLIB_LENGTH_BENCHMARK( benchmark ) { +* double y = 0.0; +* +* STDLIB_BENCHMARK_MALLOC_ARRAY_FLOAT64( x, len ); +* STDLIB_BENCHMARK_FILL_ARRAY( x, len, stdlib_bench_random_uniform( -100.0, 100.0 ) ); +* +* STDLIB_BENCHMARK_LOOP_PREAMBLE { +* y = x[ i%len ]; +* if ( y != y ) { +* printf( "should not return NaN\n" ); +* break; +* } +* } +* STDLIB_BENCHMARK_LOOP_EPILOGUE; +* if ( y != y ) { +* printf( "should not return NaN\n" ); +* } +* STDLIB_BENCHMARK_FREE( x ); +* STDLIB_BENCHMARK_EPILOGUE; * } */ -#define STDLIB_BENCHMARK_UNUSED( x ) \ - (void)( x ) +#define STDLIB_LENGTH_BENCHMARK( fn ) \ + static double fn( int iterations, int len ) /** * Macro for starting a benchmark timer and beginning the benchmark loop. @@ -409,6 +468,33 @@ static inline double stdlib_bench_random_uniform( const double min, const double #define STDLIB_BENCHMARK_MALLOC_ARRAY_FLOAT32( x, n ) \ STDLIB_BENCHMARK_MALLOC_ARRAY( float, x, n ) +/** +* Macro for filling a strided array with a value. +* +* ## Notes +* +* - Following stdlib strided array conventions, a negative stride fills the array starting from the last indexed element (i.e., the first indexed element is at index `(1-n)*stride`). +* +* @param x array +* @param n number of indexed elements +* @param stride stride length +* @param value fill value (evaluated once per indexed element) +* +* @example +* STDLIB_BENCHMARK_FILL_STRIDED_ARRAY( x, 50, 2, 0.0 ); +* +* @example +* STDLIB_BENCHMARK_FILL_STRIDED_ARRAY( x, 50, 2, stdlib_bench_random_uniform( -10.0, 10.0 ) ); +*/ +#define STDLIB_BENCHMARK_FILL_STRIDED_ARRAY( x, n, stride, value ) \ + do { \ + int stdlib_bench_ix = ( (stride) < 0 ) ? ( 1-(n) ) * (stride) : 0; \ + for ( int stdlib_bench_k = 0; stdlib_bench_k < (n); stdlib_bench_k++ ) { \ + (x)[ stdlib_bench_ix ] = (value); \ + stdlib_bench_ix += (stride); \ + } \ + } while ( 0 ) + /** * Macro for filling an array with a value. * @@ -423,11 +509,7 @@ static inline double stdlib_bench_random_uniform( const double min, const double * STDLIB_BENCHMARK_FILL_ARRAY( x, 100, stdlib_bench_random_uniform( -10.0, 10.0 ) ); */ #define STDLIB_BENCHMARK_FILL_ARRAY( x, n, value ) \ - do { \ - for ( int stdlib_bench_k = 0; stdlib_bench_k < (n); stdlib_bench_k++ ) { \ - (x)[ stdlib_bench_k ] = (value); \ - } \ - } while ( 0 ) + STDLIB_BENCHMARK_FILL_STRIDED_ARRAY( x, n, 1, value ) /** * Macro for freeing an array allocated via `STDLIB_BENCHMARK_MALLOC_ARRAY*`. diff --git a/lib/node_modules/@stdlib/blas/ext/base/zindex-of-truthy/benchmark/c/Makefile b/lib/node_modules/@stdlib/blas/ext/base/zindex-of-truthy/benchmark/c/Makefile index ab604614ba7d..32329d7629b6 100644 --- a/lib/node_modules/@stdlib/blas/ext/base/zindex-of-truthy/benchmark/c/Makefile +++ b/lib/node_modules/@stdlib/blas/ext/base/zindex-of-truthy/benchmark/c/Makefile @@ -81,12 +81,12 @@ LIBRARIES ?= # List of library paths (e.g., `-L /foo/bar -L /beep/boop`): LIBPATH ?= -# Benchmark name (typically resolved by the build tooling and used to define `STDLIB_BENCH_NAME`): +# Benchmark name (typically resolved by the build tooling and used to define `BENCHMARK_NAME`): BENCHMARK_NAME ?= # Compiler definitions: ifdef BENCHMARK_NAME - DEFINES := -DSTDLIB_BENCH_NAME='"$(BENCHMARK_NAME)"' + DEFINES := -DBENCHMARK_NAME='"$(BENCHMARK_NAME)"' else DEFINES := endif @@ -125,7 +125,7 @@ all: $(c_targets) # @private # @param {string} CC - C compiler (e.g., `gcc`) # @param {string} CFLAGS - C compiler options -# @param {(string|void)} DEFINES - compiler definitions (e.g., `-DSTDLIB_BENCH_NAME='"@stdlib/math/base/special/abs"'`) +# @param {(string|void)} DEFINES - compiler definitions (e.g., `-DBENCHMARK_NAME='"@stdlib/math/base/special/abs"'`) # @param {(string|void)} fPIC - compiler flag determining whether to generate position independent code (e.g., `-fPIC`) # @param {string} INCLUDE - list of includes (e.g., `-I /foo/bar`) # @param {string} SOURCE_FILES - list of source files diff --git a/lib/node_modules/@stdlib/blas/ext/base/zindex-of-truthy/benchmark/c/benchmark.length.c b/lib/node_modules/@stdlib/blas/ext/base/zindex-of-truthy/benchmark/c/benchmark.length.c index 1bf15521bb82..64bbc21bbac8 100644 --- a/lib/node_modules/@stdlib/blas/ext/base/zindex-of-truthy/benchmark/c/benchmark.length.c +++ b/lib/node_modules/@stdlib/blas/ext/base/zindex-of-truthy/benchmark/c/benchmark.length.c @@ -21,8 +21,8 @@ #include "stdlib/bench.h" #include -#ifndef STDLIB_BENCH_NAME -#define STDLIB_BENCH_NAME "zindex_of_truthy" +#ifndef BENCHMARK_NAME +#define BENCHMARK_NAME "zindex_of_truthy" #endif #define ITERATIONS 10000000 @@ -37,7 +37,7 @@ * @param len array length * @return elapsed time in seconds */ -STDLIB_BENCHMARK( benchmark1 ) { +STDLIB_LENGTH_BENCHMARK( benchmark1 ) { int idx = -1; STDLIB_BENCHMARK_MALLOC_ARRAY_FLOAT64( x, len*2 ); @@ -67,7 +67,7 @@ STDLIB_BENCHMARK( benchmark1 ) { * @param len array length * @return elapsed time in seconds */ -STDLIB_BENCHMARK( benchmark2 ) { +STDLIB_LENGTH_BENCHMARK( benchmark2 ) { int idx = -1; STDLIB_BENCHMARK_MALLOC_ARRAY_FLOAT64( x, len*2 ); @@ -95,11 +95,11 @@ STDLIB_BENCHMARK( benchmark2 ) { */ STDLIB_BENCH { STDLIB_BENCH_LENGTH_PREAMBLE( REPEATS, ITERATIONS, MIN, MAX ) { - STDLIB_BENCH_PRINT_NAME_F( "len=%d", len ); - STDLIB_RUN_BENCHMARK( benchmark1 ); + STDLIB_BENCH_PRINT_NAME_FORMAT( "len=%d", len ); + STDLIB_RUN_LENGTH_BENCHMARK( benchmark1 ); } STDLIB_BENCH_LENGTH_PREAMBLE( REPEATS, ITERATIONS, MIN, MAX ) { - STDLIB_BENCH_PRINT_NAME_F( "ndarray:len=%d", len ); - STDLIB_RUN_BENCHMARK( benchmark2 ); + STDLIB_BENCH_PRINT_NAME_FORMAT( "ndarray:len=%d", len ); + STDLIB_RUN_LENGTH_BENCHMARK( benchmark2 ); } }