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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 Copyright (c) 2005,2009 Eliot Dresselhaus
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:
26 The above copyright notice and this permission notice shall be
27 included in all copies or substantial portions of the Software.
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.
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>
46 elog_lock (elog_main_t * em)
48 if (PREDICT_FALSE (em->lock != 0))
49 while (clib_atomic_test_and_set (em->lock))
54 elog_unlock (elog_main_t * em)
56 if (PREDICT_FALSE (em->lock != 0))
58 CLIB_MEMORY_BARRIER ();
63 /* Non-inline version. */
65 elog_event_data (elog_main_t * em,
66 elog_event_type_t * type, elog_track_t * track, u64 cpu_time)
68 return elog_event_data_inline (em, type, track, cpu_time);
72 new_event_type (elog_main_t * em, uword i)
74 elog_event_type_t *t = vec_elt_at_index (em->event_types, i);
76 if (!em->event_type_by_format)
77 em->event_type_by_format =
78 hash_create_vec ( /* size */ 0, sizeof (u8), sizeof (uword));
80 t->type_index_plus_one = i + 1;
81 hash_set_mem (em->event_type_by_format, t->format, i);
85 find_or_create_type (elog_main_t * em, elog_event_type_t * t)
87 uword *p = hash_get_mem (em->event_type_by_format, t->format);
94 i = vec_len (em->event_types);
95 vec_add1 (em->event_types, t[0]);
96 new_event_type (em, i);
102 /* External function to register types. */
104 elog_event_type_register (elog_main_t * em, elog_event_type_t * t)
106 elog_event_type_t *static_type = t;
111 /* Multiple simultaneous registration attempts, */
112 if (t->type_index_plus_one > 0)
115 return t->type_index_plus_one - 1;
118 l = vec_len (em->event_types);
120 t->type_index_plus_one = 1 + l;
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. */
131 l = strlen (t->format);
132 for (i = 0; i < l; i++)
134 if (t->format[i] != '%')
138 if (t->format[i + 1] == '%') /* %% */
141 switch (t->format[i + 1])
147 this_arg = "i4"; /* size of u32 */
150 this_arg = "f8"; /* defaults to f64 */
153 this_arg = "s0"; /* defaults to null terminated string. */
158 (char *) format ((u8 *) t->format_args, "%s", this_arg);
161 /* Null terminate. */
162 vec_add1 (t->format_args, 0);
165 vec_add1 (em->event_types, t[0]);
167 t = em->event_types + l;
169 /* Make copies of strings for hashing etc. */
171 t->format = (char *) format (0, "%s %s%c", t->function, t->format, 0);
173 t->format = (char *) format (0, "%s%c", t->format, 0);
175 t->format_args = (char *) format (0, "%s%c", t->format_args, 0);
177 /* Construct string table. */
180 t->n_enum_strings = static_type->n_enum_strings;
181 for (i = 0; i < t->n_enum_strings; i++)
183 if (!static_type->enum_strings[i])
184 static_type->enum_strings[i] = "MISSING";
185 vec_add1 (t->enum_strings_vector,
186 (char *) format (0, "%s%c", static_type->enum_strings[i],
191 new_event_type (em, l);
198 elog_track_register (elog_main_t * em, elog_track_t * t)
204 l = vec_len (em->tracks);
206 t->track_index_plus_one = 1 + l;
210 vec_add1 (em->tracks, t[0]);
214 t->name = (char *) format (0, "%s%c", t->name, 0);
222 parse_2digit_decimal (char *p, uword * number)
227 digits[0] = digits[1] = 0;
228 while (p[i] >= '0' && p[i] <= '9')
232 digits[i] = p[i] - '0';
236 if (i >= 1 && i <= 2)
241 *number = 10 * digits[0] + digits[1];
249 fixed_format (u8 * s, char *fmt, char *result, uword * result_len)
259 if (f[0] == '%' && f[1] != '%')
264 vec_add (s, fmt, f - fmt);
272 /* Skip possible +-= justification. */
273 f += f[0] == '+' || f[0] == '-' || f[0] == '=';
275 /* Skip possible X.Y width. */
276 while ((f[0] >= '0' && f[0] <= '9') || f[0] == '.')
279 /* Skip wlL as in e.g. %Ld. */
280 f += f[0] == 'w' || f[0] == 'l' || f[0] == 'L';
282 /* Finally skip format letter. */
285 ASSERT (*result_len > f - percent);
286 l = clib_min (f - percent, *result_len - 1);
287 clib_memcpy (result, percent, l);
291 *result_len = f - fmt;
296 format_elog_event (u8 * s, va_list * va)
298 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;
302 void *d = (u8 *) e->data;
305 t = vec_elt_at_index (em->event_types, e->type);
311 uword n_bytes = 0, n_digits, f_bytes = 0;
313 f_bytes = sizeof (arg_format);
314 s = fixed_format (s, f, arg_format, &f_bytes);
317 if (a == 0 || a[0] == 0)
319 /* Format must also be at end. */
324 /* Don't go past end of event data. */
325 ASSERT (d < (void *) (e->data + sizeof (e->data)));
327 n_digits = parse_2digit_decimal (a + 1, &n_bytes);
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);
350 vec_elt (t->enum_strings_vector, n_bytes == 8 ? l : i);
351 s = format (s, arg_format, e);
353 else if (a[0] == 'T')
356 vec_elt_at_index (em->string_table, n_bytes == 8 ? l : i);
357 s = format (s, arg_format, e);
359 else if (n_bytes == 8)
360 s = format (s, arg_format, l);
362 s = format (s, arg_format, i);
370 x = clib_mem_unaligned (d, f32);
371 else if (n_bytes == 8)
372 x = clib_mem_unaligned (d, f64);
375 s = format (s, arg_format, x);
380 s = format (s, arg_format, d);
382 n_bytes = strlen (d) + 1;
390 ASSERT (n_digits > 0 && n_digits <= 2);
399 format_elog_track (u8 * s, va_list * va)
401 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);
404 return format (s, "%s", t->name);
408 elog_time_now (elog_time_stamp_t * et)
410 u64 cpu_time_now, os_time_now_nsec;
415 #include <sys/syscall.h>
417 clock_gettime (CLOCK_REALTIME, &ts);
419 syscall (SYS_clock_gettime, CLOCK_REALTIME, &ts);
421 cpu_time_now = clib_cpu_time_now ();
422 /* Subtract 3/30/2017's worth of seconds to retain precision */
423 os_time_now_nsec = 1e9 * (ts.tv_sec - 1490885108) + ts.tv_nsec;
426 cpu_time_now = clib_cpu_time_now ();
427 os_time_now_nsec = 0;
430 et->cpu = cpu_time_now;
431 et->os_nsec = os_time_now_nsec;
435 elog_time_stamp_diff_os_nsec (elog_time_stamp_t * t1, elog_time_stamp_t * t2)
437 return (i64) t1->os_nsec - (i64) t2->os_nsec;
441 elog_time_stamp_diff_cpu (elog_time_stamp_t * t1, elog_time_stamp_t * t2)
443 return (i64) t1->cpu - (i64) t2->cpu;
447 elog_nsec_per_clock (elog_main_t * em)
449 return ((f64) elog_time_stamp_diff_os_nsec (&em->serialize_time,
451 / (f64) elog_time_stamp_diff_cpu (&em->serialize_time,
456 elog_alloc (elog_main_t * em, u32 n_events)
459 vec_free (em->event_ring);
461 /* Ring size must be a power of 2. */
462 em->event_ring_size = n_events = max_pow2 (n_events);
464 /* Leave an empty ievent at end so we can always speculatively write
465 and event there (possibly a long form event). */
466 vec_resize_aligned (em->event_ring, n_events, CLIB_CACHE_LINE_BYTES);
470 elog_init (elog_main_t * em, u32 n_events)
472 clib_memset (em, 0, sizeof (em[0]));
477 elog_alloc (em, n_events);
479 clib_time_init (&em->cpu_timer);
481 em->n_total_events_disable_limit = ~0;
484 em->default_track.name = "default";
485 elog_track_register (em, &em->default_track);
487 elog_time_now (&em->init_time);
490 /* Returns number of events in ring and start index. */
492 elog_event_range (elog_main_t * em, uword * lo)
494 uword l = em->event_ring_size;
495 u64 i = em->n_total_events;
497 /* Ring never wrapped? */
513 elog_peek_events (elog_main_t * em)
515 elog_event_t *e, *f, *es = 0;
518 n = elog_event_range (em, &j);
519 for (i = 0; i < n; i++)
522 f = vec_elt_at_index (em->event_ring, j);
525 /* Convert absolute time from cycles to seconds from start. */
528 em->init_time.cpu) * em->cpu_timer.seconds_per_clock;
530 j = (j + 1) & (em->event_ring_size - 1);
536 /* Add a formatted string to the string table. */
538 elog_string (elog_main_t * em, char *fmt, ...)
544 offset = vec_len (em->string_table);
545 em->string_table = (char *) va_format ((u8 *) em->string_table, fmt, &va);
548 /* Null terminate string if it is not already. */
549 if (vec_end (em->string_table)[-1] != 0)
550 vec_add1 (em->string_table, 0);
556 elog_get_events (elog_main_t * em)
559 em->events = elog_peek_events (em);
564 maybe_fix_string_table_offset (elog_event_t * e,
565 elog_event_type_t * t, u32 offset)
567 void *d = (u8 *) e->data;
577 uword n_bytes = 0, n_digits;
582 /* Don't go past end of event data. */
583 ASSERT (d < (void *) (e->data + sizeof (e->data)));
585 n_digits = parse_2digit_decimal (a + 1, &n_bytes);
589 ASSERT (n_bytes == 4);
590 clib_mem_unaligned (d, u32) += offset;
604 ASSERT (n_digits > 0 && n_digits <= 2);
611 elog_cmp (void *a1, void *a2)
613 elog_event_t *e1 = a1;
614 elog_event_t *e2 = a2;
616 if (e1->time < e2->time)
619 if (e1->time > e2->time)
626 * merge two event logs. Complicated and cranky.
629 elog_merge (elog_main_t * dst, u8 * dst_tag, elog_main_t * src, u8 * src_tag,
634 u32 string_table_offset_for_src_events;
635 u32 track_offset_for_src_tracks;
639 clib_memset (&newt, 0, sizeof (newt));
641 /* Acquire src and dst events */
642 elog_get_events (src);
643 elog_get_events (dst);
645 string_table_offset_for_src_events = vec_len (dst->string_table);
646 vec_append (dst->string_table, src->string_table);
648 l = vec_len (dst->events);
649 vec_append (dst->events, src->events);
651 /* Prepend the supplied tag (if any) to all dst track names */
654 for (i = 0; i < vec_len (dst->tracks); i++)
656 elog_track_t *t = vec_elt_at_index (dst->tracks, i);
659 new_name = (char *) format (0, "%s:%s%c", dst_tag, t->name, 0);
666 * Remember where we started allocating new tracks while merging
668 track_offset_for_src_tracks = vec_len (dst->tracks);
670 /* Copy / tag source tracks */
671 for (i = 0; i < vec_len (src->tracks); i++)
673 elog_track_t *t = vec_elt_at_index (src->tracks, i);
675 newt.name = (char *) format (0, "%s:%s%c", src_tag, t->name, 0);
677 newt.name = (char *) format (0, "%s%c", t->name, 0);
678 (void) elog_track_register (dst, &newt);
679 vec_free (newt.name);
682 /* Across all (copied) src events... */
683 for (e = dst->events + l; e < vec_end (dst->events); e++)
685 elog_event_type_t *t = vec_elt_at_index (src->event_types, e->type);
687 /* Remap type from src -> dst. */
688 e->type = find_or_create_type (dst, t);
690 /* Remap string table offsets for 'T' format args */
691 maybe_fix_string_table_offset (e, t,
692 string_table_offset_for_src_events);
695 e->track += track_offset_for_src_tracks;
698 /* Adjust event times for relative starting times of event streams. */
700 f64 dt_event, dt_os_nsec, dt_clock_nsec;
702 /* Set clock parameters if dst was not generated by unserialize. */
703 if (dst->serialize_time.cpu == 0)
705 dst->init_time = src->init_time;
706 dst->serialize_time = src->serialize_time;
707 dst->nsec_per_cpu_clock = src->nsec_per_cpu_clock;
711 elog_time_stamp_diff_os_nsec (&src->init_time, &dst->init_time);
713 dt_event = dt_os_nsec;
715 (elog_time_stamp_diff_cpu (&src->init_time, &dst->init_time) * .5 *
716 (dst->nsec_per_cpu_clock + src->nsec_per_cpu_clock));
719 * Heuristic to see if src/dst came from same time source.
720 * If frequencies are "the same" and os clock and cpu clock agree
721 * to within 100e-9 secs about time difference between src/dst
722 * init_time, then we use cpu clock. Otherwise we use OS clock.
724 * When merging event logs from different systems, time paradoxes
725 * at the O(1ms) level are to be expected. Hence, the "align_tweak"
726 * parameter. If two events logged on different processors are known
727 * to occur in a specific order - and with a reasonably-estimated
728 * interval - supply a non-zero "align_tweak" parameter
730 if (fabs (src->nsec_per_cpu_clock - dst->nsec_per_cpu_clock) < 1e-2
731 && fabs (dt_os_nsec - dt_clock_nsec) < 100)
732 dt_event = dt_clock_nsec;
734 /* Convert to seconds. */
738 * Move the earlier set of events later, to avoid creating
739 * events which precede the Big Bang (aka have negative timestamps).
741 * Not to any scale, we have something like the following picture:
743 * DST capture start point
747 * SRC capture start point
749 * In this case dt_event is positive, src started after dst,
750 * to put src events onto a common timebase we have to move them
751 * forward in time. Naturally, the opposite case is
752 * possible, too: dt_event will be negative, and so we have to
753 * move dst events forward in time by the |dt_event|.
754 * In both cases, we add align_tweak.
758 /* Src started after dst. */
759 for (e = dst->events + l; e < vec_end (dst->events); e++)
760 e->time += dt_event + align_tweak;
764 /* Dst started after src. */
765 dt_event = -dt_event;
766 for (e = dst->events + 0; e < dst->events + l; e++)
767 e->time += dt_event + align_tweak;
771 /* Sort events by increasing time. */
772 vec_sort_with_function (dst->events, elog_cmp);
774 dst->n_total_events = vec_len (dst->events);
776 /* Recreate the event ring or the results won't serialize */
780 ASSERT (dst->cpu_timer.seconds_per_clock);
782 elog_alloc (dst, vec_len (dst->events));
783 for (i = 0; i < vec_len (dst->events); i++)
785 elog_event_t *es, *ed;
787 es = dst->events + i;
788 ed = dst->event_ring + i;
796 serialize_elog_event (serialize_main_t * m, va_list * va)
798 elog_main_t *em = va_arg (*va, elog_main_t *);
799 elog_event_t *e = va_arg (*va, elog_event_t *);
800 elog_event_type_t *t = vec_elt_at_index (em->event_types, e->type);
802 u8 *p = (u8 *) t->format_args;
804 serialize_integer (m, e->type, sizeof (e->type));
805 serialize_integer (m, e->track, sizeof (e->track));
806 serialize (m, serialize_f64, e->time);
810 uword n_digits, n_bytes = 0;
812 n_digits = parse_2digit_decimal ((char *) p + 1, &n_bytes);
820 serialize_integer (m, d[0], sizeof (u8));
821 else if (n_bytes == 2)
822 serialize_integer (m, clib_mem_unaligned (d, u16), sizeof (u16));
823 else if (n_bytes == 4)
824 serialize_integer (m, clib_mem_unaligned (d, u32), sizeof (u32));
825 else if (n_bytes == 8)
826 serialize (m, serialize_64, clib_mem_unaligned (d, u64));
832 serialize_cstring (m, (char *) d);
834 n_bytes = strlen ((char *) d) + 1;
839 serialize (m, serialize_f32, clib_mem_unaligned (d, f32));
840 else if (n_bytes == 8)
841 serialize (m, serialize_f64, clib_mem_unaligned (d, f64));
857 unserialize_elog_event (serialize_main_t * m, va_list * va)
859 elog_main_t *em = va_arg (*va, elog_main_t *);
860 elog_event_t *e = va_arg (*va, elog_event_t *);
861 elog_event_type_t *t;
867 unserialize_integer (m, &tmp[0], sizeof (e->type));
868 unserialize_integer (m, &tmp[1], sizeof (e->track));
873 /* Make sure it fits. */
874 ASSERT (e->type == tmp[0]);
875 ASSERT (e->track == tmp[1]);
878 t = vec_elt_at_index (em->event_types, e->type);
880 unserialize (m, unserialize_f64, &e->time);
883 p = (u8 *) t->format_args;
887 uword n_digits, n_bytes = 0;
890 n_digits = parse_2digit_decimal ((char *) p + 1, &n_bytes);
899 unserialize_integer (m, &tmp, sizeof (u8));
902 else if (n_bytes == 2)
904 unserialize_integer (m, &tmp, sizeof (u16));
905 clib_mem_unaligned (d, u16) = tmp;
907 else if (n_bytes == 4)
909 unserialize_integer (m, &tmp, sizeof (u32));
910 clib_mem_unaligned (d, u32) = tmp;
912 else if (n_bytes == 8)
915 unserialize (m, unserialize_64, &x);
916 clib_mem_unaligned (d, u64) = x;
925 unserialize_cstring (m, &t);
927 n_bytes = strlen (t) + 1;
928 clib_memcpy (d, t, clib_min (n_bytes, vec_len (t)));
937 unserialize (m, unserialize_f32, &x);
938 clib_mem_unaligned (d, f32) = x;
940 else if (n_bytes == 8)
943 unserialize (m, unserialize_f64, &x);
944 clib_mem_unaligned (d, f64) = x;
961 serialize_elog_event_type (serialize_main_t * m, va_list * va)
963 elog_event_type_t *t = va_arg (*va, elog_event_type_t *);
964 int n = va_arg (*va, int);
966 for (i = 0; i < n; i++)
968 serialize_cstring (m, t[i].format);
969 serialize_cstring (m, t[i].format_args);
970 serialize_integer (m, t[i].type_index_plus_one,
971 sizeof (t->type_index_plus_one));
972 serialize_integer (m, t[i].n_enum_strings,
973 sizeof (t[i].n_enum_strings));
974 for (j = 0; j < t[i].n_enum_strings; j++)
975 serialize_cstring (m, t[i].enum_strings_vector[j]);
980 unserialize_elog_event_type (serialize_main_t * m, va_list * va)
982 elog_event_type_t *t = va_arg (*va, elog_event_type_t *);
983 int n = va_arg (*va, int);
985 for (i = 0; i < n; i++)
987 unserialize_cstring (m, &t[i].format);
988 unserialize_cstring (m, &t[i].format_args);
989 unserialize_integer (m, &t[i].type_index_plus_one,
990 sizeof (t->type_index_plus_one));
991 unserialize_integer (m, &t[i].n_enum_strings,
992 sizeof (t[i].n_enum_strings));
993 vec_resize (t[i].enum_strings_vector, t[i].n_enum_strings);
994 for (j = 0; j < t[i].n_enum_strings; j++)
995 unserialize_cstring (m, &t[i].enum_strings_vector[j]);
1000 serialize_elog_track (serialize_main_t * m, va_list * va)
1002 elog_track_t *t = va_arg (*va, elog_track_t *);
1003 int n = va_arg (*va, int);
1005 for (i = 0; i < n; i++)
1007 serialize_cstring (m, t[i].name);
1012 unserialize_elog_track (serialize_main_t * m, va_list * va)
1014 elog_track_t *t = va_arg (*va, elog_track_t *);
1015 int n = va_arg (*va, int);
1017 for (i = 0; i < n; i++)
1019 unserialize_cstring (m, &t[i].name);
1024 serialize_elog_time_stamp (serialize_main_t * m, va_list * va)
1026 elog_time_stamp_t *st = va_arg (*va, elog_time_stamp_t *);
1027 serialize (m, serialize_64, st->os_nsec);
1028 serialize (m, serialize_64, st->cpu);
1032 unserialize_elog_time_stamp (serialize_main_t * m, va_list * va)
1034 elog_time_stamp_t *st = va_arg (*va, elog_time_stamp_t *);
1035 unserialize (m, unserialize_64, &st->os_nsec);
1036 unserialize (m, unserialize_64, &st->cpu);
1039 static char *elog_serialize_magic = "elog v0";
1042 serialize_elog_main (serialize_main_t * m, va_list * va)
1044 elog_main_t *em = va_arg (*va, elog_main_t *);
1045 int flush_ring = va_arg (*va, int);
1048 serialize_magic (m, elog_serialize_magic, strlen (elog_serialize_magic));
1050 serialize_integer (m, em->event_ring_size, sizeof (u32));
1052 elog_time_now (&em->serialize_time);
1053 serialize (m, serialize_elog_time_stamp, &em->serialize_time);
1054 serialize (m, serialize_elog_time_stamp, &em->init_time);
1056 vec_serialize (m, em->event_types, serialize_elog_event_type);
1057 vec_serialize (m, em->tracks, serialize_elog_track);
1058 vec_serialize (m, em->string_table, serialize_vec_8);
1060 /* Free old events (cached) in case they have changed. */
1063 vec_free (em->events);
1064 elog_get_events (em);
1067 serialize_integer (m, vec_len (em->events), sizeof (u32));
1069 /* SMP logs can easily have local time paradoxes... */
1070 vec_sort_with_function (em->events, elog_cmp);
1072 vec_foreach (e, em->events) serialize (m, serialize_elog_event, em, e);
1076 unserialize_elog_main (serialize_main_t * m, va_list * va)
1078 elog_main_t *em = va_arg (*va, elog_main_t *);
1082 unserialize_check_magic (m, elog_serialize_magic,
1083 strlen (elog_serialize_magic));
1085 unserialize_integer (m, &rs, sizeof (u32));
1086 em->event_ring_size = rs;
1087 elog_init (em, em->event_ring_size);
1089 unserialize (m, unserialize_elog_time_stamp, &em->serialize_time);
1090 unserialize (m, unserialize_elog_time_stamp, &em->init_time);
1091 em->nsec_per_cpu_clock = elog_nsec_per_clock (em);
1093 vec_unserialize (m, &em->event_types, unserialize_elog_event_type);
1094 for (i = 0; i < vec_len (em->event_types); i++)
1095 new_event_type (em, i);
1097 vec_unserialize (m, &em->tracks, unserialize_elog_track);
1098 vec_unserialize (m, &em->string_table, unserialize_vec_8);
1104 unserialize_integer (m, &ne, sizeof (u32));
1105 vec_resize (em->events, ne);
1106 vec_foreach (e, em->events)
1107 unserialize (m, unserialize_elog_event, em, e);
1112 * fd.io coding-style-patch-verification: ON
1115 * eval: (c-set-style "gnu")