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);
511 em->string_table_hash = hash_create_string (0, sizeof (uword));
514 /* Returns number of events in ring and start index. */
516 elog_event_range (elog_main_t * em, uword * lo)
518 uword l = em->event_ring_size;
519 u64 i = em->n_total_events;
521 /* Ring never wrapped? */
537 elog_peek_events (elog_main_t * em)
539 elog_event_t *e, *f, *es = 0;
542 n = elog_event_range (em, &j);
543 for (i = 0; i < n; i++)
546 f = vec_elt_at_index (em->event_ring, j);
549 /* Convert absolute time from cycles to seconds from start. */
552 em->init_time.cpu) * em->cpu_timer.seconds_per_clock;
554 j = (j + 1) & (em->event_ring_size - 1);
560 /* Add a formatted string to the string table. */
562 elog_string (elog_main_t * em, char *fmt, ...)
570 vec_reset_length (em->string_table_tmp);
572 em->string_table_tmp = va_format (em->string_table_tmp, fmt, &va);
575 /* See if we already have this string in the string table */
576 p = hash_get_mem (em->string_table_hash, em->string_table_tmp);
578 /* We already have the string, so give the caller its offset */
585 /* We don't, so add it. String table entries MUST be NULL terminated */
586 len = vec_len (em->string_table_tmp);
588 if (em->string_table_tmp[len - 1] != 0)
589 vec_add1 (em->string_table_tmp, 0);
591 offset = vec_len (em->string_table);
592 vec_append (em->string_table, em->string_table_tmp);
594 hash_set_mem (em->string_table_hash, em->string_table_tmp, offset);
596 /* We gave the key to the string table hash, so we can't reuse it! */
597 em->string_table_tmp = 0;
604 elog_get_events (elog_main_t * em)
607 em->events = elog_peek_events (em);
612 maybe_fix_string_table_offset (elog_event_t * e,
613 elog_event_type_t * t, u32 offset)
615 void *d = (u8 *) e->data;
625 uword n_bytes = 0, n_digits;
630 /* Don't go past end of event data. */
631 ASSERT (d < (void *) (e->data + sizeof (e->data)));
633 n_digits = parse_2digit_decimal (a + 1, &n_bytes);
637 ASSERT (n_bytes == 4);
638 clib_mem_unaligned (d, u32) += offset;
652 ASSERT (n_digits > 0 && n_digits <= 2);
659 elog_cmp (void *a1, void *a2)
661 elog_event_t *e1 = a1;
662 elog_event_t *e2 = a2;
664 if (e1->time < e2->time)
667 if (e1->time > e2->time)
674 * merge two event logs. Complicated and cranky.
677 elog_merge (elog_main_t * dst, u8 * dst_tag, elog_main_t * src, u8 * src_tag,
682 u32 string_table_offset_for_src_events;
683 u32 track_offset_for_src_tracks;
687 clib_memset (&newt, 0, sizeof (newt));
689 /* Acquire src and dst events */
690 elog_get_events (src);
691 elog_get_events (dst);
693 string_table_offset_for_src_events = vec_len (dst->string_table);
694 vec_append (dst->string_table, src->string_table);
696 l = vec_len (dst->events);
697 vec_append (dst->events, src->events);
699 /* Prepend the supplied tag (if any) to all dst track names */
702 for (i = 0; i < vec_len (dst->tracks); i++)
704 elog_track_t *t = vec_elt_at_index (dst->tracks, i);
707 new_name = (char *) format (0, "%s:%s%c", dst_tag, t->name, 0);
714 * Remember where we started allocating new tracks while merging
716 track_offset_for_src_tracks = vec_len (dst->tracks);
718 /* Copy / tag source tracks */
719 for (i = 0; i < vec_len (src->tracks); i++)
721 elog_track_t *t = vec_elt_at_index (src->tracks, i);
723 newt.name = (char *) format (0, "%s:%s%c", src_tag, t->name, 0);
725 newt.name = (char *) format (0, "%s%c", t->name, 0);
726 (void) elog_track_register (dst, &newt);
727 vec_free (newt.name);
730 /* Across all (copied) src events... */
731 for (e = dst->events + l; e < vec_end (dst->events); e++)
733 elog_event_type_t *t = vec_elt_at_index (src->event_types, e->type);
735 /* Remap type from src -> dst. */
736 e->type = find_or_create_type (dst, t);
738 /* Remap string table offsets for 'T' format args */
739 maybe_fix_string_table_offset (e, t,
740 string_table_offset_for_src_events);
743 e->track += track_offset_for_src_tracks;
746 /* Adjust event times for relative starting times of event streams. */
748 f64 dt_event, dt_os_nsec, dt_clock_nsec;
750 /* Set clock parameters if dst was not generated by unserialize. */
751 if (dst->serialize_time.cpu == 0)
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;
759 elog_time_stamp_diff_os_nsec (&src->init_time, &dst->init_time);
761 dt_event = dt_os_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));
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.
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
778 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;
782 /* Convert to seconds. */
786 * Move the earlier set of events later, to avoid creating
787 * events which precede the Big Bang (aka have negative timestamps).
789 * Not to any scale, we have something like the following picture:
791 * DST capture start point
795 * SRC capture start point
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.
806 /* Src started after dst. */
807 for (e = dst->events + l; e < vec_end (dst->events); e++)
808 e->time += dt_event + align_tweak;
812 /* Dst started after src. */
813 dt_event = -dt_event;
814 for (e = dst->events + 0; e < dst->events + l; e++)
815 e->time += dt_event + align_tweak;
819 /* Sort events by increasing time. */
820 vec_sort_with_function (dst->events, elog_cmp);
822 dst->n_total_events = vec_len (dst->events);
824 /* Recreate the event ring or the results won't serialize */
828 ASSERT (dst->cpu_timer.seconds_per_clock);
830 elog_alloc (dst, vec_len (dst->events));
831 for (i = 0; i < vec_len (dst->events); i++)
833 elog_event_t *es, *ed;
835 es = dst->events + i;
836 ed = dst->event_ring + i;
844 serialize_elog_event (serialize_main_t * m, va_list * va)
846 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);
850 u8 *p = (u8 *) t->format_args;
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);
858 uword n_digits, n_bytes = 0;
860 n_digits = parse_2digit_decimal ((char *) p + 1, &n_bytes);
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));
880 serialize_cstring (m, (char *) d);
882 n_bytes = strlen ((char *) d) + 1;
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));
905 unserialize_elog_event (serialize_main_t * m, va_list * va)
907 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;
915 unserialize_integer (m, &tmp[0], sizeof (e->type));
916 unserialize_integer (m, &tmp[1], sizeof (e->track));
921 /* Make sure it fits. */
922 ASSERT (e->type == tmp[0]);
923 ASSERT (e->track == tmp[1]);
926 t = vec_elt_at_index (em->event_types, e->type);
928 unserialize (m, unserialize_f64, &e->time);
931 p = (u8 *) t->format_args;
935 uword n_digits, n_bytes = 0;
938 n_digits = parse_2digit_decimal ((char *) p + 1, &n_bytes);
947 unserialize_integer (m, &tmp, sizeof (u8));
950 else if (n_bytes == 2)
952 unserialize_integer (m, &tmp, sizeof (u16));
953 clib_mem_unaligned (d, u16) = tmp;
955 else if (n_bytes == 4)
957 unserialize_integer (m, &tmp, sizeof (u32));
958 clib_mem_unaligned (d, u32) = tmp;
960 else if (n_bytes == 8)
963 unserialize (m, unserialize_64, &x);
964 clib_mem_unaligned (d, u64) = x;
973 unserialize_cstring (m, &t);
975 n_bytes = strlen (t) + 1;
976 clib_memcpy (d, t, clib_min (n_bytes, vec_len (t)));
985 unserialize (m, unserialize_f32, &x);
986 clib_mem_unaligned (d, f32) = x;
988 else if (n_bytes == 8)
991 unserialize (m, unserialize_f64, &x);
992 clib_mem_unaligned (d, f64) = x;
1009 serialize_elog_event_type (serialize_main_t * m, va_list * va)
1011 elog_event_type_t *t = va_arg (*va, elog_event_type_t *);
1012 int n = va_arg (*va, int);
1014 for (i = 0; i < n; i++)
1016 serialize_cstring (m, t[i].format);
1017 serialize_cstring (m, t[i].format_args);
1018 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));
1022 for (j = 0; j < t[i].n_enum_strings; j++)
1023 serialize_cstring (m, t[i].enum_strings_vector[j]);
1028 unserialize_elog_event_type (serialize_main_t * m, va_list * va)
1030 elog_event_type_t *t = va_arg (*va, elog_event_type_t *);
1031 int n = va_arg (*va, int);
1033 for (i = 0; i < n; i++)
1035 unserialize_cstring (m, &t[i].format);
1036 unserialize_cstring (m, &t[i].format_args);
1037 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));
1041 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]);
1048 serialize_elog_track (serialize_main_t * m, va_list * va)
1050 elog_track_t *t = va_arg (*va, elog_track_t *);
1051 int n = va_arg (*va, int);
1053 for (i = 0; i < n; i++)
1055 serialize_cstring (m, t[i].name);
1060 unserialize_elog_track (serialize_main_t * m, va_list * va)
1062 elog_track_t *t = va_arg (*va, elog_track_t *);
1063 int n = va_arg (*va, int);
1065 for (i = 0; i < n; i++)
1067 unserialize_cstring (m, &t[i].name);
1072 serialize_elog_time_stamp (serialize_main_t * m, va_list * va)
1074 elog_time_stamp_t *st = va_arg (*va, elog_time_stamp_t *);
1075 serialize (m, serialize_64, st->os_nsec);
1076 serialize (m, serialize_64, st->cpu);
1080 unserialize_elog_time_stamp (serialize_main_t * m, va_list * va)
1082 elog_time_stamp_t *st = va_arg (*va, elog_time_stamp_t *);
1083 unserialize (m, unserialize_64, &st->os_nsec);
1084 unserialize (m, unserialize_64, &st->cpu);
1087 static char *elog_serialize_magic = "elog v0";
1090 serialize_elog_main (serialize_main_t * m, va_list * va)
1092 elog_main_t *em = va_arg (*va, elog_main_t *);
1093 int flush_ring = va_arg (*va, int);
1096 serialize_magic (m, elog_serialize_magic, strlen (elog_serialize_magic));
1098 serialize_integer (m, em->event_ring_size, sizeof (u32));
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);
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);
1108 /* Free old events (cached) in case they have changed. */
1111 vec_free (em->events);
1112 elog_get_events (em);
1115 serialize_integer (m, vec_len (em->events), sizeof (u32));
1117 /* SMP logs can easily have local time paradoxes... */
1118 vec_sort_with_function (em->events, elog_cmp);
1120 vec_foreach (e, em->events) serialize (m, serialize_elog_event, em, e);
1124 unserialize_elog_main (serialize_main_t * m, va_list * va)
1126 elog_main_t *em = va_arg (*va, elog_main_t *);
1130 unserialize_check_magic (m, elog_serialize_magic,
1131 strlen (elog_serialize_magic));
1133 unserialize_integer (m, &rs, sizeof (u32));
1134 em->event_ring_size = rs;
1135 elog_init (em, em->event_ring_size);
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);
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);
1145 vec_unserialize (m, &em->tracks, unserialize_elog_track);
1146 vec_unserialize (m, &em->string_table, unserialize_vec_8);
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);
1160 * fd.io coding-style-patch-verification: ON
1163 * eval: (c-set-style "gnu")