checkasm 1.0.1
Assembly testing and benchmarking framework
Loading...
Searching...
No Matches
Getting Started

This guide will walk you through installing checkasm and writing your first test.

Installation

You can either load checkasm as a library (e.g. via pkg-config), or include it directly in your project's build system.

Meson using wrap files (recommended)

First, create subprojects/checkasm.wrap:

[wrap-git]
url = https://code.videolan.org/videolan/checkasm.git
revision = release # or a specific tag/release
directory = checkasm

Then integrate it into your build system:

# This first attempts loading checkasm as an external dependency using the
# appropriate platform-specific method (e.g. pkg-config on POSIX systems),
# and falls back to using the bundled version inside `subprojects/checkasm`
# otherwise.
checkasm_dependency = dependency('checkasm',
# Extracts the `checkasm_dep` variable from the `checkasm` subproject.
fallback: ['checkasm', 'checkasm_dep'],
required: false
)
# Alternatively, you can directly force use of the bundled version:
# checkasm_dependency = subproject('checkasm').get_variable('checkasm_dep')
if checkasm_dependency.found()
checkasm = executable('checkasm',
checkasm_sources,
dependencies: checkasm_dependency,
)
test('checkasm', checkasm, suite: 'checkasm')
benchmark('checkasm', checkasm, suite: 'checkasm', args: '--bench')
endif

Meson using submodules (alternative)

As an alternative, you may use git submodules to include checkasm as a subproject. This may be preferred in some environments where the build system cannot access the internet during configuration time, or if you're already using submodules in your project.

git submodule init
git submodule add -b release https://code.videolan.org/videolan/checkasm subprojects/checkasm
# or checkout a specific tag/release

Then declare the dependency in your meson.build as usual. (See the previous section)

Manual Installation

You can also build and install checkasm manually:

git clone https://github.com/videolan/checkasm.git && cd checkasm
meson setup builddir -Dprefix=$PREFIX # (set optional build prefix)
meson compile -C builddir
meson install -C builddir

This is discouraged in favor of using Meson subprojects or distribution packages, but may be useful inside containerized environments, CI systems or custom build roots.

Quick Start Example

Let's create a simple test for a vector addition function that operates on buffers.

1. Prerequisites

Let's assume you have a reference implementation and an optimized version, alongside a way of detecting CPU features and choosing the implementation based on that:

// my_dsp.h
#include <stdint.h>
enum {
CPU_FLAG_AVX = 1 << 0,
};
unsigned detect_cpu_flags(void);
typedef void (*add8_func_t)(uint16_t *dst, const uint8_t *src1,
const uint8_t *src2, size_t len);
add8_func_t get_add8_func(unsigned cpu_flags);
// my_dsp.c
#include "my_cpu.h"
// Reference implementation (pure C)
static void add8_c(uint16_t *dst, const uint8_t *src1,
const uint8_t *src2, size_t len)
{
for (size_t i = 0; i < len; i++)
dst[i] = src1[i] + src2[i];
}
// Optimized implementation (pretend this is assembly)
static void add8_avx(uint16_t *dst, const uint8_t *src1,
const uint8_t *src2, size_t len)
{
// Assembly optimized version would go here
add8_c(dst, src1, src2, len);
}
add8_func_t get_add8_func(unsigned cpu_flags)
{
if (cpu_flags & CPU_FLAG_AVX)
return add8_avx;
return add8_c;
}

2. Write the Test

Create your test file:

// check_dsp.c
#include <checkasm/test.h>
#include "my_dsp.h"
#define WIDTH 1024
static void test_add8(const CheckasmCpu cpu)
{
// Declare aligned buffers for testing
CHECKASM_ALIGN(uint8_t src1[WIDTH]);
CHECKASM_ALIGN(uint8_t src2[WIDTH]);
CHECKASM_ALIGN(uint16_t dst_c[WIDTH]);
CHECKASM_ALIGN(uint16_t dst_a[WIDTH]);
// Declare the function signature
checkasm_declare(void, uint16_t *, const uint8_t *, const uint8_t *, size_t);
if (checkasm_check_func(get_add8_func(cpu), "add_8")) {
// Initialize source buffers with quasi-random test vectors
// Test with various buffer sizes
for (int w = 1; w <= WIDTH; w <<= 1) {
// Clear destination buffers before each test
CLEAR_BUF(dst_c);
CLEAR_BUF(dst_a);
// Call reference and optimized implementations
checkasm_call_ref(dst_c, src1, src2, w);
checkasm_call_new(dst_a, src1, src2, w);
// Compare results - checkasm_check will report any mismatches
checkasm_check(uint16_t, dst_c, /*dst_c_stride=*/sizeof(dst_c),
dst_a, /*dst_a_stride=*/sizeof(dst_a),
/*width=*/w, /*height=*/1, "sum");
}
// Benchmark the optimized version on the largest buffer size
checkasm_bench_new(checkasm_alternate(dst_c, dst_a), src1, src2, WIDTH);
}
}
static void check_dsp(void)
{
// Test all related functions and report as a single function group
test_add8(cpu);
// test_add16(cpu);
// ...
// Check more function groups
// ...
}
// Test registry
static const CheckasmTest tests[] = {
{ "dsp", check_dsp },
{0} // array terminator
};
// CPU flag registry
static const CheckasmCpuInfo cpu_flags[] = {
{ "AVX", "avx", CPU_FLAG_AVX },
{0} // array terminator
};
int main(int argc, const char *argv[]) {
CheckasmConfig config = {
.tests = tests,
.cpu_flags = cpu_flags,
.cpu = detect_cpu_flags(),
};
return checkasm_main(&config, argc, argv);
}
Main checkasm API for test suite configuration and execution.
uint64_t CheckasmCpu
Opaque type representing a set of CPU feature flags.
Definition checkasm.h:52
CHECKASM_API CheckasmCpu checkasm_get_cpu_flags(void)
Get the current active set of CPU flags.
CHECKASM_API int checkasm_main(CheckasmConfig *config, int argc, const char *argv[])
Main entry point for checkasm test programs.
#define checkasm_check(type,...)
Compare two 2D buffers and fail test if different.
Definition utils.h:480
#define CHECKASM_ALIGN(x)
Declare a variable with platform-specific alignment requirements.
Definition utils.h:408
#define CLEAR_BUF(buf)
Clear a fixed size buffer (convenience macro).
Definition utils.h:254
#define INITIALIZE_BUF(buf)
Fill a fixed size buffer with pathological test data (convenience macro).
Definition utils.h:269
Configuration structure for the checkasm test suite.
Definition checkasm.h:122
Describes a CPU feature flag/capability.
Definition checkasm.h:69
Describes a single test function.
Definition checkasm.h:81
Test writing API for checkasm.
#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_alternate(a, b)
Alternate between two values during benchmarking.
Definition test.h:429
#define checkasm_call_new(...)
Call the implementation being tested with validation.
Definition test.h:342
#define checkasm_declare(ret,...)
Declare a function signature for testing.
Definition test.h:166
#define checkasm_check_func(func,...)
Check if a function should be tested and set up function references.
Definition test.h:76

3. Build and Run

# Compile (example using gcc directly)
gcc -o check_dsp my_dsp.c check_dsp.c $(pkg-config --cflags --libs checkasm)
# or use `meson compile` if using Meson
# Run all tests
./check_dsp

Command-Line Options

checkasm provides several useful command-line options:

# List all available functions
./checkasm --list-functions
# Run specific functions (supports wildcards)
./checkasm --function=add_*_8bpc
# Run benchmarks
./checkasm --bench
# Run specified test with higher benchmark duration (here: 10 ms)
./checkasm --test=pixel --bench --duration=10000
# Enable verbose output
./checkasm --verbose

The --help output shows all available options:

Usage: checkasm [options...] <random seed>
<random seed> Use fixed value to seed the PRNG
Options:
--affinity=<cpu> Run the process on CPU <cpu>
--bench -b Benchmark the tested functions
--csv, --tsv, --json, Choose output format for benchmarks
--html
--function=<pattern> -f Test only the functions matching <pattern>
--help -h Print this usage info
--list-cpu-flags List available cpu flags
--list-functions List available functions
--list-tests List available tests
--duration=<μs> Benchmark duration (per function) in μs
--repeat[=<N>] Repeat tests N times, on successive seeds
--test=<pattern> -t Test only <pattern>
--verbose -v Print verbose timing info and failure data

Next Steps

Now that you've set up checkasm and written your first test, learn how to integrate it properly with your project's CPU detection and dispatch mechanisms.

Next: Integration Guide