blob: 19d86bb70c018a29611817d3eb9bbe001fe81818 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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) 2005,2009 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#include <vppinfra/elog.h>
39#include <vppinfra/cache.h>
40#include <vppinfra/error.h>
41#include <vppinfra/format.h>
42#include <vppinfra/hash.h>
43#include <vppinfra/math.h>
44
Dave Barachc3799992016-08-15 11:12:27 -040045static inline void
46elog_lock (elog_main_t * em)
Ed Warnickecb9cada2015-12-08 15:45:58 -070047{
Dave Barachc3799992016-08-15 11:12:27 -040048 if (PREDICT_FALSE (em->lock != 0))
Sirshak Das2f6d7bb2018-10-03 22:53:51 +000049 while (clib_atomic_test_and_set (em->lock))
Dave Barachc3799992016-08-15 11:12:27 -040050 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -070051}
52
Dave Barachc3799992016-08-15 11:12:27 -040053static inline void
54elog_unlock (elog_main_t * em)
Ed Warnickecb9cada2015-12-08 15:45:58 -070055{
Dave Barachc3799992016-08-15 11:12:27 -040056 if (PREDICT_FALSE (em->lock != 0))
Dave Barachfb6e59d2016-03-26 18:45:42 -040057 {
Dave Barachc3799992016-08-15 11:12:27 -040058 CLIB_MEMORY_BARRIER ();
Dave Barachfb6e59d2016-03-26 18:45:42 -040059 *em->lock = 0;
60 }
Ed Warnickecb9cada2015-12-08 15:45:58 -070061}
62
63/* Non-inline version. */
64void *
65elog_event_data (elog_main_t * em,
Dave Barachc3799992016-08-15 11:12:27 -040066 elog_event_type_t * type, elog_track_t * track, u64 cpu_time)
Ed Warnickecb9cada2015-12-08 15:45:58 -070067{
Dave Barachc3799992016-08-15 11:12:27 -040068 return elog_event_data_inline (em, type, track, cpu_time);
69}
Ed Warnickecb9cada2015-12-08 15:45:58 -070070
Dave Barachc3799992016-08-15 11:12:27 -040071static void
72new_event_type (elog_main_t * em, uword i)
73{
74 elog_event_type_t *t = vec_elt_at_index (em->event_types, i);
75
76 if (!em->event_type_by_format)
77 em->event_type_by_format =
78 hash_create_vec ( /* size */ 0, sizeof (u8), sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -070079
Dave Barach903fd512017-04-01 11:07:40 -040080 t->type_index_plus_one = i + 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -070081 hash_set_mem (em->event_type_by_format, t->format, i);
82}
83
84static uword
85find_or_create_type (elog_main_t * em, elog_event_type_t * t)
86{
Dave Barachc3799992016-08-15 11:12:27 -040087 uword *p = hash_get_mem (em->event_type_by_format, t->format);
Ed Warnickecb9cada2015-12-08 15:45:58 -070088 uword i;
89
90 if (p)
91 i = p[0];
92 else
93 {
94 i = vec_len (em->event_types);
95 vec_add1 (em->event_types, t[0]);
96 new_event_type (em, i);
97 }
98
99 return i;
100}
101
102/* External function to register types. */
Dave Barachc3799992016-08-15 11:12:27 -0400103word
104elog_event_type_register (elog_main_t * em, elog_event_type_t * t)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700105{
Dave Barachc3799992016-08-15 11:12:27 -0400106 elog_event_type_t *static_type = t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700107 word l;
108
109 elog_lock (em);
110
Dave Barach12c6fdc2017-06-30 08:46:24 -0400111 /* Multiple simultaneous registration attempts, */
112 if (t->type_index_plus_one > 0)
113 {
114 elog_unlock (em);
115 return t->type_index_plus_one - 1;
116 }
117
Ed Warnickecb9cada2015-12-08 15:45:58 -0700118 l = vec_len (em->event_types);
119
120 t->type_index_plus_one = 1 + l;
121
122 ASSERT (t->format);
123
124 /* If format args are not specified try to be smart about providing defaults
125 so most of the time user does not have to specify them. */
Dave Barachc3799992016-08-15 11:12:27 -0400126 if (!t->format_args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700127 {
128 uword i, l;
Dave Barachc3799992016-08-15 11:12:27 -0400129 char *this_arg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700130
131 l = strlen (t->format);
132 for (i = 0; i < l; i++)
133 {
134 if (t->format[i] != '%')
135 continue;
136 if (i + 1 >= l)
137 continue;
Dave Barachc3799992016-08-15 11:12:27 -0400138 if (t->format[i + 1] == '%') /* %% */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700139 continue;
140
Dave Barachc3799992016-08-15 11:12:27 -0400141 switch (t->format[i + 1])
142 {
143 default:
144 case 'd':
145 case 'x':
146 case 'u':
147 this_arg = "i4"; /* size of u32 */
148 break;
149 case 'f':
150 this_arg = "f8"; /* defaults to f64 */
151 break;
152 case 's':
153 this_arg = "s0"; /* defaults to null terminated string. */
154 break;
155 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700156
Dave Barachc3799992016-08-15 11:12:27 -0400157 t->format_args =
158 (char *) format ((u8 *) t->format_args, "%s", this_arg);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700159 }
160
161 /* Null terminate. */
162 vec_add1 (t->format_args, 0);
Dave Barachc3799992016-08-15 11:12:27 -0400163 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700164
165 vec_add1 (em->event_types, t[0]);
166
167 t = em->event_types + l;
168
169 /* Make copies of strings for hashing etc. */
170 if (t->function)
171 t->format = (char *) format (0, "%s %s%c", t->function, t->format, 0);
172 else
173 t->format = (char *) format (0, "%s%c", t->format, 0);
174
175 t->format_args = (char *) format (0, "%s%c", t->format_args, 0);
176
177 /* Construct string table. */
178 {
179 uword i;
180 t->n_enum_strings = static_type->n_enum_strings;
181 for (i = 0; i < t->n_enum_strings; i++)
182 {
Dave Barachc3799992016-08-15 11:12:27 -0400183 if (!static_type->enum_strings[i])
Ed Warnickecb9cada2015-12-08 15:45:58 -0700184 static_type->enum_strings[i] = "MISSING";
Dave Barachc3799992016-08-15 11:12:27 -0400185 vec_add1 (t->enum_strings_vector,
186 (char *) format (0, "%s%c", static_type->enum_strings[i],
187 0));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700188 }
189 }
190
191 new_event_type (em, l);
Dave Barachc3799992016-08-15 11:12:27 -0400192 elog_unlock (em);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700193
194 return l;
195}
196
Dave Barachc3799992016-08-15 11:12:27 -0400197word
198elog_track_register (elog_main_t * em, elog_track_t * t)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700199{
200 word l;
201
202 elog_lock (em);
203
204 l = vec_len (em->tracks);
205
206 t->track_index_plus_one = 1 + l;
207
208 ASSERT (t->name);
209
210 vec_add1 (em->tracks, t[0]);
211
212 t = em->tracks + l;
213
214 t->name = (char *) format (0, "%s%c", t->name, 0);
215
216 elog_unlock (em);
217
218 return l;
219}
220
Dave Barachc3799992016-08-15 11:12:27 -0400221static uword
222parse_2digit_decimal (char *p, uword * number)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700223{
224 uword i = 0;
225 u8 digits[2];
226
227 digits[0] = digits[1] = 0;
228 while (p[i] >= '0' && p[i] <= '9')
229 {
230 if (i >= 2)
231 break;
232 digits[i] = p[i] - '0';
233 i++;
234 }
235
236 if (i >= 1 && i <= 2)
237 {
238 if (i == 1)
239 *number = digits[0];
240 else
241 *number = 10 * digits[0] + digits[1];
242 return i;
243 }
244 else
245 return 0;
246}
247
Dave Barachc3799992016-08-15 11:12:27 -0400248static u8 *
249fixed_format (u8 * s, char *fmt, char *result, uword * result_len)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700250{
Dave Barachc3799992016-08-15 11:12:27 -0400251 char *f = fmt;
252 char *percent;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700253 uword l = 0;
254
255 while (1)
256 {
257 if (f[0] == 0)
258 break;
259 if (f[0] == '%' && f[1] != '%')
260 break;
261 f++;
262 }
263 if (f > fmt)
264 vec_add (s, fmt, f - fmt);
265
266 if (f[0] != '%')
267 goto done;
268
269 /* Skip percent. */
270 percent = f++;
271
272 /* Skip possible +-= justification. */
273 f += f[0] == '+' || f[0] == '-' || f[0] == '=';
274
275 /* Skip possible X.Y width. */
276 while ((f[0] >= '0' && f[0] <= '9') || f[0] == '.')
277 f++;
278
279 /* Skip wlL as in e.g. %Ld. */
280 f += f[0] == 'w' || f[0] == 'l' || f[0] == 'L';
281
282 /* Finally skip format letter. */
283 f += f[0] != 0;
284
285 ASSERT (*result_len > f - percent);
286 l = clib_min (f - percent, *result_len - 1);
Damjan Marionf1213b82016-03-13 02:22:06 +0100287 clib_memcpy (result, percent, l);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700288 result[l] = 0;
289
Dave Barachc3799992016-08-15 11:12:27 -0400290done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700291 *result_len = f - fmt;
292 return s;
293}
294
Dave Barachc3799992016-08-15 11:12:27 -0400295u8 *
296format_elog_event (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700297{
Dave Barachc3799992016-08-15 11:12:27 -0400298 elog_main_t *em = va_arg (*va, elog_main_t *);
299 elog_event_t *e = va_arg (*va, elog_event_t *);
300 elog_event_type_t *t;
301 char *a, *f;
302 void *d = (u8 *) e->data;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700303 char arg_format[64];
304
305 t = vec_elt_at_index (em->event_types, e->type);
306
307 f = t->format;
308 a = t->format_args;
309 while (1)
310 {
311 uword n_bytes = 0, n_digits, f_bytes = 0;
312
313 f_bytes = sizeof (arg_format);
314 s = fixed_format (s, f, arg_format, &f_bytes);
315 f += f_bytes;
316
317 if (a == 0 || a[0] == 0)
318 {
319 /* Format must also be at end. */
320 ASSERT (f[0] == 0);
321 break;
322 }
323
324 /* Don't go past end of event data. */
325 ASSERT (d < (void *) (e->data + sizeof (e->data)));
326
327 n_digits = parse_2digit_decimal (a + 1, &n_bytes);
328 switch (a[0])
329 {
330 case 'i':
331 case 't':
332 case 'T':
333 {
334 u32 i = 0;
335 u64 l = 0;
336
337 if (n_bytes == 1)
338 i = ((u8 *) d)[0];
339 else if (n_bytes == 2)
340 i = clib_mem_unaligned (d, u16);
341 else if (n_bytes == 4)
342 i = clib_mem_unaligned (d, u32);
343 else if (n_bytes == 8)
344 l = clib_mem_unaligned (d, u64);
345 else
346 ASSERT (0);
347 if (a[0] == 't')
348 {
Dave Barachc3799992016-08-15 11:12:27 -0400349 char *e =
350 vec_elt (t->enum_strings_vector, n_bytes == 8 ? l : i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700351 s = format (s, arg_format, e);
352 }
353 else if (a[0] == 'T')
354 {
Dave Barachc3799992016-08-15 11:12:27 -0400355 char *e =
356 vec_elt_at_index (em->string_table, n_bytes == 8 ? l : i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700357 s = format (s, arg_format, e);
358 }
359 else if (n_bytes == 8)
360 s = format (s, arg_format, l);
361 else
362 s = format (s, arg_format, i);
363 }
364 break;
365
366 case 'f':
367 {
368 f64 x = 0;
369 if (n_bytes == 4)
370 x = clib_mem_unaligned (d, f32);
371 else if (n_bytes == 8)
372 x = clib_mem_unaligned (d, f64);
373 else
374 ASSERT (0);
375 s = format (s, arg_format, x);
376 }
377 break;
378
379 case 's':
380 s = format (s, arg_format, d);
381 if (n_bytes == 0)
382 n_bytes = strlen (d) + 1;
383 break;
384
385 default:
386 ASSERT (0);
387 break;
388 }
389
390 ASSERT (n_digits > 0 && n_digits <= 2);
391 a += 1 + n_digits;
392 d += n_bytes;
393 }
394
395 return s;
396}
397
Dave Barachc3799992016-08-15 11:12:27 -0400398u8 *
Florin Corasaefbede2018-12-19 13:07:49 -0800399format_elog_track_name (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700400{
Dave Barachc3799992016-08-15 11:12:27 -0400401 elog_main_t *em = va_arg (*va, elog_main_t *);
402 elog_event_t *e = va_arg (*va, elog_event_t *);
403 elog_track_t *t = vec_elt_at_index (em->tracks, e->track);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700404 return format (s, "%s", t->name);
405}
406
Florin Corasaefbede2018-12-19 13:07:49 -0800407u8 *
408format_elog_track (u8 * s, va_list * args)
409{
410 elog_main_t *em = va_arg (*args, elog_main_t *);
411 f64 dt = va_arg (*args, f64);
412 int track_index = va_arg (*args, int);
413 elog_event_t *e, *es;
414 u8 indent;
415
416 indent = format_get_indent (s) + 1;
417
418 es = elog_peek_events (em);
419 vec_foreach (e, es)
420 {
421 if (e->track != track_index)
422 continue;
423 s = format (s, "%U%18.9f: %U\n", format_white_space, indent, e->time + dt,
424 format_elog_event, em, e);
425 }
426 vec_free (es);
427 return s;
428}
429
Dave Barachc3799992016-08-15 11:12:27 -0400430void
431elog_time_now (elog_time_stamp_t * et)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700432{
433 u64 cpu_time_now, os_time_now_nsec;
Dave Barach903fd512017-04-01 11:07:40 -0400434 struct timespec ts;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700435
436#ifdef CLIB_UNIX
437 {
438#include <sys/syscall.h>
Damjan Marion4dffd1c2018-09-03 12:30:36 +0200439#ifdef __APPLE__
440 clock_gettime (CLOCK_REALTIME, &ts);
441#else
Ed Warnickecb9cada2015-12-08 15:45:58 -0700442 syscall (SYS_clock_gettime, CLOCK_REALTIME, &ts);
Damjan Marion4dffd1c2018-09-03 12:30:36 +0200443#endif
Ed Warnickecb9cada2015-12-08 15:45:58 -0700444 cpu_time_now = clib_cpu_time_now ();
Dave Barach903fd512017-04-01 11:07:40 -0400445 /* Subtract 3/30/2017's worth of seconds to retain precision */
446 os_time_now_nsec = 1e9 * (ts.tv_sec - 1490885108) + ts.tv_nsec;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700447 }
448#else
449 cpu_time_now = clib_cpu_time_now ();
450 os_time_now_nsec = 0;
451#endif
452
453 et->cpu = cpu_time_now;
454 et->os_nsec = os_time_now_nsec;
455}
456
457always_inline i64
Dave Barachc3799992016-08-15 11:12:27 -0400458elog_time_stamp_diff_os_nsec (elog_time_stamp_t * t1, elog_time_stamp_t * t2)
459{
460 return (i64) t1->os_nsec - (i64) t2->os_nsec;
461}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700462
463always_inline i64
Dave Barachc3799992016-08-15 11:12:27 -0400464elog_time_stamp_diff_cpu (elog_time_stamp_t * t1, elog_time_stamp_t * t2)
465{
466 return (i64) t1->cpu - (i64) t2->cpu;
467}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700468
469always_inline f64
470elog_nsec_per_clock (elog_main_t * em)
471{
472 return ((f64) elog_time_stamp_diff_os_nsec (&em->serialize_time,
473 &em->init_time)
474 / (f64) elog_time_stamp_diff_cpu (&em->serialize_time,
475 &em->init_time));
476}
477
Dave Barachc3799992016-08-15 11:12:27 -0400478void
479elog_alloc (elog_main_t * em, u32 n_events)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700480{
481 if (em->event_ring)
482 vec_free (em->event_ring);
Dave Barachc3799992016-08-15 11:12:27 -0400483
Ed Warnickecb9cada2015-12-08 15:45:58 -0700484 /* Ring size must be a power of 2. */
485 em->event_ring_size = n_events = max_pow2 (n_events);
486
487 /* Leave an empty ievent at end so we can always speculatively write
488 and event there (possibly a long form event). */
489 vec_resize_aligned (em->event_ring, n_events, CLIB_CACHE_LINE_BYTES);
490}
491
Dave Barachc3799992016-08-15 11:12:27 -0400492void
493elog_init (elog_main_t * em, u32 n_events)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700494{
Dave Barachb7b92992018-10-17 10:38:51 -0400495 clib_memset (em, 0, sizeof (em[0]));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700496
497 em->lock = 0;
498
499 if (n_events > 0)
500 elog_alloc (em, n_events);
501
502 clib_time_init (&em->cpu_timer);
503
504 em->n_total_events_disable_limit = ~0;
505
506 /* Make track 0. */
507 em->default_track.name = "default";
508 elog_track_register (em, &em->default_track);
509
510 elog_time_now (&em->init_time);
Dave Barach9c8ca8d2019-06-14 12:02:38 -0400511 em->string_table_hash = hash_create_string (0, sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700512}
513
514/* Returns number of events in ring and start index. */
Dave Barachc3799992016-08-15 11:12:27 -0400515static uword
516elog_event_range (elog_main_t * em, uword * lo)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700517{
518 uword l = em->event_ring_size;
519 u64 i = em->n_total_events;
520
521 /* Ring never wrapped? */
522 if (i <= (u64) l)
523 {
Dave Barachc3799992016-08-15 11:12:27 -0400524 if (lo)
525 *lo = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700526 return i;
527 }
528 else
529 {
Dave Barachc3799992016-08-15 11:12:27 -0400530 if (lo)
531 *lo = i & (l - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700532 return l;
533 }
534}
535
Dave Barachc3799992016-08-15 11:12:27 -0400536elog_event_t *
537elog_peek_events (elog_main_t * em)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700538{
Dave Barachc3799992016-08-15 11:12:27 -0400539 elog_event_t *e, *f, *es = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700540 uword i, j, n;
541
542 n = elog_event_range (em, &j);
543 for (i = 0; i < n; i++)
544 {
545 vec_add2 (es, e, 1);
546 f = vec_elt_at_index (em->event_ring, j);
547 e[0] = f[0];
548
549 /* Convert absolute time from cycles to seconds from start. */
Dave Barachc3799992016-08-15 11:12:27 -0400550 e->time =
551 (e->time_cycles -
552 em->init_time.cpu) * em->cpu_timer.seconds_per_clock;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700553
554 j = (j + 1) & (em->event_ring_size - 1);
555 }
556
557 return es;
558}
559
560/* Add a formatted string to the string table. */
Dave Barachc3799992016-08-15 11:12:27 -0400561u32
562elog_string (elog_main_t * em, char *fmt, ...)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700563{
564 u32 offset;
Dave Barach9c8ca8d2019-06-14 12:02:38 -0400565 uword *p;
566 uword len;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700567 va_list va;
568
Steven Luongd31a5982019-05-31 07:34:39 -0700569 elog_lock (em);
Dave Barach9c8ca8d2019-06-14 12:02:38 -0400570 vec_reset_length (em->string_table_tmp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700571 va_start (va, fmt);
Dave Barach9c8ca8d2019-06-14 12:02:38 -0400572 em->string_table_tmp = va_format (em->string_table_tmp, fmt, &va);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700573 va_end (va);
574
Dave Barach9c8ca8d2019-06-14 12:02:38 -0400575 /* See if we already have this string in the string table */
576 p = hash_get_mem (em->string_table_hash, em->string_table_tmp);
577
578 /* We already have the string, so give the caller its offset */
579 if (p)
580 {
581 elog_unlock (em);
582 return (p[0]);
583 }
584
585 /* We don't, so add it. String table entries MUST be NULL terminated */
586 len = vec_len (em->string_table_tmp);
587 ASSERT (len > 0);
588 if (em->string_table_tmp[len - 1] != 0)
589 vec_add1 (em->string_table_tmp, 0);
590
591 offset = vec_len (em->string_table);
592 vec_append (em->string_table, em->string_table_tmp);
593
594 hash_set_mem (em->string_table_hash, em->string_table_tmp, offset);
595
596 /* We gave the key to the string table hash, so we can't reuse it! */
597 em->string_table_tmp = 0;
Steven Luongd31a5982019-05-31 07:34:39 -0700598 elog_unlock (em);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700599
600 return offset;
601}
602
Dave Barachc3799992016-08-15 11:12:27 -0400603elog_event_t *
604elog_get_events (elog_main_t * em)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700605{
Dave Barachc3799992016-08-15 11:12:27 -0400606 if (!em->events)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700607 em->events = elog_peek_events (em);
608 return em->events;
609}
610
Dave Barachc3799992016-08-15 11:12:27 -0400611static void
612maybe_fix_string_table_offset (elog_event_t * e,
613 elog_event_type_t * t, u32 offset)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700614{
Dave Barachc3799992016-08-15 11:12:27 -0400615 void *d = (u8 *) e->data;
616 char *a;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700617
618 if (offset == 0)
619 return;
620
621 a = t->format_args;
622
623 while (1)
624 {
625 uword n_bytes = 0, n_digits;
626
627 if (a[0] == 0)
Dave Barachc3799992016-08-15 11:12:27 -0400628 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700629
630 /* Don't go past end of event data. */
631 ASSERT (d < (void *) (e->data + sizeof (e->data)));
632
633 n_digits = parse_2digit_decimal (a + 1, &n_bytes);
634 switch (a[0])
635 {
636 case 'T':
Dave Barachc3799992016-08-15 11:12:27 -0400637 ASSERT (n_bytes == 4);
638 clib_mem_unaligned (d, u32) += offset;
639 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700640
641 case 'i':
642 case 't':
643 case 'f':
644 case 's':
645 break;
646
647 default:
648 ASSERT (0);
649 break;
650 }
651
652 ASSERT (n_digits > 0 && n_digits <= 2);
653 a += 1 + n_digits;
654 d += n_bytes;
655 }
656}
657
Dave Barachc3799992016-08-15 11:12:27 -0400658static int
659elog_cmp (void *a1, void *a2)
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500660{
Dave Barachc3799992016-08-15 11:12:27 -0400661 elog_event_t *e1 = a1;
662 elog_event_t *e2 = a2;
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500663
Dave Barach903fd512017-04-01 11:07:40 -0400664 if (e1->time < e2->time)
665 return -1;
666
667 if (e1->time > e2->time)
668 return 1;
669
670 return 0;
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500671}
672
Dave Barach903fd512017-04-01 11:07:40 -0400673/*
674 * merge two event logs. Complicated and cranky.
675 */
Dave Barachc3799992016-08-15 11:12:27 -0400676void
Dave Barach903fd512017-04-01 11:07:40 -0400677elog_merge (elog_main_t * dst, u8 * dst_tag, elog_main_t * src, u8 * src_tag,
678 f64 align_tweak)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700679{
Dave Barachc3799992016-08-15 11:12:27 -0400680 elog_event_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700681 uword l;
682 u32 string_table_offset_for_src_events;
683 u32 track_offset_for_src_tracks;
684 elog_track_t newt;
685 int i;
686
Dave Barachb7b92992018-10-17 10:38:51 -0400687 clib_memset (&newt, 0, sizeof (newt));
Dave Barachf9c231e2016-08-05 10:10:18 -0400688
Dave Barach903fd512017-04-01 11:07:40 -0400689 /* Acquire src and dst events */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700690 elog_get_events (src);
691 elog_get_events (dst);
692
693 string_table_offset_for_src_events = vec_len (dst->string_table);
694 vec_append (dst->string_table, src->string_table);
695
696 l = vec_len (dst->events);
Dave Barach903fd512017-04-01 11:07:40 -0400697 vec_append (dst->events, src->events);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700698
699 /* Prepend the supplied tag (if any) to all dst track names */
700 if (dst_tag)
701 {
Dave Barachc3799992016-08-15 11:12:27 -0400702 for (i = 0; i < vec_len (dst->tracks); i++)
703 {
704 elog_track_t *t = vec_elt_at_index (dst->tracks, i);
705 char *new_name;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700706
Dave Barachc3799992016-08-15 11:12:27 -0400707 new_name = (char *) format (0, "%s:%s%c", dst_tag, t->name, 0);
708 vec_free (t->name);
709 t->name = new_name;
710 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700711 }
Dave Barachc3799992016-08-15 11:12:27 -0400712
Dave Barach903fd512017-04-01 11:07:40 -0400713 /*
714 * Remember where we started allocating new tracks while merging
715 */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700716 track_offset_for_src_tracks = vec_len (dst->tracks);
Dave Barachc3799992016-08-15 11:12:27 -0400717
Ed Warnickecb9cada2015-12-08 15:45:58 -0700718 /* Copy / tag source tracks */
719 for (i = 0; i < vec_len (src->tracks); i++)
720 {
Dave Barachc3799992016-08-15 11:12:27 -0400721 elog_track_t *t = vec_elt_at_index (src->tracks, i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700722 if (src_tag)
Dave Barachc3799992016-08-15 11:12:27 -0400723 newt.name = (char *) format (0, "%s:%s%c", src_tag, t->name, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700724 else
Dave Barachc3799992016-08-15 11:12:27 -0400725 newt.name = (char *) format (0, "%s%c", t->name, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700726 (void) elog_track_register (dst, &newt);
727 vec_free (newt.name);
728 }
Dave Barachc3799992016-08-15 11:12:27 -0400729
Ed Warnickecb9cada2015-12-08 15:45:58 -0700730 /* Across all (copied) src events... */
731 for (e = dst->events + l; e < vec_end (dst->events); e++)
732 {
Dave Barachc3799992016-08-15 11:12:27 -0400733 elog_event_type_t *t = vec_elt_at_index (src->event_types, e->type);
734
Ed Warnickecb9cada2015-12-08 15:45:58 -0700735 /* Remap type from src -> dst. */
736 e->type = find_or_create_type (dst, t);
737
738 /* Remap string table offsets for 'T' format args */
Dave Barachc3799992016-08-15 11:12:27 -0400739 maybe_fix_string_table_offset (e, t,
740 string_table_offset_for_src_events);
741
Ed Warnickecb9cada2015-12-08 15:45:58 -0700742 /* Remap track */
743 e->track += track_offset_for_src_tracks;
744 }
745
746 /* Adjust event times for relative starting times of event streams. */
747 {
748 f64 dt_event, dt_os_nsec, dt_clock_nsec;
749
750 /* Set clock parameters if dst was not generated by unserialize. */
751 if (dst->serialize_time.cpu == 0)
752 {
753 dst->init_time = src->init_time;
754 dst->serialize_time = src->serialize_time;
755 dst->nsec_per_cpu_clock = src->nsec_per_cpu_clock;
756 }
757
Dave Barachc3799992016-08-15 11:12:27 -0400758 dt_os_nsec =
759 elog_time_stamp_diff_os_nsec (&src->init_time, &dst->init_time);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700760
761 dt_event = dt_os_nsec;
Dave Barachc3799992016-08-15 11:12:27 -0400762 dt_clock_nsec =
763 (elog_time_stamp_diff_cpu (&src->init_time, &dst->init_time) * .5 *
764 (dst->nsec_per_cpu_clock + src->nsec_per_cpu_clock));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700765
Dave Barach903fd512017-04-01 11:07:40 -0400766 /*
767 * Heuristic to see if src/dst came from same time source.
768 * If frequencies are "the same" and os clock and cpu clock agree
769 * to within 100e-9 secs about time difference between src/dst
770 * init_time, then we use cpu clock. Otherwise we use OS clock.
771 *
772 * When merging event logs from different systems, time paradoxes
773 * at the O(1ms) level are to be expected. Hence, the "align_tweak"
774 * parameter. If two events logged on different processors are known
775 * to occur in a specific order - and with a reasonably-estimated
776 * interval - supply a non-zero "align_tweak" parameter
777 */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700778 if (fabs (src->nsec_per_cpu_clock - dst->nsec_per_cpu_clock) < 1e-2
779 && fabs (dt_os_nsec - dt_clock_nsec) < 100)
780 dt_event = dt_clock_nsec;
781
782 /* Convert to seconds. */
783 dt_event *= 1e-9;
784
Dave Barach903fd512017-04-01 11:07:40 -0400785 /*
786 * Move the earlier set of events later, to avoid creating
Paul Vinciguerraec11b132018-09-24 05:25:00 -0700787 * events which precede the Big Bang (aka have negative timestamps).
Dave Barach903fd512017-04-01 11:07:40 -0400788 *
789 * Not to any scale, we have something like the following picture:
790 *
791 * DST capture start point
792 * ^
793 * +--- dt_event --+
794 * v
795 * SRC capture start point
796 *
797 * In this case dt_event is positive, src started after dst,
798 * to put src events onto a common timebase we have to move them
799 * forward in time. Naturally, the opposite case is
800 * possible, too: dt_event will be negative, and so we have to
801 * move dst events forward in time by the |dt_event|.
802 * In both cases, we add align_tweak.
803 */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700804 if (dt_event > 0)
805 {
806 /* Src started after dst. */
807 for (e = dst->events + l; e < vec_end (dst->events); e++)
Dave Barach903fd512017-04-01 11:07:40 -0400808 e->time += dt_event + align_tweak;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700809 }
810 else
811 {
812 /* Dst started after src. */
Dave Barach903fd512017-04-01 11:07:40 -0400813 dt_event = -dt_event;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700814 for (e = dst->events + 0; e < dst->events + l; e++)
Dave Barach903fd512017-04-01 11:07:40 -0400815 e->time += dt_event + align_tweak;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700816 }
817 }
818
819 /* Sort events by increasing time. */
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500820 vec_sort_with_function (dst->events, elog_cmp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700821
Dave Barach903fd512017-04-01 11:07:40 -0400822 dst->n_total_events = vec_len (dst->events);
823
Ed Warnickecb9cada2015-12-08 15:45:58 -0700824 /* Recreate the event ring or the results won't serialize */
825 {
826 int i;
827
828 ASSERT (dst->cpu_timer.seconds_per_clock);
829
830 elog_alloc (dst, vec_len (dst->events));
Dave Barachc3799992016-08-15 11:12:27 -0400831 for (i = 0; i < vec_len (dst->events); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700832 {
Dave Barachc3799992016-08-15 11:12:27 -0400833 elog_event_t *es, *ed;
834
835 es = dst->events + i;
836 ed = dst->event_ring + i;
837
838 ed[0] = es[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700839 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700840 }
841}
842
843static void
844serialize_elog_event (serialize_main_t * m, va_list * va)
845{
Dave Barachc3799992016-08-15 11:12:27 -0400846 elog_main_t *em = va_arg (*va, elog_main_t *);
847 elog_event_t *e = va_arg (*va, elog_event_t *);
848 elog_event_type_t *t = vec_elt_at_index (em->event_types, e->type);
849 u8 *d = e->data;
850 u8 *p = (u8 *) t->format_args;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700851
852 serialize_integer (m, e->type, sizeof (e->type));
853 serialize_integer (m, e->track, sizeof (e->track));
854 serialize (m, serialize_f64, e->time);
855
856 while (*p)
857 {
858 uword n_digits, n_bytes = 0;
859
860 n_digits = parse_2digit_decimal ((char *) p + 1, &n_bytes);
861
862 switch (p[0])
863 {
864 case 'i':
865 case 't':
866 case 'T':
867 if (n_bytes == 1)
868 serialize_integer (m, d[0], sizeof (u8));
869 else if (n_bytes == 2)
870 serialize_integer (m, clib_mem_unaligned (d, u16), sizeof (u16));
871 else if (n_bytes == 4)
872 serialize_integer (m, clib_mem_unaligned (d, u32), sizeof (u32));
873 else if (n_bytes == 8)
874 serialize (m, serialize_64, clib_mem_unaligned (d, u64));
875 else
876 ASSERT (0);
877 break;
878
879 case 's':
880 serialize_cstring (m, (char *) d);
881 if (n_bytes == 0)
882 n_bytes = strlen ((char *) d) + 1;
883 break;
884
885 case 'f':
886 if (n_bytes == 4)
887 serialize (m, serialize_f32, clib_mem_unaligned (d, f32));
888 else if (n_bytes == 8)
889 serialize (m, serialize_f64, clib_mem_unaligned (d, f64));
890 else
891 ASSERT (0);
892 break;
893
894 default:
895 ASSERT (0);
896 break;
897 }
898
899 p += 1 + n_digits;
900 d += n_bytes;
901 }
902}
903
904static void
905unserialize_elog_event (serialize_main_t * m, va_list * va)
906{
Dave Barachc3799992016-08-15 11:12:27 -0400907 elog_main_t *em = va_arg (*va, elog_main_t *);
908 elog_event_t *e = va_arg (*va, elog_event_t *);
909 elog_event_type_t *t;
910 u8 *p, *d;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700911
912 {
913 u16 tmp[2];
914
915 unserialize_integer (m, &tmp[0], sizeof (e->type));
916 unserialize_integer (m, &tmp[1], sizeof (e->track));
917
918 e->type = tmp[0];
919 e->track = tmp[1];
920
921 /* Make sure it fits. */
922 ASSERT (e->type == tmp[0]);
923 ASSERT (e->track == tmp[1]);
924 }
925
926 t = vec_elt_at_index (em->event_types, e->type);
927
928 unserialize (m, unserialize_f64, &e->time);
929
930 d = e->data;
931 p = (u8 *) t->format_args;
932
933 while (p && *p)
934 {
935 uword n_digits, n_bytes = 0;
936 u32 tmp;
937
938 n_digits = parse_2digit_decimal ((char *) p + 1, &n_bytes);
939
940 switch (p[0])
941 {
942 case 'i':
943 case 't':
944 case 'T':
945 if (n_bytes == 1)
946 {
947 unserialize_integer (m, &tmp, sizeof (u8));
948 d[0] = tmp;
949 }
950 else if (n_bytes == 2)
951 {
952 unserialize_integer (m, &tmp, sizeof (u16));
953 clib_mem_unaligned (d, u16) = tmp;
954 }
955 else if (n_bytes == 4)
956 {
957 unserialize_integer (m, &tmp, sizeof (u32));
958 clib_mem_unaligned (d, u32) = tmp;
959 }
960 else if (n_bytes == 8)
961 {
962 u64 x;
963 unserialize (m, unserialize_64, &x);
964 clib_mem_unaligned (d, u64) = x;
965 }
966 else
967 ASSERT (0);
968 break;
969
Dave Barachc3799992016-08-15 11:12:27 -0400970 case 's':
971 {
972 char *t;
973 unserialize_cstring (m, &t);
974 if (n_bytes == 0)
975 n_bytes = strlen (t) + 1;
976 clib_memcpy (d, t, clib_min (n_bytes, vec_len (t)));
977 vec_free (t);
978 break;
979 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700980
981 case 'f':
982 if (n_bytes == 4)
983 {
984 f32 x;
985 unserialize (m, unserialize_f32, &x);
986 clib_mem_unaligned (d, f32) = x;
987 }
988 else if (n_bytes == 8)
989 {
990 f64 x;
991 unserialize (m, unserialize_f64, &x);
992 clib_mem_unaligned (d, f64) = x;
993 }
994 else
995 ASSERT (0);
996 break;
997
998 default:
999 ASSERT (0);
1000 break;
1001 }
1002
1003 p += 1 + n_digits;
1004 d += n_bytes;
1005 }
1006}
1007
1008static void
1009serialize_elog_event_type (serialize_main_t * m, va_list * va)
1010{
Dave Barachc3799992016-08-15 11:12:27 -04001011 elog_event_type_t *t = va_arg (*va, elog_event_type_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001012 int n = va_arg (*va, int);
1013 int i, j;
1014 for (i = 0; i < n; i++)
1015 {
1016 serialize_cstring (m, t[i].format);
1017 serialize_cstring (m, t[i].format_args);
Dave Barachc3799992016-08-15 11:12:27 -04001018 serialize_integer (m, t[i].type_index_plus_one,
1019 sizeof (t->type_index_plus_one));
1020 serialize_integer (m, t[i].n_enum_strings,
1021 sizeof (t[i].n_enum_strings));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001022 for (j = 0; j < t[i].n_enum_strings; j++)
1023 serialize_cstring (m, t[i].enum_strings_vector[j]);
1024 }
1025}
1026
1027static void
1028unserialize_elog_event_type (serialize_main_t * m, va_list * va)
1029{
Dave Barachc3799992016-08-15 11:12:27 -04001030 elog_event_type_t *t = va_arg (*va, elog_event_type_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001031 int n = va_arg (*va, int);
1032 int i, j;
1033 for (i = 0; i < n; i++)
1034 {
1035 unserialize_cstring (m, &t[i].format);
1036 unserialize_cstring (m, &t[i].format_args);
Dave Barachc3799992016-08-15 11:12:27 -04001037 unserialize_integer (m, &t[i].type_index_plus_one,
1038 sizeof (t->type_index_plus_one));
1039 unserialize_integer (m, &t[i].n_enum_strings,
1040 sizeof (t[i].n_enum_strings));
Ed Warnickecb9cada2015-12-08 15:45:58 -07001041 vec_resize (t[i].enum_strings_vector, t[i].n_enum_strings);
1042 for (j = 0; j < t[i].n_enum_strings; j++)
1043 unserialize_cstring (m, &t[i].enum_strings_vector[j]);
1044 }
1045}
1046
1047static void
1048serialize_elog_track (serialize_main_t * m, va_list * va)
1049{
Dave Barachc3799992016-08-15 11:12:27 -04001050 elog_track_t *t = va_arg (*va, elog_track_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001051 int n = va_arg (*va, int);
1052 int i;
1053 for (i = 0; i < n; i++)
1054 {
1055 serialize_cstring (m, t[i].name);
1056 }
1057}
1058
1059static void
1060unserialize_elog_track (serialize_main_t * m, va_list * va)
1061{
Dave Barachc3799992016-08-15 11:12:27 -04001062 elog_track_t *t = va_arg (*va, elog_track_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001063 int n = va_arg (*va, int);
1064 int i;
1065 for (i = 0; i < n; i++)
1066 {
1067 unserialize_cstring (m, &t[i].name);
1068 }
1069}
1070
1071static void
1072serialize_elog_time_stamp (serialize_main_t * m, va_list * va)
1073{
Dave Barachc3799992016-08-15 11:12:27 -04001074 elog_time_stamp_t *st = va_arg (*va, elog_time_stamp_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001075 serialize (m, serialize_64, st->os_nsec);
1076 serialize (m, serialize_64, st->cpu);
1077}
1078
1079static void
1080unserialize_elog_time_stamp (serialize_main_t * m, va_list * va)
1081{
Dave Barachc3799992016-08-15 11:12:27 -04001082 elog_time_stamp_t *st = va_arg (*va, elog_time_stamp_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001083 unserialize (m, unserialize_64, &st->os_nsec);
1084 unserialize (m, unserialize_64, &st->cpu);
1085}
1086
Dave Barachc3799992016-08-15 11:12:27 -04001087static char *elog_serialize_magic = "elog v0";
Ed Warnickecb9cada2015-12-08 15:45:58 -07001088
1089void
1090serialize_elog_main (serialize_main_t * m, va_list * va)
1091{
Dave Barachc3799992016-08-15 11:12:27 -04001092 elog_main_t *em = va_arg (*va, elog_main_t *);
Dave Barach903fd512017-04-01 11:07:40 -04001093 int flush_ring = va_arg (*va, int);
Dave Barachc3799992016-08-15 11:12:27 -04001094 elog_event_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001095
1096 serialize_magic (m, elog_serialize_magic, strlen (elog_serialize_magic));
1097
1098 serialize_integer (m, em->event_ring_size, sizeof (u32));
1099
1100 elog_time_now (&em->serialize_time);
1101 serialize (m, serialize_elog_time_stamp, &em->serialize_time);
1102 serialize (m, serialize_elog_time_stamp, &em->init_time);
1103
1104 vec_serialize (m, em->event_types, serialize_elog_event_type);
1105 vec_serialize (m, em->tracks, serialize_elog_track);
1106 vec_serialize (m, em->string_table, serialize_vec_8);
1107
1108 /* Free old events (cached) in case they have changed. */
Dave Barach903fd512017-04-01 11:07:40 -04001109 if (flush_ring)
1110 {
1111 vec_free (em->events);
1112 elog_get_events (em);
1113 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001114
1115 serialize_integer (m, vec_len (em->events), sizeof (u32));
1116
1117 /* SMP logs can easily have local time paradoxes... */
Matus Fabiand2dc3df2015-12-14 10:31:33 -05001118 vec_sort_with_function (em->events, elog_cmp);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001119
Dave Barachc3799992016-08-15 11:12:27 -04001120 vec_foreach (e, em->events) serialize (m, serialize_elog_event, em, e);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001121}
1122
1123void
1124unserialize_elog_main (serialize_main_t * m, va_list * va)
1125{
Dave Barachc3799992016-08-15 11:12:27 -04001126 elog_main_t *em = va_arg (*va, elog_main_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001127 uword i;
1128 u32 rs;
1129
1130 unserialize_check_magic (m, elog_serialize_magic,
1131 strlen (elog_serialize_magic));
1132
1133 unserialize_integer (m, &rs, sizeof (u32));
1134 em->event_ring_size = rs;
1135 elog_init (em, em->event_ring_size);
1136
1137 unserialize (m, unserialize_elog_time_stamp, &em->serialize_time);
1138 unserialize (m, unserialize_elog_time_stamp, &em->init_time);
1139 em->nsec_per_cpu_clock = elog_nsec_per_clock (em);
1140
1141 vec_unserialize (m, &em->event_types, unserialize_elog_event_type);
1142 for (i = 0; i < vec_len (em->event_types); i++)
1143 new_event_type (em, i);
1144
1145 vec_unserialize (m, &em->tracks, unserialize_elog_track);
1146 vec_unserialize (m, &em->string_table, unserialize_vec_8);
1147
1148 {
1149 u32 ne;
Dave Barachc3799992016-08-15 11:12:27 -04001150 elog_event_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001151
1152 unserialize_integer (m, &ne, sizeof (u32));
1153 vec_resize (em->events, ne);
1154 vec_foreach (e, em->events)
1155 unserialize (m, unserialize_elog_event, em, e);
1156 }
1157}
Dave Barachc3799992016-08-15 11:12:27 -04001158
1159/*
1160 * fd.io coding-style-patch-verification: ON
1161 *
1162 * Local Variables:
1163 * eval: (c-set-style "gnu")
1164 * End:
1165 */