1 /* 2 * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/> 3 * (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com> 4 * 5 * This file is part of lsp-plugins 6 * Created on: 16 авг. 2018 г. 7 * 8 * lsp-plugins is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Lesser General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * any later version. 12 * 13 * lsp-plugins is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public License 19 * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>. 20 */ 21 22 #ifndef TEST_PTEST_H_ 23 #define TEST_PTEST_H_ 24 25 #include <stddef.h> 26 #include <stdint.h> 27 #include <stdlib.h> 28 #include <time.h> 29 #include <core/types.h> 30 #include <core/stdlib/stdio.h> 31 #include <data/cstorage.h> 32 #include <test/test.h> 33 34 #define PTEST_BEGIN(group, name, time, iterations) \ 35 namespace ptest { \ 36 namespace { \ 37 \ 38 using namespace ::test; \ 39 \ 40 class ptest_ ## name: public PerformanceTest { \ 41 public: \ 42 typedef ptest_ ## name test_type_t; \ 43 \ 44 public: \ 45 explicit ptest_ ## name() : PerformanceTest(group, #name, time, iterations) {} \ 46 \ 47 virtual ~ptest_ ## name() {} 48 49 #define PTEST_IGNORE \ 50 virtual bool ignore() const { return true; } 51 52 #define PTEST_MAIN \ 53 virtual void execute(int argc, const char **argv) 54 55 #define PTEST_SUPPORTED(ptr) TEST_SUPPORTED(ptr) 56 57 #define PTEST_LOOP(__key, ...) { \ 58 double __start = clock(); \ 59 double __time = 0.0f; \ 60 wsize_t __iterations = 0; \ 61 \ 62 do { \ 63 for (size_t __i=0; __i<__test_iterations; ++__i) { \ 64 __VA_ARGS__; \ 65 } \ 66 /* Calculate statistics */ \ 67 __iterations += __test_iterations; \ 68 __time = (clock() - __start) / CLOCKS_PER_SEC; \ 69 } while (__time < __test_time); \ 70 \ 71 gather_stats(__key, __time, __iterations); \ 72 if (__verbose) { \ 73 printf(" time [s]: %.2f/%.2f\n", __time, __test_time); \ 74 printf(" iterations: %ld/%ld\n", long(__iterations), long((__iterations * __test_time) / __time)); \ 75 printf(" performance [i/s]: %.2f\n", __iterations / __time); \ 76 printf(" iteration time [us/i]: %.4f\n\n", (1000000.0 * __time) / __iterations); \ 77 } \ 78 } 79 80 #define PTEST_KLOOP(__key, __mul, ...) { \ 81 double __start = clock(); \ 82 double __time = 0.0f; \ 83 wsize_t __iterations = 0; \ 84 wsize_t __k_iterations = __test_iterations; \ 85 \ 86 do { \ 87 for (size_t __i=0; __i<__k_iterations; ++__i) { \ 88 __VA_ARGS__; \ 89 } \ 90 /* Calculate statistics */ \ 91 __iterations += __k_iterations; \ 92 __time = (clock() - __start) / CLOCKS_PER_SEC; \ 93 } while (__time < __test_time); \ 94 \ 95 gather_stats(__key, __time, __iterations); \ 96 if (__verbose) { \ 97 printf(" time [s]: %.2f/%.2f\n", __time, __test_time); \ 98 printf(" iterations: %ld/%ld\n", long(__iterations), long((__iterations * __test_time) / __time)); \ 99 printf(" performance [i/s]: %.2f\n", __iterations / __time); \ 100 printf(" iteration time [us/i]: %.4f\n\n", (1000000.0 * __time) / __iterations); \ 101 } \ 102 } 103 104 #define PTEST_SEPARATOR \ 105 gather_stats(NULL, 0.0f, 0); \ 106 printf("\n"); 107 108 #define PTEST_SEPARATOR2 \ 109 gather_stats(NULL, 0.0f, 1); \ 110 printf("\n"); 111 112 #define PTEST_FAIL_MSG(message, ...) { \ 113 fprintf(stderr, "Performance test '%s.%s' has failed at file %s, line %d with message:\n " message "\n", \ 114 __test_group, __test_name, __FILE__, __LINE__, ## __VA_ARGS__); \ 115 exit(1); \ 116 } 117 118 #define PTEST_FAIL() {\ 119 fprintf(stderr, "Performance test '%s.%s' has failed at file %s, line %d\n", \ 120 __test_group, __test_name, __FILE__, __LINE__); \ 121 exit(1); \ 122 } 123 124 #define PTEST_END \ 125 } performance_test; /* ptest class */ \ 126 } /* anonymous namespace */ \ 127 } /* namespace ptest */ 128 129 namespace test 130 { 131 class PerformanceTest: public Test 132 { 133 private: 134 friend PerformanceTest *ptest_init(); 135 136 private: 137 static PerformanceTest *__root; 138 PerformanceTest *__next; 139 140 protected: 141 typedef struct stats_t 142 { 143 char *key; /* The loop indicator */ 144 char *time; /* Actual time [seconds] */ 145 char *n_time; /* Normalized time [seconds] */ 146 char *iterations; /* Number of iterations */ 147 char *n_iterations; /* Normalized number of iterations */ 148 char *performance; /* The performance of test [iterations per second] */ 149 char *time_cost; /* The amount of time spent per iteration [milliseconds per iteration] */ 150 char *rel; /* The relative speed */ 151 double cost; /* The overall cost */ 152 } stats_t; 153 154 protected: 155 size_t __test_iterations; 156 double __test_time; 157 mutable lsp::cstorage<stats_t> __test_stats; 158 159 protected: 160 void gather_stats(const char *key, double time, wsize_t iterations); 161 static void destroy_stats(stats_t *stats); 162 static void estimate(size_t *len, const char *text); 163 static void out_text(FILE *out, size_t length, const char *text, int align, const char *padding, const char *tail); 164 165 public: 166 int printf(const char *fmt, ...); 167 168 public: 169 explicit PerformanceTest(const char *group, const char *name, float time, size_t iterations); 170 virtual ~PerformanceTest(); 171 172 public: next()173 inline PerformanceTest *next() { return __next; } next_test()174 virtual Test *next_test() const { return const_cast<PerformanceTest *>(__next); }; 175 176 void dump_stats(FILE *out) const; 177 void free_stats(); 178 }; 179 180 181 /** 182 * Initialize set of performance tests (validate duplicates, etc) 183 * @return valid set of performance tests 184 */ 185 PerformanceTest *ptest_init(); 186 } 187 188 #endif /* TEST_PTEST_H_ */ 189