checkasm 1.0.1
Assembly testing and benchmarking framework
Loading...
Searching...
No Matches
test.h File Reference

Detailed Description

Test writing API for checkasm.

This header provides the API used within test functions to declare, call, report, and benchmark different implementations of functions.

Go to the source code of this file.

Data Structures

struct  CheckasmPerf

Macros

#define checkasm_check_func(func, ...)
 Check if a function should be tested and set up function references.
#define checkasm_fail()
 Mark the current test as failed.
#define checkasm_declare(ret, ...)
 Declare a function signature for testing.
#define checkasm_declare_emms(cpu_flags, ret, ...)
 Declare signature for non-ABI compliant MMX functions (x86 only).
#define checkasm_call(func, ...)
 Call a function with signal handling.
#define checkasm_call_checked(func, ...)
 Call an assembly function with full validation.
#define checkasm_func_ref   ((func_type *) checkasm_key_ref)
 Function pointer to the reference implementation.
#define checkasm_func_new   ((func_type *) checkasm_key_new)
 Function pointer to the implementation being tested.
#define checkasm_call_ref(...)
 Call the reference implementation.
#define checkasm_call_new(...)
 Call the implementation being tested with validation.
#define checkasm_bench(func, ...)
 Benchmark a function.
#define checkasm_bench_new(...)
 Benchmark the optimized implementation.
#define checkasm_alternate(a, b)
 Alternate between two values during benchmarking.
#define fail   checkasm_fail
#define report   checkasm_report
#define check_func   checkasm_check_func
#define func_ref   checkasm_func_ref
#define func_new   checkasm_func_new
#define call_ref   checkasm_call_ref
#define call_new   checkasm_call_new
#define bench_new   checkasm_bench_new
#define alternate   checkasm_alternate
#define declare_func   checkasm_declare
#define declare_func_emms   checkasm_declare_emms
#define checkasm_clear_cpu_state()
 Clear CPU state after running a function.
#define CHECKASM_PERF_CALL4(...)
#define CHECKASM_PERF_CALL16(...)
#define CHECKASM_PERF_BENCH_SIMPLE(count, time, ...)
#define CHECKASM_PERF_BENCH_ASM(total_count, time, ...)
#define CHECKASM_PERF_BENCH(count, time, ...)

Functions

CHECKASM_API int checkasm_fail_func (const char *msg,...) CHECKASM_PRINTF(1
 Mark the current function as failed with a custom message.
CHECKASM_API void checkasm_report (const char *name,...) CHECKASM_PRINTF(1
 Report test outcome for a named group of functions.
CHECKASM_API int checkasm_should_fail (CheckasmCpu cpu_flags)
 Mark a block of tests as expected to fail.
CHECKASM_API CheckasmKey checkasm_check_key (CheckasmKey version, const char *name,...) CHECKASM_PRINTF(2
 Internal implementation of checkasm_check_func().
CHECKASM_API CheckasmKey CHECKASM_API void checkasm_set_signal_handler_state (int enabled)
 Enable or disable signal handling.
CHECKASM_API void checkasm_push_stack_guard (uintptr_t guard[2])
 Push stack guard values for corruption detection.
CHECKASM_API void checkasm_pop_stack_guard (void)
CHECKASM_API const CheckasmPerfcheckasm_get_perf (void)
CHECKASM_API int checkasm_bench_func (void)
 Check if current function should be benchmarked.
CHECKASM_API int checkasm_bench_runs (void)
 Get number of iterations for current benchmark run.
CHECKASM_API void checkasm_bench_update (int iterations, uint64_t cycles)
 Update benchmark statistics with timing results.
CHECKASM_API void checkasm_bench_finish (void)
 Finalize and store benchmark results.
static void checkasm_unused (void)
 Suppress unused variable warnings.

Variables

static CheckasmKey checkasm_key_ref
 Key identifying the reference implementation.
static CheckasmKey checkasm_key_new
 Key identifying the implementation being tested.

Macro Definition Documentation

◆ checkasm_alternate

#define checkasm_alternate ( a,
b )
Value:
((tidx & 1) ? (b) : (a))

Alternate between two values during benchmarking.

Returns one of two values, alternating between them across benchmark iterations. Intended for use within bench_new() calls for functions that modify their input buffers. This ensures throughput (not latency) is measured by preventing data dependencies between iterations.

Parameters
aFirst value
bSecond value
Returns
Either a or b depending on the current benchmark iteration
CHECKASM_ALIGN(uint8_t buf0[SIZE]);
CHECKASM_ALIGN(uint8_t buf1[SIZE]);
bench_new(alternate(buf0, buf1), size);
// Each iteration uses a different buffer, preventing stalls
#define CHECKASM_ALIGN(x)
Declare a variable with platform-specific alignment requirements.
Definition utils.h:408

◆ checkasm_bench

#define checkasm_bench ( func,
... )
Value:
do { \
func_type *const bench_func = (func); \
checkasm_set_signal_handler_state(1); \
for (int truns; (truns = checkasm_bench_runs());) { \
uint64_t time; \
CHECKASM_PERF_BENCH(truns, time, __VA_ARGS__); \
checkasm_clear_cpu_state(); \
checkasm_bench_update(truns, time); \
} \
checkasm_set_signal_handler_state(0); \
checkasm_bench_finish(); \
} else { \
const int tidx = 0; \
(void) tidx; \
checkasm_call_checked(func, __VA_ARGS__); \
} \
} while (0)
CHECKASM_API int checkasm_bench_func(void)
Check if current function should be benchmarked.
CHECKASM_API int checkasm_bench_runs(void)
Get number of iterations for current benchmark run.

Benchmark a function.

Repeatedly calls a function to measure its performance. If benchmarking is enabled, runs the function many times and collects timing statistics. If benchmarking is disabled, simply calls the function once with validation.

Parameters
funcFunction pointer to benchmark
...Arguments to pass to the function
Note
This function may be called multiple times within the same checkasm_check_func() block. If done, the timing results will be accumulated and reported as a geometric mean. This is useful for benchmarking multiple different input sizes or configurations that should be reported as a single average figure.
See also
checkasm_bench_new(), checkasm_alternate()

◆ checkasm_bench_new

#define checkasm_bench_new ( ...)
Value:
#define checkasm_bench(func,...)
Benchmark a function.
Definition test.h:363
#define checkasm_func_new
Function pointer to the implementation being tested.
Definition test.h:313

Benchmark the optimized implementation.

Convenience macro that benchmarks the optimized implementation set up by checkasm_check_func(). Equivalent to checkasm_bench(checkasm_func_new, ...).

Parameters
...Arguments to pass to the function
if (checkasm_check_func(get_my_func(checkasm_get_cpu_flags()), "my_func")) {
// Test correctness
checkasm_call_ref(output_ref, input);
checkasm_call_new(output_new, input);
checkasm_check(type, output_ref, output_new);
// Benchmark performance
checkasm_bench_new(output_new, input);
}
checkasm_report("my_func");
CHECKASM_API CheckasmCpu checkasm_get_cpu_flags(void)
Get the current active set of CPU flags.
#define checkasm_check(type,...)
Compare two 2D buffers and fail test if different.
Definition utils.h:480
#define checkasm_bench_new(...)
Benchmark the optimized implementation.
Definition test.h:407
#define checkasm_call_ref(...)
Call the reference implementation.
Definition test.h:327
CHECKASM_API void checkasm_report(const char *name,...) CHECKASM_PRINTF(1
Report test outcome for a named group of functions.
#define checkasm_call_new(...)
Call the implementation being tested with validation.
Definition test.h:342
#define checkasm_check_func(func,...)
Check if a function should be tested and set up function references.
Definition test.h:76
See also
checkasm_bench(), checkasm_check_func()

◆ checkasm_call

#define checkasm_call ( func,
... )
Value:
(checkasm_set_signal_handler_state(1), (func) (__VA_ARGS__)); \
checkasm_set_signal_handler_state(0)
CHECKASM_API CheckasmKey CHECKASM_API void checkasm_set_signal_handler_state(int enabled)
Enable or disable signal handling.

Call a function with signal handling.

Calls an arbitrary function while handling signals (crashes, segfaults, etc.). Use this for calling the reference implementation or other nominally-safe code. For testing assembly/optimized implementations, use checkasm_call_checked() instead, which provides additional validation for common assembly mistakes.

Parameters
funcFunction pointer to call
...Arguments to pass to the function
Note
This only handles signals; use checkasm_call_checked() for full validation.
See also
checkasm_call_checked()

◆ checkasm_call_checked

#define checkasm_call_checked ( func,
... )
Value:
checkasm_push_stack_guard((uintptr_t[16]) { 0, 0 }), \
((func_type *) (func))(__VA_ARGS__)); \
checkasm_pop_stack_guard(); \
checkasm_set_signal_handler_state(0)

Call an assembly function with full validation.

Calls an assembly/optimized function (matching the signature declared by checkasm_declare()) while handling signals and checking for common assembly errors like stack corruption, clobbered registers, register size mismatches and ABI violations. Use this for calling the implementation being tested.

Parameters
funcFunction pointer to call (must match declared signature)
...Arguments to pass to the function
Note
Requires prior call to checkasm_declare().
See also
checkasm_declare(), checkasm_call_ref(), checkasm_call_new()

◆ checkasm_call_new

#define checkasm_call_new ( ...)
Value:
#define checkasm_call_checked(func,...)
Call an assembly function with full validation.
Definition test.h:233

Call the implementation being tested with validation.

Calls the optimized implementation being tested with the specified arguments, including full validation for register clobbering, stack corruption, etc. Must be preceded by a successful checkasm_check_func() call.

Parameters
...Arguments to pass to the function
Returns
Return value from the optimized implementation
See also
checkasm_check_func(), checkasm_call_ref()

◆ checkasm_call_ref

#define checkasm_call_ref ( ...)
Value:
#define checkasm_func_ref
Function pointer to the reference implementation.
Definition test.h:299
#define checkasm_call(func,...)
Call a function with signal handling.
Definition test.h:213

Call the reference implementation.

Calls the reference (C) implementation with the specified arguments. Must be preceded by a successful checkasm_check_func() call.

Parameters
...Arguments to pass to the function
Returns
Return value from the reference implementation
See also
checkasm_check_func(), checkasm_call_new()

◆ checkasm_check_func

#define checkasm_check_func ( func,
... )
Value:
= checkasm_check_key((checkasm_key_new = (CheckasmKey) (func)), __VA_ARGS__))
uintptr_t CheckasmKey
Opaque type used to identify function implementations.
Definition checkasm.h:60
CHECKASM_API CheckasmKey checkasm_check_key(CheckasmKey version, const char *name,...) CHECKASM_PRINTF(2
Internal implementation of checkasm_check_func().
static CheckasmKey checkasm_key_ref
Key identifying the reference implementation.
Definition test.h:278
static CheckasmKey checkasm_key_new
Key identifying the implementation being tested.
Definition test.h:288

Check if a function should be tested and set up function references.

Determines if the given function implementation should be tested, and if so, sets up the function pointers for subsequent calls to checkasm_call_ref() and checkasm_call_new().

Parameters
[in]funcFunction pointer (or arbitrary CheckasmKey) to test, or 0 to skip
[in]namePrintf-style format string for the function name
[in]...Format arguments for the function name
Returns
Non-zero if testing should proceed, 0 if this function should be skipped
if (checkasm_check_func(get_my_func(checkasm_get_cpu_flags()), "my_func")) {
// checkasm_call_ref() and checkasm_call_new() are now ready to use
int ref_result = checkasm_call_ref(args...);
int new_result = checkasm_call_new(args...);
if (ref_result != new_result) {
fprintf(stderr, "expected %d, got %d\n", ref_result, new_result);
}
}
checkasm_report("my_func");
#define checkasm_fail()
Mark the current test as failed.
Definition test.h:116
See also
checkasm_func_ref, checkasm_func_new
checkasm_call_ref(), checkasm_call_new()

◆ checkasm_declare

#define checkasm_declare ( ret,
... )
Value:
checkasm_declare_impl(ret, __VA_ARGS__); \
typedef ret func_type(__VA_ARGS__); \
(void) ((func_type *) NULL)

Declare a function signature for testing.

Declares the function prototype that will be tested. This must be called before using checkasm_call_checked(), checkasm_call_ref(), or checkasm_call_new(). The first argument is the return type, and remaining arguments are the function parameters (naming parameters is optional).

Parameters
retReturn type of the function
...Function parameter types
// Declare signature for: int add(int a, int b)
declare_func(int, int a, int b);
// Can also omit parameter names for brevity:
declare_func(int, int, int);
See also
checkasm_call_checked(), checkasm_call_call_ref(), checkasm_call_new()

◆ checkasm_declare_emms

#define checkasm_declare_emms ( cpu_flags,
ret,
... )
Value:
checkasm_declare(ret, __VA_ARGS__)
#define checkasm_declare(ret,...)
Declare a function signature for testing.
Definition test.h:166

Declare signature for non-ABI compliant MMX functions (x86 only).

Variant of checkasm_declare() for MMX functions that omit calling emms before returning to the caller. This is used for optimized MMX kernels that expect the caller to run emms manually.

Parameters
cpu_flagsMask of CPU flags under which to enable the extra emms call
retReturn type of the function
...Function parameter types
Note
MMX code normally needs to call emms before any floating-point code can be executed. Since this instruction can be very slow, many MMX kernels (used inside loops) are designed to omit emms and instead expect the caller to run emms manually after the loop. This macro will omit the emms check and instead explicitly run emms after calling the function (only when any of the specified cpu_flags are active).
On non-x86 platforms, this is equivalent to checkasm_declare().
See also
checkasm_declare()

◆ checkasm_fail

#define checkasm_fail ( )
Value:
checkasm_fail_func("%s:%d", __FILE__, __LINE__)
CHECKASM_API int checkasm_fail_func(const char *msg,...) CHECKASM_PRINTF(1
Mark the current function as failed with a custom message.

Mark the current test as failed.

Records a test failure with the current file and line number. This is the most common way to indicate test failure. The test will continue executing, but any future calls to checkasm_check_func() for this function will return 0.

Returns
1 if the failure details should be printed verbosely, 0 otherwise
if (output != expected) {
fprintf(stderr, "expected %d, got %d\n", expected, output);
}

◆ checkasm_func_new

#define checkasm_func_new   ((func_type *) checkasm_key_new)

Function pointer to the implementation being tested.

This is just a typed version of checkasm_key_new, cast to the type declared by checkasm_declare().

Note
This is read-only. To test a different function, use checkasm_call_checked() instead of checkasm_call_new().
See also
checkasm_func_ref(), checkasm_check_func()

◆ checkasm_func_ref

#define checkasm_func_ref   ((func_type *) checkasm_key_ref)

Function pointer to the reference implementation.

This is just a typed version of checkasm_key_ref, cast to the type declared by checkasm_declare().

See also
checkasm_func_new(), checkasm_check_func()

Function Documentation

◆ checkasm_fail_func()

CHECKASM_API int checkasm_fail_func ( const char * msg,
... )

Mark the current function as failed with a custom message.

Records a test failure with a printf-style formatted message.

Parameters
[in]msgPrintf-style format string describing the failure
[in]...Format arguments
Returns
1 if the failure details should be printed verbosely, 0 otherwise
if (output != expected)
checkasm_fail_func("%s:%d", filename, line);
Note
This is typically called via checkasm_fail() rather than directly.
See also
checkasm_fail()

◆ checkasm_report()

CHECKASM_API void checkasm_report ( const char * name,
... )

Report test outcome for a named group of functions.

Prints the result (pass/fail) for a named group of functions. Typically called at the end of a test, as well as after any larger block of similar functions.

Note
Since v1.0.1, this is optional. If not called before the end of a test, any remaining results will be reported directly under the name of the associated test itself.
Parameters
[in]namePrintf-style format string for the test case name
[in]...Format arguments
for (int w = 4; w < 128; w <<= 1) {
if (checkasm_check_func(.., "blockcopy_%dbpc_w%d", bits, w)) {
// ...
}
}
checkasm_report("blockcopy_%dbpc", bits);

◆ checkasm_should_fail()

CHECKASM_API int checkasm_should_fail ( CheckasmCpu cpu_flags)

Mark a block of tests as expected to fail.

Marks the following test functions as expected to fail when any of the specified CPU flags are set. Returns whether these functions should be executed.

Parameters
[in]cpu_flagsCPU flags for which failure is expected (or -1 for all)
Returns
1 if functions should be executed, 0 if they should be skipped
Note
All functions inside such a block must fail, otherwise the whole test will be considered failed. This is used for testing that known-broken implementations are properly detected as broken.
This is not normally useful for end users; it is mainly defined for use inside checkasm's internal test suite.
if (checkasm_should_fail(CPU_FLAG_SSE2)) {
// This implementation is known to be broken on SSE2
if (checkasm_check_func(broken_func_sse2, "broken_func")) {
checkasm_call_new(); // should fail
}
}
CHECKASM_API int checkasm_should_fail(CheckasmCpu cpu_flags)
Mark a block of tests as expected to fail.

Variable Documentation

◆ checkasm_key_new

CheckasmKey checkasm_key_new
static

Key identifying the implementation being tested.

Set by checkasm_check_func() to point to the key passed to it.

See also
checkasm_check_func(), checkasm_func_new, checkasm_key_ref
Since
v1.0.1

◆ checkasm_key_ref

CheckasmKey checkasm_key_ref
static

Key identifying the reference implementation.

Set by checkasm_check_func() to point to the reference key for the function currently being tested.

See also
checkasm_check_func(), checkasm_func_ref, checkasm_key_new
Since
v1.0.1