c11 safe string handling support
[vpp.git] / src / vppinfra / test_mheap.c
1 /*
2  * Copyright (c) 2015 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16   Copyright (c) 2001, 2002, 2003 Eliot Dresselhaus
17
18   Permission is hereby granted, free of charge, to any person obtaining
19   a copy of this software and associated documentation files (the
20   "Software"), to deal in the Software without restriction, including
21   without limitation the rights to use, copy, modify, merge, publish,
22   distribute, sublicense, and/or sell copies of the Software, and to
23   permit persons to whom the Software is furnished to do so, subject to
24   the following conditions:
25
26   The above copyright notice and this permission notice shall be
27   included in all copies or substantial portions of the Software.
28
29   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33   LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34   OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35   WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 */
37
38 #ifdef CLIB_LINUX_KERNEL
39 #include <linux/unistd.h>
40 #endif
41
42 #ifdef CLIB_UNIX
43 #include <unistd.h>
44 #include <stdlib.h>
45 #include <stdio.h>              /* scanf */
46 #endif
47
48 #include <vppinfra/mheap.h>
49 #include <vppinfra/format.h>
50 #include <vppinfra/random.h>
51 #include <vppinfra/time.h>
52
53 static int verbose = 0;
54 #define if_verbose(format,args...) \
55   if (verbose) { clib_warning(format, ## args); }
56
57 int
58 test1 (void)
59 {
60   clib_time_t clib_time;
61   void *h_mem = clib_mem_alloc (2ULL << 30);
62   void *h;
63   uword *objects = 0;
64   int i;
65   f64 before, after;
66
67   clib_time_init (&clib_time);
68
69   vec_validate (objects, 2000000 - 1);
70
71   h = mheap_alloc (h_mem, (uword) (2 << 30));
72
73   before = clib_time_now (&clib_time);
74
75   for (i = 0; i < vec_len (objects); i++)
76     {
77       h = mheap_get_aligned (h, 24 /* size */ ,
78                              64 /* align */ ,
79                              16 /* align at offset */ , &objects[i]);
80     }
81
82   after = clib_time_now (&clib_time);
83
84   fformat (stdout, "alloc: %u objects in %.2f seconds, %.2f objects/second\n",
85            vec_len (objects), (after - before),
86            ((f64) vec_len (objects)) / (after - before));
87
88   return 0;
89 }
90
91
92 int
93 test_mheap_main (unformat_input_t * input)
94 {
95   int i, j, k, n_iterations;
96   void *h, *h_mem;
97   uword *objects = 0;
98   u32 objects_used, really_verbose, n_objects, max_object_size;
99   u32 check_mask, seed, trace, use_vm;
100   u32 print_every = 0;
101   u32 *data;
102   mheap_t *mh;
103
104   /* Validation flags. */
105   check_mask = 0;
106 #define CHECK_VALIDITY 1
107 #define CHECK_DATA     2
108 #define CHECK_ALIGN    4
109 #define TEST1          8
110
111   n_iterations = 10;
112   seed = 0;
113   max_object_size = 100;
114   n_objects = 1000;
115   trace = 0;
116   really_verbose = 0;
117   use_vm = 0;
118
119   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
120     {
121       if (0 == unformat (input, "iter %d", &n_iterations)
122           && 0 == unformat (input, "count %d", &n_objects)
123           && 0 == unformat (input, "size %d", &max_object_size)
124           && 0 == unformat (input, "seed %d", &seed)
125           && 0 == unformat (input, "print %d", &print_every)
126           && 0 == unformat (input, "validdata %|",
127                             &check_mask, CHECK_DATA | CHECK_VALIDITY)
128           && 0 == unformat (input, "valid %|",
129                             &check_mask, CHECK_VALIDITY)
130           && 0 == unformat (input, "verbose %=", &really_verbose, 1)
131           && 0 == unformat (input, "trace %=", &trace, 1)
132           && 0 == unformat (input, "vm %=", &use_vm, 1)
133           && 0 == unformat (input, "align %|", &check_mask, CHECK_ALIGN)
134           && 0 == unformat (input, "test1 %|", &check_mask, TEST1))
135         {
136           clib_warning ("unknown input `%U'", format_unformat_error, input);
137           return 1;
138         }
139     }
140
141   /* Zero seed means use default. */
142   if (!seed)
143     seed = random_default_seed ();
144
145   if (check_mask & TEST1)
146     {
147       return test1 ();
148     }
149
150   if_verbose
151     ("testing %d iterations, %d %saligned objects, max. size %d, seed %d",
152      n_iterations, n_objects, (check_mask & CHECK_ALIGN) ? "randomly " : "un",
153      max_object_size, seed);
154
155   vec_resize (objects, n_objects);
156   if (vec_bytes (objects) > 0)  /* stupid warning be gone */
157     clib_memset (objects, ~0, vec_bytes (objects));
158   objects_used = 0;
159
160   /* Allocate initial heap. */
161   {
162     uword size =
163       max_pow2 (2 * n_objects * max_object_size * sizeof (data[0]));
164
165     h_mem = clib_mem_alloc (size);
166     if (!h_mem)
167       return 0;
168
169     h = mheap_alloc (h_mem, size);
170   }
171
172   if (trace)
173     mheap_trace (h, trace);
174
175   mh = mheap_header (h);
176
177   if (use_vm)
178     mh->flags &= ~MHEAP_FLAG_DISABLE_VM;
179   else
180     mh->flags |= MHEAP_FLAG_DISABLE_VM;
181
182   if (check_mask & CHECK_VALIDITY)
183     mh->flags |= MHEAP_FLAG_VALIDATE;
184
185   for (i = 0; i < n_iterations; i++)
186     {
187       while (1)
188         {
189           j = random_u32 (&seed) % vec_len (objects);
190           if (objects[j] != ~0 || i + objects_used < n_iterations)
191             break;
192         }
193
194       if (objects[j] != ~0)
195         {
196           mheap_put (h, objects[j]);
197           objects_used--;
198           objects[j] = ~0;
199         }
200       else
201         {
202           uword size, align, align_offset;
203
204           size = (random_u32 (&seed) % max_object_size) * sizeof (data[0]);
205           align = align_offset = 0;
206           if (check_mask & CHECK_ALIGN)
207             {
208               align = 1 << (random_u32 (&seed) % 10);
209               align_offset = round_pow2 (random_u32 (&seed) & (align - 1),
210                                          sizeof (u32));
211             }
212
213           h = mheap_get_aligned (h, size, align, align_offset, &objects[j]);
214
215           if (align > 0)
216             ASSERT (0 == ((objects[j] + align_offset) & (align - 1)));
217
218           ASSERT (objects[j] != ~0);
219           objects_used++;
220
221           /* Set newly allocated object with test data. */
222           if (check_mask & CHECK_DATA)
223             {
224               uword len;
225
226               data = (void *) h + objects[j];
227               len = mheap_len (h, data);
228
229               ASSERT (size <= mheap_data_bytes (h, objects[j]));
230
231               data[0] = len;
232               for (k = 1; k < len; k++)
233                 data[k] = objects[j] + k;
234             }
235         }
236
237       /* Verify that all used objects have correct test data. */
238       if (check_mask & 2)
239         {
240           for (j = 0; j < vec_len (objects); j++)
241             if (objects[j] != ~0)
242               {
243                 u32 *data = h + objects[j];
244                 uword len = data[0];
245                 for (k = 1; k < len; k++)
246                   ASSERT (data[k] == objects[j] + k);
247               }
248         }
249       if (print_every != 0 && i > 0 && (i % print_every) == 0)
250         fformat (stderr, "iteration %d: %U\n", i, format_mheap, h,
251                  really_verbose);
252     }
253
254   if (verbose)
255     fformat (stderr, "%U\n", format_mheap, h, really_verbose);
256   mheap_free (h);
257   clib_mem_free (h_mem);
258   vec_free (objects);
259
260   return 0;
261 }
262
263 #ifdef CLIB_UNIX
264 int
265 main (int argc, char *argv[])
266 {
267   unformat_input_t i;
268   int ret;
269
270   clib_mem_init (0, 3ULL << 30);
271
272   verbose = (argc > 1);
273   unformat_init_command_line (&i, argv);
274   ret = test_mheap_main (&i);
275   unformat_free (&i);
276
277   return ret;
278 }
279 #endif /* CLIB_UNIX */
280
281 /*
282  * fd.io coding-style-patch-verification: ON
283  *
284  * Local Variables:
285  * eval: (c-set-style "gnu")
286  * End:
287  */