Next: Report Output, Up: Advanced Usage [Contents][Index]
THe following example shows a more realistic use case in C:
#include <mbenchmark/all.h> #include <stdio.h> #include <string.h> /* Main can be placed anywhere. */ MICRO_BENCHMARK_MAIN (); /* Recursive implementation -- overflows with small values!. */ long fibrec (int x) { if (x > 1) return fibrec (x - 1) + fibrec (x - 2); if (x < 0) return fibrec (x + 2) - fibrec (x + 1); return x; } /* Iterative implementation -- overflows with small values!. */ long fibit (int x) { long curr, last; #define impl(c, l, start, sign) \ last = l; \ curr = c; \ for (int i = start; i < sign x; ++i) \ { \ long tmp = last sign curr; \ last = curr; \ curr = tmp; \ } \ return curr if (x > 0) { impl (1, 0, 1, +); } impl (0, 1, 0, -); #undef impl } /* Prepare the pointer and its value. */ static int * set_up (micro_benchmark_test_state s) { static int value = 0; value = micro_benchmark_state_get_size (s, 0); value *= micro_benchmark_state_get_size (s, 1) ? 1 : -1; return &value; } static void tear_down (micro_benchmark_test_state s, int *ptr) { char buf[100]; const char *name = micro_benchmark_state_get_name (s); if (strcmp (name, "test_fibit") == 0) snprintf (buf, sizeof (buf) - 1, "fibit/%d", *ptr); else snprintf (buf, sizeof (buf) - 1, "fibrec/%d", *ptr); buf[sizeof (buf) - 1] = '\0'; micro_benchmark_state_set_name (s, buf); } /* Recursive implementation test. */ static void test_fibrec (int *r) { long fib = fibrec (*r); MICRO_BENCHMARK_DO_NOT_OPTIMIZE (fib); } MICRO_BENCHMARK_REGISTER_AUTO_TEST (set_up, test_fibrec, tear_down); /* Iterative implementation test. */ static void test_fibit (int *r) { long fib = fibit (*r); MICRO_BENCHMARK_DO_NOT_OPTIMIZE (fib); } MICRO_BENCHMARK_REGISTER_AUTO_TEST (set_up, test_fibit, tear_down); /* Constraints on the recursive test. */ static void rec_constraints (micro_benchmark_test_case test) { const size_t sizes[] = { 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30 }; const size_t ssizes = sizeof (sizes) / sizeof (*sizes); micro_benchmark_test_case_add_dimension (test, ssizes, sizes); const size_t sign[] = { 0, 1 }; const size_t ssign = sizeof (sign) / sizeof (*sign); micro_benchmark_test_case_add_dimension (test, ssign, sign); micro_benchmark_clock_time mt = { 3, 0 }; micro_benchmark_test_case_set_max_time (test, mt); micro_benchmark_test_case_limit_iterations (test, 0, 1000000); } MICRO_BENCHMARK_CONSTRAINT_TEST ("test_fibrec", rec_constraints); /* Constraints on the iterative test, this is enough. */ static void it_constraints (micro_benchmark_test_case test) { const size_t sizes[] = { 10, 20, 30, 40 }; const size_t ssizes = sizeof (sizes) / sizeof (*sizes); micro_benchmark_test_case_add_dimension (test, ssizes, sizes); const size_t sign[] = { 0, 1 }; const size_t ssign = sizeof (sign) / sizeof (*sign); micro_benchmark_test_case_add_dimension (test, ssign, sign); micro_benchmark_clock_time mt = { 3, 0 }; micro_benchmark_test_case_set_max_time (test, mt); micro_benchmark_test_case_limit_iterations (test, 0, 1000000); } MICRO_BENCHMARK_CONSTRAINT_TEST ("test_fibit", it_constraints);
This is its C++ version:
#include <mbenchmark/all.hpp> #include <functional> /* std::plus and std::less */ #include <string> /* Main can be placed anywhere. */ MICRO_BENCHMARK_MAIN (); namespace { /* Recursive implementation. */ template <typename T, typename I = int> T fibrec (I x) { if (x > 1) return fibrec<T> (x - 1) + fibrec<T> (x - 2); if (x < 0) return fibrec<T> (x + 2) - fibrec<T> (x + 1); return x; } /* Iterative implementation. */ template <typename T, typename I = int> T fibit (I x) { auto doit = [x] (T curr, T last, I start, auto&& op) { for (I i = start; i < op (0, x); ++i) { T tmp = op (last, curr); last = curr; curr = tmp; } return curr; }; if (x > 0) return doit (T{1}, T{0}, 1, std::plus<T>{}); return doit (T{0}, T{1}, 0, std::minus<T>{}); } /* Prepare the pointer and its value. */ int set_up (micro_benchmark::state const& s) { auto sizes = s.sizes (); int value = sizes.at (0); value *= sizes.at (1) ? 1 : -1; return value; } void tear_down (micro_benchmark::state& s, int v) { constexpr auto fibit_base = "fibit/"; constexpr auto fibrec_base = "fibrec/"; std::string name = s.get_name (); if (name == "test_fibit") s.set_name (fibit_base + std::to_string (v)); else s.set_name (fibrec_base + std::to_string (v)); } /* Constraints on the recursive test. */ void rec_constraints (micro_benchmark::test_case& test) { test.add_dimension ({ 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30 }); test.add_dimension ({ 0, 1 }); test.limit_iterations (0, 1000000); } /* Register the recursive test with its constraints. */ void rtestfun (int v) { auto r = fibrec<long> (v); micro_benchmark::do_not_optimize (r); } auto rtest = micro_benchmark::register_test (micro_benchmark::with_constraints, "test_fibrec", rec_constraints, rtestfun, set_up, tear_down); /* Constraints on the iterative test, this is enough. */ void it_constraints (micro_benchmark::test_case& test) { test.add_dimension ({ 10, 20, 30, 40 }); test.add_dimension ({ 0, 1 }); test.limit_iterations (0, 1000000); } /* Register the iterative test with its constraints. */ void itestfun (int v) { auto r = fibit<long> (v); micro_benchmark::do_not_optimize (r); } auto itest = micro_benchmark::register_test (micro_benchmark::with_constraints, "test_fibit", it_constraints, itestfun, set_up, tear_down); }
This is its Guile version:
(define (fibrec n) (cond ((> n 1) (+ (fibrec (- n 2)) (fibrec (- n 1)))) ((< n 0) (- (fibrec (+ n 2)) (fibrec (+ n 1)))) (else n))) (define (fibit n) (define (up curr last p) (if (> p 0) (up (+ curr last) curr (- p 1)) curr)) (define (down curr last p) (if (< p 0) (down (- last curr) curr (+ p 1)) curr)) (cond ((> n 1) (up 1 0 (- n 1))) ((< n 0) (down 0 1 n)) (else n))) (define (set-up state) (define (doit size sign) (if (eqv? sign 0) (list size) (list (- size)))) (apply doit (state-sizes state))) (define (tear-down state n) (let ((base (if (equal? (state-name state) "fibit") "fibit/" "fibrec/"))) (set-state-name! state (string-append base (number->string n))))) (register-test! "fibit" #:test fibit #:set-up set-up #:tear-down tear-down #:dimensions '((10 50 100 500 1000 5000 10000 50000 100000) (0 1)) #:max-iterations 1000000) (register-test! "fibrec" #:test fibrec #:set-up set-up #:tear-down tear-down #:dimensions '((10 12 14 16 18 20 22 24 26 28 30) (0 1)) #:max-iterations 1000000) (main (command-line))
These file can be found on the source code tree as
doc/examples/fib.c
, doc/examples/fib.cxx
and
doc/examples.fib.scm
respectively.
Their output would be something like this:
fib --brief --log-level=warn
⇒
Suite: fib (40 test executions) ======================================== Test Name | Iterations | It.Time (μ) ======================================== fibit | -- | -- fibit/10 | 1000000 | 252ns fibit/50 | 1000000 | 429ns fibit/100 | 1000000 | 1.64μs fibit/500 | 92253 | 53.3μs fibit/1000 | 32308 | 159μs fibit/5000 | 2509 | 2.00ms fibit/10000 | 639 | 7.84ms fibit/50000 | 32 | 157ms fibit/100000 | 9 | 582ms fibit/-10 | 1000000 | 308ns fibit/-50 | 1000000 | 503ns fibit/-100 | 1000000 | 1.94μs fibit/-500 | 80266 | 62.7μs fibit/-1000 | 29633 | 169μs fibit/-5000 | 2153 | 2.33ms fibit/-10000 | 576 | 8.78ms fibit/-50000 | 29 | 173ms fibit/-100000 | 9 | 621ms ---------------------------------------- fibrec | -- | -- fibrec/10 | 1000000 | 2.07μs fibrec/12 | 884087 | 4.53μs fibrec/14 | 388238 | 11.7μs fibrec/16 | 155112 | 31.1μs fibrec/18 | 60585 | 81.3μs fibrec/20 | 23411 | 213μs fibrec/22 | 8991 | 555μs fibrec/24 | 3441 | 1.45ms fibrec/26 | 1316 | 3.80ms fibrec/28 | 510 | 9.84ms fibrec/30 | 195 | 25.7ms fibrec/-10 | 1000000 | 2.81μs fibrec/-12 | 593652 | 7.29μs fibrec/-14 | 243955 | 19.3μs fibrec/-16 | 95423 | 51.0μs fibrec/-18 | 36732 | 135μs fibrec/-20 | 13949 | 357μs fibrec/-22 | 5257 | 0.945ms fibrec/-24 | 1998 | 2.51ms fibrec/-26 | 770 | 6.53ms fibrec/-28 | 295 | 17.0ms fibrec/-30 | 113 | 44.5ms ---------------------------------------- ========================================
The recursive implementation speed decreases very quickly when the magnitude increases. On the other hand, the iterative version can calculate several times values with the same order of magnitude.
Next: Report Output, Up: Advanced Usage [Contents][Index]