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>
44 #include <vppinfra/lock.h>
47 elog_lock (elog_main_t * em)
49 if (PREDICT_FALSE (em->lock != 0))
50 while (clib_atomic_test_and_set (em->lock))
55 elog_unlock (elog_main_t * em)
57 if (PREDICT_FALSE (em->lock != 0))
59 clib_atomic_release (em->lock);
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 /* String table entries MUST be NULL terminated */
576 len = vec_len (em->string_table_tmp);
578 if (em->string_table_tmp[len - 1] != 0)
579 vec_add1 (em->string_table_tmp, 0);
581 /* See if we already have this string in the string table */
582 p = hash_get_mem (em->string_table_hash, em->string_table_tmp);
584 /* We already have the string, so give the caller its offset */
591 /* We don't, so add it. */
593 offset = vec_len (em->string_table);
594 vec_append (em->string_table, em->string_table_tmp);
596 hash_set_mem (em->string_table_hash, em->string_table_tmp, offset);
598 /* We gave the key to the string table hash, so we can't reuse it! */
599 em->string_table_tmp = 0;
606 elog_get_events (elog_main_t * em)
609 em->events = elog_peek_events (em);
614 maybe_fix_string_table_offset (elog_event_t * e,
615 elog_event_type_t * t, u32 offset)
617 void *d = (u8 *) e->data;
627 uword n_bytes = 0, n_digits;
632 /* Don't go past end of event data. */
633 ASSERT (d < (void *) (e->data + sizeof (e->data)));
635 n_digits = parse_2digit_decimal (a + 1, &n_bytes);
639 ASSERT (n_bytes == 4);
640 clib_mem_unaligned (d, u32) += offset;
654 ASSERT (n_digits > 0 && n_digits <= 2);
661 elog_cmp (void *a1, void *a2)
663 elog_event_t *e1 = a1;
664 elog_event_t *e2 = a2;
666 if (e1->time < e2->time)
669 if (e1->time > e2->time)
676 * merge two event logs. Complicated and cranky.
679 elog_merge (elog_main_t * dst, u8 * dst_tag, elog_main_t * src, u8 * src_tag,
684 u32 string_table_offset_for_src_events;
685 u32 track_offset_for_src_tracks;
689 clib_memset (&newt, 0, sizeof (newt));
691 /* Acquire src and dst events */
692 elog_get_events (src);
693 elog_get_events (dst);
695 string_table_offset_for_src_events = vec_len (dst->string_table);
696 vec_append (dst->string_table, src->string_table);
698 l = vec_len (dst->events);
699 vec_append (dst->events, src->events);
701 /* Prepend the supplied tag (if any) to all dst track names */
704 for (i = 0; i < vec_len (dst->tracks); i++)
706 elog_track_t *t = vec_elt_at_index (dst->tracks, i);
709 new_name = (char *) format (0, "%s:%s%c", dst_tag, t->name, 0);
716 * Remember where we started allocating new tracks while merging
718 track_offset_for_src_tracks = vec_len (dst->tracks);
720 /* Copy / tag source tracks */
721 for (i = 0; i < vec_len (src->tracks); i++)
723 elog_track_t *t = vec_elt_at_index (src->tracks, i);
725 newt.name = (char *) format (0, "%s:%s%c", src_tag, t->name, 0);
727 newt.name = (char *) format (0, "%s%c", t->name, 0);
728 (void) elog_track_register (dst, &newt);
729 vec_free (newt.name);
732 /* Across all (copied) src events... */
733 for (e = dst->events + l; e < vec_end (dst->events); e++)
735 elog_event_type_t *t = vec_elt_at_index (src->event_types, e->type);
737 /* Remap type from src -> dst. */
738 e->type = find_or_create_type (dst, t);
740 /* Remap string table offsets for 'T' format args */
741 maybe_fix_string_table_offset (e, t,
742 string_table_offset_for_src_events);
745 e->track += track_offset_for_src_tracks;
748 /* Adjust event times for relative starting times of event streams. */
750 f64 dt_event, dt_os_nsec, dt_clock_nsec;
752 /* Set clock parameters if dst was not generated by unserialize. */
753 if (dst->serialize_time.cpu == 0)
755 dst->init_time = src->init_time;
756 dst->serialize_time = src->serialize_time;
757 dst->nsec_per_cpu_clock = src->nsec_per_cpu_clock;
761 elog_time_stamp_diff_os_nsec (&src->init_time, &dst->init_time);
763 dt_event = dt_os_nsec;
765 (elog_time_stamp_diff_cpu (&src->init_time, &dst->init_time) * .5 *
766 (dst->nsec_per_cpu_clock + src->nsec_per_cpu_clock));
769 * Heuristic to see if src/dst came from same time source.
770 * If frequencies are "the same" and os clock and cpu clock agree
771 * to within 100e-9 secs about time difference between src/dst
772 * init_time, then we use cpu clock. Otherwise we use OS clock.
774 * When merging event logs from different systems, time paradoxes
775 * at the O(1ms) level are to be expected. Hence, the "align_tweak"
776 * parameter. If two events logged on different processors are known
777 * to occur in a specific order - and with a reasonably-estimated
778 * interval - supply a non-zero "align_tweak" parameter
780 if (fabs (src->nsec_per_cpu_clock - dst->nsec_per_cpu_clock) < 1e-2
781 && fabs (dt_os_nsec - dt_clock_nsec) < 100)
782 dt_event = dt_clock_nsec;
784 /* Convert to seconds. */
788 * Move the earlier set of events later, to avoid creating
789 * events which precede the Big Bang (aka have negative timestamps).
791 * Not to any scale, we have something like the following picture:
793 * DST capture start point
797 * SRC capture start point
799 * In this case dt_event is positive, src started after dst,
800 * to put src events onto a common timebase we have to move them
801 * forward in time. Naturally, the opposite case is
802 * possible, too: dt_event will be negative, and so we have to
803 * move dst events forward in time by the |dt_event|.
804 * In both cases, we add align_tweak.
808 /* Src started after dst. */
809 for (e = dst->events + l; e < vec_end (dst->events); e++)
810 e->time += dt_event + align_tweak;
814 /* Dst started after src. */
815 dt_event = -dt_event;
816 for (e = dst->events + 0; e < dst->events + l; e++)
817 e->time += dt_event + align_tweak;
821 /* Sort events by increasing time. */
822 vec_sort_with_function (dst->events, elog_cmp);
824 dst->n_total_events = vec_len (dst->events);
826 /* Recreate the event ring or the results won't serialize */
830 ASSERT (dst->cpu_timer.seconds_per_clock);
832 elog_alloc (dst, vec_len (dst->events));
833 for (i = 0; i < vec_len (dst->events); i++)
835 elog_event_t *es, *ed;
837 es = dst->events + i;
838 ed = dst->event_ring + i;
846 serialize_elog_event (serialize_main_t * m, va_list * va)
848 elog_main_t *em = va_arg (*va, elog_main_t *);
849 elog_event_t *e = va_arg (*va, elog_event_t *);
850 elog_event_type_t *t = vec_elt_at_index (em->event_types, e->type);
852 u8 *p = (u8 *) t->format_args;
854 serialize_integer (m, e->type, sizeof (e->type));
855 serialize_integer (m, e->track, sizeof (e->track));
856 serialize (m, serialize_f64, e->time);
860 uword n_digits, n_bytes = 0;
862 n_digits = parse_2digit_decimal ((char *) p + 1, &n_bytes);
870 serialize_integer (m, d[0], sizeof (u8));
871 else if (n_bytes == 2)
872 serialize_integer (m, clib_mem_unaligned (d, u16), sizeof (u16));
873 else if (n_bytes == 4)
874 serialize_integer (m, clib_mem_unaligned (d, u32), sizeof (u32));
875 else if (n_bytes == 8)
876 serialize (m, serialize_64, clib_mem_unaligned (d, u64));
882 serialize_cstring (m, (char *) d);
884 n_bytes = strlen ((char *) d) + 1;
889 serialize (m, serialize_f32, clib_mem_unaligned (d, f32));
890 else if (n_bytes == 8)
891 serialize (m, serialize_f64, clib_mem_unaligned (d, f64));
907 unserialize_elog_event (serialize_main_t * m, va_list * va)
909 elog_main_t *em = va_arg (*va, elog_main_t *);
910 elog_event_t *e = va_arg (*va, elog_event_t *);
911 elog_event_type_t *t;
917 unserialize_integer (m, &tmp[0], sizeof (e->type));
918 unserialize_integer (m, &tmp[1], sizeof (e->track));
923 /* Make sure it fits. */
924 ASSERT (e->type == tmp[0]);
925 ASSERT (e->track == tmp[1]);
928 t = vec_elt_at_index (em->event_types, e->type);
930 unserialize (m, unserialize_f64, &e->time);
933 p = (u8 *) t->format_args;
937 uword n_digits, n_bytes = 0;
940 n_digits = parse_2digit_decimal ((char *) p + 1, &n_bytes);
949 unserialize_integer (m, &tmp, sizeof (u8));
952 else if (n_bytes == 2)
954 unserialize_integer (m, &tmp, sizeof (u16));
955 clib_mem_unaligned (d, u16) = tmp;
957 else if (n_bytes == 4)
959 unserialize_integer (m, &tmp, sizeof (u32));
960 clib_mem_unaligned (d, u32) = tmp;
962 else if (n_bytes == 8)
965 unserialize (m, unserialize_64, &x);
966 clib_mem_unaligned (d, u64) = x;
975 unserialize_cstring (m, &t);
977 n_bytes = strlen (t) + 1;
978 clib_memcpy (d, t, clib_min (n_bytes, vec_len (t)));
987 unserialize (m, unserialize_f32, &x);
988 clib_mem_unaligned (d, f32) = x;
990 else if (n_bytes == 8)
993 unserialize (m, unserialize_f64, &x);
994 clib_mem_unaligned (d, f64) = x;
1011 serialize_elog_event_type (serialize_main_t * m, va_list * va)
1013 elog_event_type_t *t = va_arg (*va, elog_event_type_t *);
1014 int n = va_arg (*va, int);
1016 for (i = 0; i < n; i++)
1018 serialize_cstring (m, t[i].format);
1019 serialize_cstring (m, t[i].format_args);
1020 serialize_integer (m, t[i].type_index_plus_one,
1021 sizeof (t->type_index_plus_one));
1022 serialize_integer (m, t[i].n_enum_strings,
1023 sizeof (t[i].n_enum_strings));
1024 for (j = 0; j < t[i].n_enum_strings; j++)
1025 serialize_cstring (m, t[i].enum_strings_vector[j]);
1030 unserialize_elog_event_type (serialize_main_t * m, va_list * va)
1032 elog_event_type_t *t = va_arg (*va, elog_event_type_t *);
1033 int n = va_arg (*va, int);
1035 for (i = 0; i < n; i++)
1037 unserialize_cstring (m, &t[i].format);
1038 unserialize_cstring (m, &t[i].format_args);
1039 unserialize_integer (m, &t[i].type_index_plus_one,
1040 sizeof (t->type_index_plus_one));
1041 unserialize_integer (m, &t[i].n_enum_strings,
1042 sizeof (t[i].n_enum_strings));
1043 vec_resize (t[i].enum_strings_vector, t[i].n_enum_strings);
1044 for (j = 0; j < t[i].n_enum_strings; j++)
1045 unserialize_cstring (m, &t[i].enum_strings_vector[j]);
1050 serialize_elog_track (serialize_main_t * m, va_list * va)
1052 elog_track_t *t = va_arg (*va, elog_track_t *);
1053 int n = va_arg (*va, int);
1055 for (i = 0; i < n; i++)
1057 serialize_cstring (m, t[i].name);
1062 unserialize_elog_track (serialize_main_t * m, va_list * va)
1064 elog_track_t *t = va_arg (*va, elog_track_t *);
1065 int n = va_arg (*va, int);
1067 for (i = 0; i < n; i++)
1069 unserialize_cstring (m, &t[i].name);
1074 serialize_elog_time_stamp (serialize_main_t * m, va_list * va)
1076 elog_time_stamp_t *st = va_arg (*va, elog_time_stamp_t *);
1077 serialize (m, serialize_64, st->os_nsec);
1078 serialize (m, serialize_64, st->cpu);
1082 unserialize_elog_time_stamp (serialize_main_t * m, va_list * va)
1084 elog_time_stamp_t *st = va_arg (*va, elog_time_stamp_t *);
1085 unserialize (m, unserialize_64, &st->os_nsec);
1086 unserialize (m, unserialize_64, &st->cpu);
1089 static char *elog_serialize_magic = "elog v0";
1092 serialize_elog_main (serialize_main_t * m, va_list * va)
1094 elog_main_t *em = va_arg (*va, elog_main_t *);
1095 int flush_ring = va_arg (*va, int);
1098 serialize_magic (m, elog_serialize_magic, strlen (elog_serialize_magic));
1100 serialize_integer (m, em->event_ring_size, sizeof (u32));
1102 elog_time_now (&em->serialize_time);
1103 serialize (m, serialize_elog_time_stamp, &em->serialize_time);
1104 serialize (m, serialize_elog_time_stamp, &em->init_time);
1106 vec_serialize (m, em->event_types, serialize_elog_event_type);
1107 vec_serialize (m, em->tracks, serialize_elog_track);
1108 vec_serialize (m, em->string_table, serialize_vec_8);
1110 /* Free old events (cached) in case they have changed. */
1113 vec_free (em->events);
1114 elog_get_events (em);
1117 serialize_integer (m, vec_len (em->events), sizeof (u32));
1119 /* SMP logs can easily have local time paradoxes... */
1120 vec_sort_with_function (em->events, elog_cmp);
1122 vec_foreach (e, em->events) serialize (m, serialize_elog_event, em, e);
1126 unserialize_elog_main (serialize_main_t * m, va_list * va)
1128 elog_main_t *em = va_arg (*va, elog_main_t *);
1132 unserialize_check_magic (m, elog_serialize_magic,
1133 strlen (elog_serialize_magic));
1135 unserialize_integer (m, &rs, sizeof (u32));
1136 em->event_ring_size = rs;
1137 elog_init (em, em->event_ring_size);
1139 unserialize (m, unserialize_elog_time_stamp, &em->serialize_time);
1140 unserialize (m, unserialize_elog_time_stamp, &em->init_time);
1141 em->nsec_per_cpu_clock = elog_nsec_per_clock (em);
1143 vec_unserialize (m, &em->event_types, unserialize_elog_event_type);
1144 for (i = 0; i < vec_len (em->event_types); i++)
1145 new_event_type (em, i);
1147 vec_unserialize (m, &em->tracks, unserialize_elog_track);
1148 vec_unserialize (m, &em->string_table, unserialize_vec_8);
1154 unserialize_integer (m, &ne, sizeof (u32));
1155 vec_resize (em->events, ne);
1156 vec_foreach (e, em->events)
1157 unserialize (m, unserialize_elog_event, em, e);
1162 * fd.io coding-style-patch-verification: ON
1165 * eval: (c-set-style "gnu")