@page getting_started Getting Started This guide will walk you through installing checkasm and writing your first test. @tableofcontents @section installation Installation You can either load checkasm as a library (e.g. via `pkg-config`), or include it directly in your project's build system. @subsection meson_submodules Meson using wrap files (recommended) First, create `subprojects/checkasm.wrap`: @code{.ini} [wrap-git] url = https://code.videolan.org/videolan/checkasm.git revision = release # or a specific tag/release directory = checkasm @endcode Then integrate it into your build system: @code{.meson} # 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 @endcode @subsection meson_wrap 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. @code{.bash} git submodule init git submodule add -b release https://code.videolan.org/videolan/checkasm subprojects/checkasm # or checkout a specific tag/release @endcode Then declare the dependency in your `meson.build` as usual. (See the previous section) @subsection manual_installation Manual Installation You can also build and install checkasm manually: @code{.bash} 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 @endcode 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. @section quick_start Quick Start Example Let's create a simple test for a vector addition function that operates on buffers. @subsection quick_start1 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: @code{.h} // my_dsp.h #include 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); @endcode @code{.c} // 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; } @endcode @subsection quick_start2 2. Write the Test Create your test file: @code{.c} // check_dsp.c #include #include #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 INITIALIZE_BUF(src1); INITIALIZE_BUF(src2); // 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_check1d will report any mismatches checkasm_check1d(uint16_t, dst_c, dst_a, w, "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) { const CheckasmCpu cpu = checkasm_get_cpu_flags(); // Test all related functions and report as a single function group test_add8(cpu); // test_add16(cpu); // ... checkasm_report("add"); // 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); } @endcode @subsection quick_start3 3. Build and Run @code{.bash} # 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 @endcode @section options Command-Line Options checkasm provides several useful command-line options: @code{.bash} # 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 @endcode The `--help` output shows all available options: @code{.txt} Usage: checkasm [options...] Use fixed value to seed the PRNG Options: --affinity= Run the process on CPU --bench -b Benchmark the tested functions --csv, --tsv, --json, Choose output format for benchmarks --html --function= -f Test only the functions matching --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[=] Repeat tests N times, on successive seeds --test= -t Test only --verbose -v Print verbose timing info and failure data @endcode --- @section getting_started_next_steps 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:** @ref integration