vppinfra: auto-free test memory
[vpp.git] / src / vppinfra / test / test.c
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright(c) 2021 Cisco Systems, Inc.
3  */
4
5 #include <vppinfra/format.h>
6 #include <vppinfra/test/test.h>
7 #include <vppinfra/error.h>
8
9 test_main_t test_main;
10
11 int
12 test_march_supported (clib_march_variant_type_t type)
13 {
14 #define _(s, n)                                                               \
15   if (CLIB_MARCH_VARIANT_TYPE_##s == type)                                    \
16     return clib_cpu_march_priority_##s ();
17   foreach_march_variant
18 #undef _
19     return 0;
20 }
21
22 clib_error_t *
23 test_funct (test_main_t *tm)
24 {
25   for (int i = 0; i < CLIB_MARCH_TYPE_N_VARIANTS; i++)
26     {
27       test_registration_t *r = tm->registrations[i];
28
29       if (r == 0 || test_march_supported (i) < 0)
30         continue;
31
32       fformat (stdout, "\nMultiarch Variant: %U\n", format_march_variant, i);
33       fformat (stdout,
34                "-------------------------------------------------------\n");
35       while (r)
36         {
37           clib_error_t *err;
38           if (tm->filter && strstr (r->name, (char *) tm->filter) == 0)
39             goto next;
40           err = (r->fn) (0);
41           fformat (stdout, "%-50s %s\n", r->name, err ? "FAIL" : "PASS");
42           for (int i = 0; i < vec_len (tm->allocated_mem); i++)
43             clib_mem_free (tm->allocated_mem[i]);
44           vec_free (tm->allocated_mem);
45           if (err)
46             {
47               clib_error_report (err);
48               fformat (stdout, "\n");
49             }
50         next:
51           r = r->next;
52         }
53     }
54
55   fformat (stdout, "\n");
56   return 0;
57 }
58
59 #if 0
60 static u8 *
61 format_test_perf_bundle_core_power (u8 *s, va_list *args)
62 {
63   test_perf_event_bundle_t __clib_unused *b =
64     va_arg (*args, test_perf_event_bundle_t *);
65   test_perf_t __clib_unused *tp = va_arg (*args, test_perf_t *);
66   u64 *data = va_arg (*args, u64 *);
67
68   if (data)
69     s = format (s, "%7.1f %%", (f64) 100 * data[1] / data[0]);
70   else
71     s = format (s, "%9s", "Level 0");
72
73   if (data)
74     s = format (s, "%8.1f %%", (f64) 100 * data[2] / data[0]);
75   else
76     s = format (s, "%9s", "Level 1");
77
78   if (data)
79     s = format (s, "%7.1f %%", (f64) 100 * data[3] / data[0]);
80   else
81     s = format (s, "%9s", "Level 2");
82
83   return s;
84 }
85
86 #ifdef __x86_64__
87 #define PERF_INTEL_CODE(event, umask) ((event) | (umask) << 8)
88   ,
89   {
90     .name = "core-power",
91     .desc =
92       "Core cycles where the core was running under specific turbo schedule.",
93     .type = PERF_TYPE_RAW,
94     .config[0] = PERF_INTEL_CODE (0x3c, 0x00),
95     .config[1] = PERF_INTEL_CODE (0x28, 0x07),
96     .config[2] = PERF_INTEL_CODE (0x28, 0x18),
97     .config[3] = PERF_INTEL_CODE (0x28, 0x20),
98     .config[4] = PERF_INTEL_CODE (0x28, 0x40),
99     .n_events = 5,
100     .format_fn = format_test_perf_bundle_core_power,
101   }
102 #endif
103 };
104 #endif
105
106 #ifdef __linux__
107 clib_error_t *
108 test_perf (test_main_t *tm)
109 {
110   clib_error_t *err = 0;
111   clib_perfmon_ctx_t _ctx, *ctx = &_ctx;
112
113   if ((err = clib_perfmon_init_by_bundle_name (
114          ctx, "%s", tm->bundle ? (char *) tm->bundle : "default")))
115     return err;
116
117   fformat (stdout, "Warming up...\n");
118   clib_perfmon_warmup (ctx);
119
120   for (int i = 0; i < CLIB_MARCH_TYPE_N_VARIANTS; i++)
121     {
122       test_registration_t *r = tm->registrations[i];
123
124       if (r == 0 || test_march_supported (i) < 0)
125         continue;
126
127       fformat (stdout, "\nMultiarch Variant: %U\n", format_march_variant, i);
128       fformat (stdout,
129                "-------------------------------------------------------\n");
130       while (r)
131         {
132           if (r->perf_tests)
133             {
134               test_perf_t *pt = r->perf_tests;
135               if (tm->filter && strstr (r->name, (char *) tm->filter) == 0)
136                 goto next;
137
138               clib_perfmon_capture_group (ctx, "%s", r->name);
139               do
140                 {
141                   for (int i = 0; i < tm->repeat; i++)
142                     {
143                       pt->fd = ctx->group_fd;
144                       clib_perfmon_reset (ctx);
145                       pt->fn (pt);
146                       clib_perfmon_capture (ctx, pt->n_ops, "%0s", pt->name);
147                       for (int i = 0; i < vec_len (tm->allocated_mem); i++)
148                         clib_mem_free (tm->allocated_mem[i]);
149                       vec_free (tm->allocated_mem);
150                     }
151                 }
152               while ((++pt)->fn);
153             }
154         next:
155           r = r->next;
156         }
157       fformat (stdout, "%U\n", format_perfmon_bundle, ctx);
158       clib_perfmon_clear (ctx);
159     }
160
161   clib_perfmon_free (ctx);
162   return err;
163 }
164 #endif
165
166 int
167 main (int argc, char *argv[])
168 {
169   test_main_t *tm = &test_main;
170   unformat_input_t _i = {}, *i = &_i;
171   clib_mem_init (0, 64ULL << 20);
172   clib_error_t *err;
173   int perf = 0;
174
175   /* defaults */
176   tm->repeat = 3;
177
178   unformat_init_command_line (i, argv);
179
180   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
181     {
182       if (unformat (i, "perf"))
183         perf = 1;
184       else if (unformat (i, "filter %s", &tm->filter))
185         ;
186       else if (unformat (i, "bundle %s", &tm->bundle))
187         ;
188       else if (unformat (i, "repeat %d", &tm->repeat))
189         ;
190       else
191         {
192           clib_warning ("unknown input '%U'", format_unformat_error, i);
193           exit (1);
194         }
195     }
196
197   if (perf)
198     err = test_perf (tm);
199   else
200     err = test_funct (tm);
201
202   if (err)
203     {
204       clib_error_report (err);
205       fformat (stderr, "\n");
206       return 1;
207     }
208   return 0;
209 }
210
211 void *
212 test_mem_alloc (uword size)
213 {
214   void *rv;
215   size = round_pow2 (size, CLIB_CACHE_LINE_BYTES);
216   rv = clib_mem_alloc_aligned (size, CLIB_CACHE_LINE_BYTES);
217   clib_memset_u8 (rv, 0, size);
218   vec_add1 (test_main.allocated_mem, rv);
219   return rv;
220 }
221
222 void *
223 test_mem_alloc_and_fill_inc_u8 (uword size, u8 start, u8 mask)
224 {
225   u8 *rv;
226   mask = mask ? mask : 0xff;
227   size = round_pow2 (size, CLIB_CACHE_LINE_BYTES);
228   rv = clib_mem_alloc_aligned (size, CLIB_CACHE_LINE_BYTES);
229   for (uword i = 0; i < size; i++)
230     rv[i] = ((u8) i + start) & mask;
231   vec_add1 (test_main.allocated_mem, rv);
232   return rv;
233 }
234
235 void *
236 test_mem_alloc_and_splat (uword elt_size, uword n_elts, void *elt)
237 {
238   u8 *rv, *e;
239   uword data_size = elt_size * n_elts;
240   uword alloc_size = round_pow2 (data_size, CLIB_CACHE_LINE_BYTES);
241   e = rv = clib_mem_alloc_aligned (alloc_size, CLIB_CACHE_LINE_BYTES);
242   while (e - rv < data_size)
243     {
244       clib_memcpy_fast (e, elt, elt_size);
245       e += elt_size;
246     }
247
248   if (data_size < alloc_size)
249     clib_memset_u8 (e, 0, alloc_size - data_size);
250   vec_add1 (test_main.allocated_mem, rv);
251   return rv;
252 }
253