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_name (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 format_elog_track (u8 * s, va_list * args)
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;
416 indent = format_get_indent (s) + 1;
418 es = elog_peek_events (em);
421 if (e->track != track_index)
423 s = format (s, "%U%18.9f: %U\n", format_white_space, indent, e->time + dt,
424 format_elog_event, em, e);
431 elog_time_now (elog_time_stamp_t * et)
433 u64 cpu_time_now, os_time_now_nsec;
438 #include <sys/syscall.h>
440 clock_gettime (CLOCK_REALTIME, &ts);
442 syscall (SYS_clock_gettime, CLOCK_REALTIME, &ts);
444 cpu_time_now = clib_cpu_time_now ();
445 /* Subtract 3/30/2017's worth of seconds to retain precision */
446 os_time_now_nsec = 1e9 * (ts.tv_sec - 1490885108) + ts.tv_nsec;
449 cpu_time_now = clib_cpu_time_now ();
450 os_time_now_nsec = 0;
453 et->cpu = cpu_time_now;
454 et->os_nsec = os_time_now_nsec;
458 elog_time_stamp_diff_os_nsec (elog_time_stamp_t * t1, elog_time_stamp_t * t2)
460 return (i64) t1->os_nsec - (i64) t2->os_nsec;
464 elog_time_stamp_diff_cpu (elog_time_stamp_t * t1, elog_time_stamp_t * t2)
466 return (i64) t1->cpu - (i64) t2->cpu;
470 elog_nsec_per_clock (elog_main_t * em)
472 return ((f64) elog_time_stamp_diff_os_nsec (&em->serialize_time,
474 / (f64) elog_time_stamp_diff_cpu (&em->serialize_time,
479 elog_alloc (elog_main_t * em, u32 n_events)
482 vec_free (em->event_ring);
484 /* Ring size must be a power of 2. */
485 em->event_ring_size = n_events = max_pow2 (n_events);
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);
493 elog_init (elog_main_t * em, u32 n_events)
495 clib_memset (em, 0, sizeof (em[0]));
500 elog_alloc (em, n_events);
502 clib_time_init (&em->cpu_timer);
504 em->n_total_events_disable_limit = ~0;
507 em->default_track.name = "default";
508 elog_track_register (em, &em->default_track);
510 elog_time_now (&em->init_time);
513 /* Returns number of events in ring and start index. */
515 elog_event_range (elog_main_t * em, uword * lo)
517 uword l = em->event_ring_size;
518 u64 i = em->n_total_events;
520 /* Ring never wrapped? */
536 elog_peek_events (elog_main_t * em)
538 elog_event_t *e, *f, *es = 0;
541 n = elog_event_range (em, &j);
542 for (i = 0; i < n; i++)
545 f = vec_elt_at_index (em->event_ring, j);
548 /* Convert absolute time from cycles to seconds from start. */
551 em->init_time.cpu) * em->cpu_timer.seconds_per_clock;
553 j = (j + 1) & (em->event_ring_size - 1);
559 /* Add a formatted string to the string table. */
561 elog_string (elog_main_t * em, char *fmt, ...)
568 offset = vec_len (em->string_table);
569 em->string_table = (char *) va_format ((u8 *) em->string_table, fmt, &va);
572 /* Null terminate string if it is not already. */
573 if (vec_end (em->string_table)[-1] != 0)
574 vec_add1 (em->string_table, 0);
581 elog_get_events (elog_main_t * em)
584 em->events = elog_peek_events (em);
589 maybe_fix_string_table_offset (elog_event_t * e,
590 elog_event_type_t * t, u32 offset)
592 void *d = (u8 *) e->data;
602 uword n_bytes = 0, n_digits;
607 /* Don't go past end of event data. */
608 ASSERT (d < (void *) (e->data + sizeof (e->data)));
610 n_digits = parse_2digit_decimal (a + 1, &n_bytes);
614 ASSERT (n_bytes == 4);
615 clib_mem_unaligned (d, u32) += offset;
629 ASSERT (n_digits > 0 && n_digits <= 2);
636 elog_cmp (void *a1, void *a2)
638 elog_event_t *e1 = a1;
639 elog_event_t *e2 = a2;
641 if (e1->time < e2->time)
644 if (e1->time > e2->time)
651 * merge two event logs. Complicated and cranky.
654 elog_merge (elog_main_t * dst, u8 * dst_tag, elog_main_t * src, u8 * src_tag,
659 u32 string_table_offset_for_src_events;
660 u32 track_offset_for_src_tracks;
664 clib_memset (&newt, 0, sizeof (newt));
666 /* Acquire src and dst events */
667 elog_get_events (src);
668 elog_get_events (dst);
670 string_table_offset_for_src_events = vec_len (dst->string_table);
671 vec_append (dst->string_table, src->string_table);
673 l = vec_len (dst->events);
674 vec_append (dst->events, src->events);
676 /* Prepend the supplied tag (if any) to all dst track names */
679 for (i = 0; i < vec_len (dst->tracks); i++)
681 elog_track_t *t = vec_elt_at_index (dst->tracks, i);
684 new_name = (char *) format (0, "%s:%s%c", dst_tag, t->name, 0);
691 * Remember where we started allocating new tracks while merging
693 track_offset_for_src_tracks = vec_len (dst->tracks);
695 /* Copy / tag source tracks */
696 for (i = 0; i < vec_len (src->tracks); i++)
698 elog_track_t *t = vec_elt_at_index (src->tracks, i);
700 newt.name = (char *) format (0, "%s:%s%c", src_tag, t->name, 0);
702 newt.name = (char *) format (0, "%s%c", t->name, 0);
703 (void) elog_track_register (dst, &newt);
704 vec_free (newt.name);
707 /* Across all (copied) src events... */
708 for (e = dst->events + l; e < vec_end (dst->events); e++)
710 elog_event_type_t *t = vec_elt_at_index (src->event_types, e->type);
712 /* Remap type from src -> dst. */
713 e->type = find_or_create_type (dst, t);
715 /* Remap string table offsets for 'T' format args */
716 maybe_fix_string_table_offset (e, t,
717 string_table_offset_for_src_events);
720 e->track += track_offset_for_src_tracks;
723 /* Adjust event times for relative starting times of event streams. */
725 f64 dt_event, dt_os_nsec, dt_clock_nsec;
727 /* Set clock parameters if dst was not generated by unserialize. */
728 if (dst->serialize_time.cpu == 0)
730 dst->init_time = src->init_time;
731 dst->serialize_time = src->serialize_time;
732 dst->nsec_per_cpu_clock = src->nsec_per_cpu_clock;
736 elog_time_stamp_diff_os_nsec (&src->init_time, &dst->init_time);
738 dt_event = dt_os_nsec;
740 (elog_time_stamp_diff_cpu (&src->init_time, &dst->init_time) * .5 *
741 (dst->nsec_per_cpu_clock + src->nsec_per_cpu_clock));
744 * Heuristic to see if src/dst came from same time source.
745 * If frequencies are "the same" and os clock and cpu clock agree
746 * to within 100e-9 secs about time difference between src/dst
747 * init_time, then we use cpu clock. Otherwise we use OS clock.
749 * When merging event logs from different systems, time paradoxes
750 * at the O(1ms) level are to be expected. Hence, the "align_tweak"
751 * parameter. If two events logged on different processors are known
752 * to occur in a specific order - and with a reasonably-estimated
753 * interval - supply a non-zero "align_tweak" parameter
755 if (fabs (src->nsec_per_cpu_clock - dst->nsec_per_cpu_clock) < 1e-2
756 && fabs (dt_os_nsec - dt_clock_nsec) < 100)
757 dt_event = dt_clock_nsec;
759 /* Convert to seconds. */
763 * Move the earlier set of events later, to avoid creating
764 * events which precede the Big Bang (aka have negative timestamps).
766 * Not to any scale, we have something like the following picture:
768 * DST capture start point
772 * SRC capture start point
774 * In this case dt_event is positive, src started after dst,
775 * to put src events onto a common timebase we have to move them
776 * forward in time. Naturally, the opposite case is
777 * possible, too: dt_event will be negative, and so we have to
778 * move dst events forward in time by the |dt_event|.
779 * In both cases, we add align_tweak.
783 /* Src started after dst. */
784 for (e = dst->events + l; e < vec_end (dst->events); e++)
785 e->time += dt_event + align_tweak;
789 /* Dst started after src. */
790 dt_event = -dt_event;
791 for (e = dst->events + 0; e < dst->events + l; e++)
792 e->time += dt_event + align_tweak;
796 /* Sort events by increasing time. */
797 vec_sort_with_function (dst->events, elog_cmp);
799 dst->n_total_events = vec_len (dst->events);
801 /* Recreate the event ring or the results won't serialize */
805 ASSERT (dst->cpu_timer.seconds_per_clock);
807 elog_alloc (dst, vec_len (dst->events));
808 for (i = 0; i < vec_len (dst->events); i++)
810 elog_event_t *es, *ed;
812 es = dst->events + i;
813 ed = dst->event_ring + i;
821 serialize_elog_event (serialize_main_t * m, va_list * va)
823 elog_main_t *em = va_arg (*va, elog_main_t *);
824 elog_event_t *e = va_arg (*va, elog_event_t *);
825 elog_event_type_t *t = vec_elt_at_index (em->event_types, e->type);
827 u8 *p = (u8 *) t->format_args;
829 serialize_integer (m, e->type, sizeof (e->type));
830 serialize_integer (m, e->track, sizeof (e->track));
831 serialize (m, serialize_f64, e->time);
835 uword n_digits, n_bytes = 0;
837 n_digits = parse_2digit_decimal ((char *) p + 1, &n_bytes);
845 serialize_integer (m, d[0], sizeof (u8));
846 else if (n_bytes == 2)
847 serialize_integer (m, clib_mem_unaligned (d, u16), sizeof (u16));
848 else if (n_bytes == 4)
849 serialize_integer (m, clib_mem_unaligned (d, u32), sizeof (u32));
850 else if (n_bytes == 8)
851 serialize (m, serialize_64, clib_mem_unaligned (d, u64));
857 serialize_cstring (m, (char *) d);
859 n_bytes = strlen ((char *) d) + 1;
864 serialize (m, serialize_f32, clib_mem_unaligned (d, f32));
865 else if (n_bytes == 8)
866 serialize (m, serialize_f64, clib_mem_unaligned (d, f64));
882 unserialize_elog_event (serialize_main_t * m, va_list * va)
884 elog_main_t *em = va_arg (*va, elog_main_t *);
885 elog_event_t *e = va_arg (*va, elog_event_t *);
886 elog_event_type_t *t;
892 unserialize_integer (m, &tmp[0], sizeof (e->type));
893 unserialize_integer (m, &tmp[1], sizeof (e->track));
898 /* Make sure it fits. */
899 ASSERT (e->type == tmp[0]);
900 ASSERT (e->track == tmp[1]);
903 t = vec_elt_at_index (em->event_types, e->type);
905 unserialize (m, unserialize_f64, &e->time);
908 p = (u8 *) t->format_args;
912 uword n_digits, n_bytes = 0;
915 n_digits = parse_2digit_decimal ((char *) p + 1, &n_bytes);
924 unserialize_integer (m, &tmp, sizeof (u8));
927 else if (n_bytes == 2)
929 unserialize_integer (m, &tmp, sizeof (u16));
930 clib_mem_unaligned (d, u16) = tmp;
932 else if (n_bytes == 4)
934 unserialize_integer (m, &tmp, sizeof (u32));
935 clib_mem_unaligned (d, u32) = tmp;
937 else if (n_bytes == 8)
940 unserialize (m, unserialize_64, &x);
941 clib_mem_unaligned (d, u64) = x;
950 unserialize_cstring (m, &t);
952 n_bytes = strlen (t) + 1;
953 clib_memcpy (d, t, clib_min (n_bytes, vec_len (t)));
962 unserialize (m, unserialize_f32, &x);
963 clib_mem_unaligned (d, f32) = x;
965 else if (n_bytes == 8)
968 unserialize (m, unserialize_f64, &x);
969 clib_mem_unaligned (d, f64) = x;
986 serialize_elog_event_type (serialize_main_t * m, va_list * va)
988 elog_event_type_t *t = va_arg (*va, elog_event_type_t *);
989 int n = va_arg (*va, int);
991 for (i = 0; i < n; i++)
993 serialize_cstring (m, t[i].format);
994 serialize_cstring (m, t[i].format_args);
995 serialize_integer (m, t[i].type_index_plus_one,
996 sizeof (t->type_index_plus_one));
997 serialize_integer (m, t[i].n_enum_strings,
998 sizeof (t[i].n_enum_strings));
999 for (j = 0; j < t[i].n_enum_strings; j++)
1000 serialize_cstring (m, t[i].enum_strings_vector[j]);
1005 unserialize_elog_event_type (serialize_main_t * m, va_list * va)
1007 elog_event_type_t *t = va_arg (*va, elog_event_type_t *);
1008 int n = va_arg (*va, int);
1010 for (i = 0; i < n; i++)
1012 unserialize_cstring (m, &t[i].format);
1013 unserialize_cstring (m, &t[i].format_args);
1014 unserialize_integer (m, &t[i].type_index_plus_one,
1015 sizeof (t->type_index_plus_one));
1016 unserialize_integer (m, &t[i].n_enum_strings,
1017 sizeof (t[i].n_enum_strings));
1018 vec_resize (t[i].enum_strings_vector, t[i].n_enum_strings);
1019 for (j = 0; j < t[i].n_enum_strings; j++)
1020 unserialize_cstring (m, &t[i].enum_strings_vector[j]);
1025 serialize_elog_track (serialize_main_t * m, va_list * va)
1027 elog_track_t *t = va_arg (*va, elog_track_t *);
1028 int n = va_arg (*va, int);
1030 for (i = 0; i < n; i++)
1032 serialize_cstring (m, t[i].name);
1037 unserialize_elog_track (serialize_main_t * m, va_list * va)
1039 elog_track_t *t = va_arg (*va, elog_track_t *);
1040 int n = va_arg (*va, int);
1042 for (i = 0; i < n; i++)
1044 unserialize_cstring (m, &t[i].name);
1049 serialize_elog_time_stamp (serialize_main_t * m, va_list * va)
1051 elog_time_stamp_t *st = va_arg (*va, elog_time_stamp_t *);
1052 serialize (m, serialize_64, st->os_nsec);
1053 serialize (m, serialize_64, st->cpu);
1057 unserialize_elog_time_stamp (serialize_main_t * m, va_list * va)
1059 elog_time_stamp_t *st = va_arg (*va, elog_time_stamp_t *);
1060 unserialize (m, unserialize_64, &st->os_nsec);
1061 unserialize (m, unserialize_64, &st->cpu);
1064 static char *elog_serialize_magic = "elog v0";
1067 serialize_elog_main (serialize_main_t * m, va_list * va)
1069 elog_main_t *em = va_arg (*va, elog_main_t *);
1070 int flush_ring = va_arg (*va, int);
1073 serialize_magic (m, elog_serialize_magic, strlen (elog_serialize_magic));
1075 serialize_integer (m, em->event_ring_size, sizeof (u32));
1077 elog_time_now (&em->serialize_time);
1078 serialize (m, serialize_elog_time_stamp, &em->serialize_time);
1079 serialize (m, serialize_elog_time_stamp, &em->init_time);
1081 vec_serialize (m, em->event_types, serialize_elog_event_type);
1082 vec_serialize (m, em->tracks, serialize_elog_track);
1083 vec_serialize (m, em->string_table, serialize_vec_8);
1085 /* Free old events (cached) in case they have changed. */
1088 vec_free (em->events);
1089 elog_get_events (em);
1092 serialize_integer (m, vec_len (em->events), sizeof (u32));
1094 /* SMP logs can easily have local time paradoxes... */
1095 vec_sort_with_function (em->events, elog_cmp);
1097 vec_foreach (e, em->events) serialize (m, serialize_elog_event, em, e);
1101 unserialize_elog_main (serialize_main_t * m, va_list * va)
1103 elog_main_t *em = va_arg (*va, elog_main_t *);
1107 unserialize_check_magic (m, elog_serialize_magic,
1108 strlen (elog_serialize_magic));
1110 unserialize_integer (m, &rs, sizeof (u32));
1111 em->event_ring_size = rs;
1112 elog_init (em, em->event_ring_size);
1114 unserialize (m, unserialize_elog_time_stamp, &em->serialize_time);
1115 unserialize (m, unserialize_elog_time_stamp, &em->init_time);
1116 em->nsec_per_cpu_clock = elog_nsec_per_clock (em);
1118 vec_unserialize (m, &em->event_types, unserialize_elog_event_type);
1119 for (i = 0; i < vec_len (em->event_types); i++)
1120 new_event_type (em, i);
1122 vec_unserialize (m, &em->tracks, unserialize_elog_track);
1123 vec_unserialize (m, &em->string_table, unserialize_vec_8);
1129 unserialize_integer (m, &ne, sizeof (u32));
1130 vec_resize (em->events, ne);
1131 vec_foreach (e, em->events)
1132 unserialize (m, unserialize_elog_event, em, e);
1137 * fd.io coding-style-patch-verification: ON
1140 * eval: (c-set-style "gnu")