nat: Include platform specific headers on FreeBSD
[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 #elif __FreeBSD__
165 clib_error_t *
166 test_perf (test_main_t *tm)
167 {
168   return NULL;
169 }
170 #endif
171
172 int
173 main (int argc, char *argv[])
174 {
175   test_main_t *tm = &test_main;
176   unformat_input_t _i = {}, *i = &_i;
177   clib_mem_init (0, 64ULL << 20);
178   clib_error_t *err;
179   int perf = 0;
180
181   /* defaults */
182   tm->repeat = 3;
183
184   unformat_init_command_line (i, argv);
185
186   while (unformat_check_input (i) != UNFORMAT_END_OF_INPUT)
187     {
188       if (unformat (i, "perf"))
189         perf = 1;
190       else if (unformat (i, "filter %s", &tm->filter))
191         ;
192       else if (unformat (i, "bundle %s", &tm->bundle))
193         ;
194       else if (unformat (i, "repeat %d", &tm->repeat))
195         ;
196       else
197         {
198           clib_warning ("unknown input '%U'", format_unformat_error, i);
199           exit (1);
200         }
201     }
202
203   if (perf)
204     err = test_perf (tm);
205   else
206     err = test_funct (tm);
207
208   if (err)
209     {
210       clib_error_report (err);
211       fformat (stderr, "\n");
212       return 1;
213     }
214   return 0;
215 }
216
217 void *
218 test_mem_alloc (uword size)
219 {
220   void *rv;
221   size = round_pow2 (size, CLIB_CACHE_LINE_BYTES);
222   rv = clib_mem_alloc_aligned (size, CLIB_CACHE_LINE_BYTES);
223   clib_memset_u8 (rv, 0, size);
224   vec_add1 (test_main.allocated_mem, rv);
225   return rv;
226 }
227
228 void *
229 test_mem_alloc_and_fill_inc_u8 (uword size, u8 start, u8 mask)
230 {
231   u8 *rv;
232   mask = mask ? mask : 0xff;
233   size = round_pow2 (size, CLIB_CACHE_LINE_BYTES);
234   rv = clib_mem_alloc_aligned (size, CLIB_CACHE_LINE_BYTES);
235   for (uword i = 0; i < size; i++)
236     rv[i] = ((u8) i + start) & mask;
237   vec_add1 (test_main.allocated_mem, rv);
238   return rv;
239 }
240
241 void *
242 test_mem_alloc_and_splat (uword elt_size, uword n_elts, void *elt)
243 {
244   u8 *rv, *e;
245   uword data_size = elt_size * n_elts;
246   uword alloc_size = round_pow2 (data_size, CLIB_CACHE_LINE_BYTES);
247   e = rv = clib_mem_alloc_aligned (alloc_size, CLIB_CACHE_LINE_BYTES);
248   while (e - rv < data_size)
249     {
250       clib_memcpy_fast (e, elt, elt_size);
251       e += elt_size;
252     }
253
254   if (data_size < alloc_size)
255     clib_memset_u8 (e, 0, alloc_size - data_size);
256   vec_add1 (test_main.allocated_mem, rv);
257   return rv;
258 }
259