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_MEMORY_BARRIER ();
64 /* Non-inline version. */
66 elog_event_data (elog_main_t * em,
67 elog_event_type_t * type, elog_track_t * track, u64 cpu_time)
69 return elog_event_data_inline (em, type, track, cpu_time);
73 new_event_type (elog_main_t * em, uword i)
75 elog_event_type_t *t = vec_elt_at_index (em->event_types, i);
77 if (!em->event_type_by_format)
78 em->event_type_by_format =
79 hash_create_vec ( /* size */ 0, sizeof (u8), sizeof (uword));
81 t->type_index_plus_one = i + 1;
82 hash_set_mem (em->event_type_by_format, t->format, i);
86 find_or_create_type (elog_main_t * em, elog_event_type_t * t)
88 uword *p = hash_get_mem (em->event_type_by_format, t->format);
95 i = vec_len (em->event_types);
96 vec_add1 (em->event_types, t[0]);
97 new_event_type (em, i);
103 /* External function to register types. */
105 elog_event_type_register (elog_main_t * em, elog_event_type_t * t)
107 elog_event_type_t *static_type = t;
112 /* Multiple simultaneous registration attempts, */
113 if (t->type_index_plus_one > 0)
116 return t->type_index_plus_one - 1;
119 l = vec_len (em->event_types);
121 t->type_index_plus_one = 1 + l;
125 /* If format args are not specified try to be smart about providing defaults
126 so most of the time user does not have to specify them. */
132 l = strlen (t->format);
133 for (i = 0; i < l; i++)
135 if (t->format[i] != '%')
139 if (t->format[i + 1] == '%') /* %% */
142 switch (t->format[i + 1])
148 this_arg = "i4"; /* size of u32 */
151 this_arg = "f8"; /* defaults to f64 */
154 this_arg = "s0"; /* defaults to null terminated string. */
159 (char *) format ((u8 *) t->format_args, "%s", this_arg);
162 /* Null terminate. */
163 vec_add1 (t->format_args, 0);
166 vec_add1 (em->event_types, t[0]);
168 t = em->event_types + l;
170 /* Make copies of strings for hashing etc. */
172 t->format = (char *) format (0, "%s %s%c", t->function, t->format, 0);
174 t->format = (char *) format (0, "%s%c", t->format, 0);
176 t->format_args = (char *) format (0, "%s%c", t->format_args, 0);
178 /* Construct string table. */
181 t->n_enum_strings = static_type->n_enum_strings;
182 for (i = 0; i < t->n_enum_strings; i++)
184 if (!static_type->enum_strings[i])
185 static_type->enum_strings[i] = "MISSING";
186 vec_add1 (t->enum_strings_vector,
187 (char *) format (0, "%s%c", static_type->enum_strings[i],
192 new_event_type (em, l);
199 elog_track_register (elog_main_t * em, elog_track_t * t)
205 l = vec_len (em->tracks);
207 t->track_index_plus_one = 1 + l;
211 vec_add1 (em->tracks, t[0]);
215 t->name = (char *) format (0, "%s%c", t->name, 0);
223 parse_2digit_decimal (char *p, uword * number)
228 digits[0] = digits[1] = 0;
229 while (p[i] >= '0' && p[i] <= '9')
233 digits[i] = p[i] - '0';
237 if (i >= 1 && i <= 2)
242 *number = 10 * digits[0] + digits[1];
250 fixed_format (u8 * s, char *fmt, char *result, uword * result_len)
260 if (f[0] == '%' && f[1] != '%')
265 vec_add (s, fmt, f - fmt);
273 /* Skip possible +-= justification. */
274 f += f[0] == '+' || f[0] == '-' || f[0] == '=';
276 /* Skip possible X.Y width. */
277 while ((f[0] >= '0' && f[0] <= '9') || f[0] == '.')
280 /* Skip wlL as in e.g. %Ld. */
281 f += f[0] == 'w' || f[0] == 'l' || f[0] == 'L';
283 /* Finally skip format letter. */
286 ASSERT (*result_len > f - percent);
287 l = clib_min (f - percent, *result_len - 1);
288 clib_memcpy (result, percent, l);
292 *result_len = f - fmt;
297 format_elog_event (u8 * s, va_list * va)
299 elog_main_t *em = va_arg (*va, elog_main_t *);
300 elog_event_t *e = va_arg (*va, elog_event_t *);
301 elog_event_type_t *t;
303 void *d = (u8 *) e->data;
306 t = vec_elt_at_index (em->event_types, e->type);
312 uword n_bytes = 0, n_digits, f_bytes = 0;
314 f_bytes = sizeof (arg_format);
315 s = fixed_format (s, f, arg_format, &f_bytes);
318 if (a == 0 || a[0] == 0)
320 /* Format must also be at end. */
325 /* Don't go past end of event data. */
326 ASSERT (d < (void *) (e->data + sizeof (e->data)));
328 n_digits = parse_2digit_decimal (a + 1, &n_bytes);
340 else if (n_bytes == 2)
341 i = clib_mem_unaligned (d, u16);
342 else if (n_bytes == 4)
343 i = clib_mem_unaligned (d, u32);
344 else if (n_bytes == 8)
345 l = clib_mem_unaligned (d, u64);
351 vec_elt (t->enum_strings_vector, n_bytes == 8 ? l : i);
352 s = format (s, arg_format, e);
354 else if (a[0] == 'T')
357 vec_elt_at_index (em->string_table, n_bytes == 8 ? l : i);
358 s = format (s, arg_format, e);
360 else if (n_bytes == 8)
361 s = format (s, arg_format, l);
363 s = format (s, arg_format, i);
371 x = clib_mem_unaligned (d, f32);
372 else if (n_bytes == 8)
373 x = clib_mem_unaligned (d, f64);
376 s = format (s, arg_format, x);
381 s = format (s, arg_format, d);
383 n_bytes = strlen (d) + 1;
391 ASSERT (n_digits > 0 && n_digits <= 2);
400 format_elog_track_name (u8 * s, va_list * va)
402 elog_main_t *em = va_arg (*va, elog_main_t *);
403 elog_event_t *e = va_arg (*va, elog_event_t *);
404 elog_track_t *t = vec_elt_at_index (em->tracks, e->track);
405 return format (s, "%s", t->name);
409 format_elog_track (u8 * s, va_list * args)
411 elog_main_t *em = va_arg (*args, elog_main_t *);
412 f64 dt = va_arg (*args, f64);
413 int track_index = va_arg (*args, int);
414 elog_event_t *e, *es;
417 indent = format_get_indent (s) + 1;
419 es = elog_peek_events (em);
422 if (e->track != track_index)
424 s = format (s, "%U%18.9f: %U\n", format_white_space, indent, e->time + dt,
425 format_elog_event, em, e);
432 elog_time_now (elog_time_stamp_t * et)
434 u64 cpu_time_now, os_time_now_nsec;
439 #include <sys/syscall.h>
441 clock_gettime (CLOCK_REALTIME, &ts);
443 syscall (SYS_clock_gettime, CLOCK_REALTIME, &ts);
445 cpu_time_now = clib_cpu_time_now ();
446 /* Subtract 3/30/2017's worth of seconds to retain precision */
447 os_time_now_nsec = 1e9 * (ts.tv_sec - 1490885108) + ts.tv_nsec;
450 cpu_time_now = clib_cpu_time_now ();
451 os_time_now_nsec = 0;
454 et->cpu = cpu_time_now;
455 et->os_nsec = os_time_now_nsec;
459 elog_time_stamp_diff_os_nsec (elog_time_stamp_t * t1, elog_time_stamp_t * t2)
461 return (i64) t1->os_nsec - (i64) t2->os_nsec;
465 elog_time_stamp_diff_cpu (elog_time_stamp_t * t1, elog_time_stamp_t * t2)
467 return (i64) t1->cpu - (i64) t2->cpu;
471 elog_nsec_per_clock (elog_main_t * em)
473 return ((f64) elog_time_stamp_diff_os_nsec (&em->serialize_time,
475 / (f64) elog_time_stamp_diff_cpu (&em->serialize_time,
480 elog_alloc (elog_main_t * em, u32 n_events)
483 vec_free (em->event_ring);
485 /* Ring size must be a power of 2. */
486 em->event_ring_size = n_events = max_pow2 (n_events);
488 /* Leave an empty ievent at end so we can always speculatively write
489 and event there (possibly a long form event). */
490 vec_resize_aligned (em->event_ring, n_events, CLIB_CACHE_LINE_BYTES);
494 elog_init (elog_main_t * em, u32 n_events)
496 clib_memset (em, 0, sizeof (em[0]));
501 elog_alloc (em, n_events);
503 clib_time_init (&em->cpu_timer);
505 em->n_total_events_disable_limit = ~0;
508 em->default_track.name = "default";
509 elog_track_register (em, &em->default_track);
511 elog_time_now (&em->init_time);
512 em->string_table_hash = hash_create_string (0, sizeof (uword));
515 /* Returns number of events in ring and start index. */
517 elog_event_range (elog_main_t * em, uword * lo)
519 uword l = em->event_ring_size;
520 u64 i = em->n_total_events;
522 /* Ring never wrapped? */
538 elog_peek_events (elog_main_t * em)
540 elog_event_t *e, *f, *es = 0;
543 n = elog_event_range (em, &j);
544 for (i = 0; i < n; i++)
547 f = vec_elt_at_index (em->event_ring, j);
550 /* Convert absolute time from cycles to seconds from start. */
553 em->init_time.cpu) * em->cpu_timer.seconds_per_clock;
555 j = (j + 1) & (em->event_ring_size - 1);
561 /* Add a formatted string to the string table. */
563 elog_string (elog_main_t * em, char *fmt, ...)
571 vec_reset_length (em->string_table_tmp);
573 em->string_table_tmp = va_format (em->string_table_tmp, fmt, &va);
576 /* String table entries MUST be NULL terminated */
577 len = vec_len (em->string_table_tmp);
579 if (em->string_table_tmp[len - 1] != 0)
580 vec_add1 (em->string_table_tmp, 0);
582 /* See if we already have this string in the string table */
583 p = hash_get_mem (em->string_table_hash, em->string_table_tmp);
585 /* We already have the string, so give the caller its offset */
592 /* We don't, so add it. */
594 offset = vec_len (em->string_table);
595 vec_append (em->string_table, em->string_table_tmp);
597 hash_set_mem (em->string_table_hash, em->string_table_tmp, offset);
599 /* We gave the key to the string table hash, so we can't reuse it! */
600 em->string_table_tmp = 0;
607 elog_get_events (elog_main_t * em)
610 em->events = elog_peek_events (em);
615 maybe_fix_string_table_offset (elog_event_t * e,
616 elog_event_type_t * t, u32 offset)
618 void *d = (u8 *) e->data;
628 uword n_bytes = 0, n_digits;
633 /* Don't go past end of event data. */
634 ASSERT (d < (void *) (e->data + sizeof (e->data)));
636 n_digits = parse_2digit_decimal (a + 1, &n_bytes);
640 ASSERT (n_bytes == 4);
641 clib_mem_unaligned (d, u32) += offset;
655 ASSERT (n_digits > 0 && n_digits <= 2);
662 elog_cmp (void *a1, void *a2)
664 elog_event_t *e1 = a1;
665 elog_event_t *e2 = a2;
667 if (e1->time < e2->time)
670 if (e1->time > e2->time)
677 * merge two event logs. Complicated and cranky.
680 elog_merge (elog_main_t * dst, u8 * dst_tag, elog_main_t * src, u8 * src_tag,
685 u32 string_table_offset_for_src_events;
686 u32 track_offset_for_src_tracks;
690 clib_memset (&newt, 0, sizeof (newt));
692 /* Acquire src and dst events */
693 elog_get_events (src);
694 elog_get_events (dst);
696 string_table_offset_for_src_events = vec_len (dst->string_table);
697 vec_append (dst->string_table, src->string_table);
699 l = vec_len (dst->events);
700 vec_append (dst->events, src->events);
702 /* Prepend the supplied tag (if any) to all dst track names */
705 for (i = 0; i < vec_len (dst->tracks); i++)
707 elog_track_t *t = vec_elt_at_index (dst->tracks, i);
710 new_name = (char *) format (0, "%s:%s%c", dst_tag, t->name, 0);
717 * Remember where we started allocating new tracks while merging
719 track_offset_for_src_tracks = vec_len (dst->tracks);
721 /* Copy / tag source tracks */
722 for (i = 0; i < vec_len (src->tracks); i++)
724 elog_track_t *t = vec_elt_at_index (src->tracks, i);
726 newt.name = (char *) format (0, "%s:%s%c", src_tag, t->name, 0);
728 newt.name = (char *) format (0, "%s%c", t->name, 0);
729 (void) elog_track_register (dst, &newt);
730 vec_free (newt.name);
733 /* Across all (copied) src events... */
734 for (e = dst->events + l; e < vec_end (dst->events); e++)
736 elog_event_type_t *t = vec_elt_at_index (src->event_types, e->type);
738 /* Remap type from src -> dst. */
739 e->type = find_or_create_type (dst, t);
741 /* Remap string table offsets for 'T' format args */
742 maybe_fix_string_table_offset (e, t,
743 string_table_offset_for_src_events);
746 e->track += track_offset_for_src_tracks;
749 /* Adjust event times for relative starting times of event streams. */
751 f64 dt_event, dt_os_nsec, dt_clock_nsec;
753 /* Set clock parameters if dst was not generated by unserialize. */
754 if (dst->serialize_time.cpu == 0)
756 dst->init_time = src->init_time;
757 dst->serialize_time = src->serialize_time;
758 dst->nsec_per_cpu_clock = src->nsec_per_cpu_clock;
762 elog_time_stamp_diff_os_nsec (&src->init_time, &dst->init_time);
764 dt_event = dt_os_nsec;
766 (elog_time_stamp_diff_cpu (&src->init_time, &dst->init_time) * .5 *
767 (dst->nsec_per_cpu_clock + src->nsec_per_cpu_clock));
770 * Heuristic to see if src/dst came from same time source.
771 * If frequencies are "the same" and os clock and cpu clock agree
772 * to within 100e-9 secs about time difference between src/dst
773 * init_time, then we use cpu clock. Otherwise we use OS clock.
775 * When merging event logs from different systems, time paradoxes
776 * at the O(1ms) level are to be expected. Hence, the "align_tweak"
777 * parameter. If two events logged on different processors are known
778 * to occur in a specific order - and with a reasonably-estimated
779 * interval - supply a non-zero "align_tweak" parameter
781 if (fabs (src->nsec_per_cpu_clock - dst->nsec_per_cpu_clock) < 1e-2
782 && fabs (dt_os_nsec - dt_clock_nsec) < 100)
783 dt_event = dt_clock_nsec;
785 /* Convert to seconds. */
789 * Move the earlier set of events later, to avoid creating
790 * events which precede the Big Bang (aka have negative timestamps).
792 * Not to any scale, we have something like the following picture:
794 * DST capture start point
798 * SRC capture start point
800 * In this case dt_event is positive, src started after dst,
801 * to put src events onto a common timebase we have to move them
802 * forward in time. Naturally, the opposite case is
803 * possible, too: dt_event will be negative, and so we have to
804 * move dst events forward in time by the |dt_event|.
805 * In both cases, we add align_tweak.
809 /* Src started after dst. */
810 for (e = dst->events + l; e < vec_end (dst->events); e++)
811 e->time += dt_event + align_tweak;
815 /* Dst started after src. */
816 dt_event = -dt_event;
817 for (e = dst->events + 0; e < dst->events + l; e++)
818 e->time += dt_event + align_tweak;
822 /* Sort events by increasing time. */
823 vec_sort_with_function (dst->events, elog_cmp);
825 dst->n_total_events = vec_len (dst->events);
827 /* Recreate the event ring or the results won't serialize */
831 ASSERT (dst->cpu_timer.seconds_per_clock);
833 elog_alloc (dst, vec_len (dst->events));
834 for (i = 0; i < vec_len (dst->events); i++)
836 elog_event_t *es, *ed;
838 es = dst->events + i;
839 ed = dst->event_ring + i;
847 serialize_elog_event (serialize_main_t * m, va_list * va)
849 elog_main_t *em = va_arg (*va, elog_main_t *);
850 elog_event_t *e = va_arg (*va, elog_event_t *);
851 elog_event_type_t *t = vec_elt_at_index (em->event_types, e->type);
853 u8 *p = (u8 *) t->format_args;
855 serialize_integer (m, e->type, sizeof (e->type));
856 serialize_integer (m, e->track, sizeof (e->track));
857 serialize (m, serialize_f64, e->time);
861 uword n_digits, n_bytes = 0;
863 n_digits = parse_2digit_decimal ((char *) p + 1, &n_bytes);
871 serialize_integer (m, d[0], sizeof (u8));
872 else if (n_bytes == 2)
873 serialize_integer (m, clib_mem_unaligned (d, u16), sizeof (u16));
874 else if (n_bytes == 4)
875 serialize_integer (m, clib_mem_unaligned (d, u32), sizeof (u32));
876 else if (n_bytes == 8)
877 serialize (m, serialize_64, clib_mem_unaligned (d, u64));
883 serialize_cstring (m, (char *) d);
885 n_bytes = strlen ((char *) d) + 1;
890 serialize (m, serialize_f32, clib_mem_unaligned (d, f32));
891 else if (n_bytes == 8)
892 serialize (m, serialize_f64, clib_mem_unaligned (d, f64));
908 unserialize_elog_event (serialize_main_t * m, va_list * va)
910 elog_main_t *em = va_arg (*va, elog_main_t *);
911 elog_event_t *e = va_arg (*va, elog_event_t *);
912 elog_event_type_t *t;
918 unserialize_integer (m, &tmp[0], sizeof (e->type));
919 unserialize_integer (m, &tmp[1], sizeof (e->track));
924 /* Make sure it fits. */
925 ASSERT (e->type == tmp[0]);
926 ASSERT (e->track == tmp[1]);
929 t = vec_elt_at_index (em->event_types, e->type);
931 unserialize (m, unserialize_f64, &e->time);
934 p = (u8 *) t->format_args;
938 uword n_digits, n_bytes = 0;
941 n_digits = parse_2digit_decimal ((char *) p + 1, &n_bytes);
950 unserialize_integer (m, &tmp, sizeof (u8));
953 else if (n_bytes == 2)
955 unserialize_integer (m, &tmp, sizeof (u16));
956 clib_mem_unaligned (d, u16) = tmp;
958 else if (n_bytes == 4)
960 unserialize_integer (m, &tmp, sizeof (u32));
961 clib_mem_unaligned (d, u32) = tmp;
963 else if (n_bytes == 8)
966 unserialize (m, unserialize_64, &x);
967 clib_mem_unaligned (d, u64) = x;
976 unserialize_cstring (m, &t);
978 n_bytes = strlen (t) + 1;
979 clib_memcpy (d, t, clib_min (n_bytes, vec_len (t)));
988 unserialize (m, unserialize_f32, &x);
989 clib_mem_unaligned (d, f32) = x;
991 else if (n_bytes == 8)
994 unserialize (m, unserialize_f64, &x);
995 clib_mem_unaligned (d, f64) = x;
1012 serialize_elog_event_type (serialize_main_t * m, va_list * va)
1014 elog_event_type_t *t = va_arg (*va, elog_event_type_t *);
1015 int n = va_arg (*va, int);
1017 for (i = 0; i < n; i++)
1019 serialize_cstring (m, t[i].format);
1020 serialize_cstring (m, t[i].format_args);
1021 serialize_integer (m, t[i].type_index_plus_one,
1022 sizeof (t->type_index_plus_one));
1023 serialize_integer (m, t[i].n_enum_strings,
1024 sizeof (t[i].n_enum_strings));
1025 for (j = 0; j < t[i].n_enum_strings; j++)
1026 serialize_cstring (m, t[i].enum_strings_vector[j]);
1031 unserialize_elog_event_type (serialize_main_t * m, va_list * va)
1033 elog_event_type_t *t = va_arg (*va, elog_event_type_t *);
1034 int n = va_arg (*va, int);
1036 for (i = 0; i < n; i++)
1038 unserialize_cstring (m, &t[i].format);
1039 unserialize_cstring (m, &t[i].format_args);
1040 unserialize_integer (m, &t[i].type_index_plus_one,
1041 sizeof (t->type_index_plus_one));
1042 unserialize_integer (m, &t[i].n_enum_strings,
1043 sizeof (t[i].n_enum_strings));
1044 vec_resize (t[i].enum_strings_vector, t[i].n_enum_strings);
1045 for (j = 0; j < t[i].n_enum_strings; j++)
1046 unserialize_cstring (m, &t[i].enum_strings_vector[j]);
1051 serialize_elog_track (serialize_main_t * m, va_list * va)
1053 elog_track_t *t = va_arg (*va, elog_track_t *);
1054 int n = va_arg (*va, int);
1056 for (i = 0; i < n; i++)
1058 serialize_cstring (m, t[i].name);
1063 unserialize_elog_track (serialize_main_t * m, va_list * va)
1065 elog_track_t *t = va_arg (*va, elog_track_t *);
1066 int n = va_arg (*va, int);
1068 for (i = 0; i < n; i++)
1070 unserialize_cstring (m, &t[i].name);
1075 serialize_elog_time_stamp (serialize_main_t * m, va_list * va)
1077 elog_time_stamp_t *st = va_arg (*va, elog_time_stamp_t *);
1078 serialize (m, serialize_64, st->os_nsec);
1079 serialize (m, serialize_64, st->cpu);
1083 unserialize_elog_time_stamp (serialize_main_t * m, va_list * va)
1085 elog_time_stamp_t *st = va_arg (*va, elog_time_stamp_t *);
1086 unserialize (m, unserialize_64, &st->os_nsec);
1087 unserialize (m, unserialize_64, &st->cpu);
1090 static char *elog_serialize_magic = "elog v0";
1093 serialize_elog_main (serialize_main_t * m, va_list * va)
1095 elog_main_t *em = va_arg (*va, elog_main_t *);
1096 int flush_ring = va_arg (*va, int);
1099 serialize_magic (m, elog_serialize_magic, strlen (elog_serialize_magic));
1101 serialize_integer (m, em->event_ring_size, sizeof (u32));
1103 elog_time_now (&em->serialize_time);
1104 serialize (m, serialize_elog_time_stamp, &em->serialize_time);
1105 serialize (m, serialize_elog_time_stamp, &em->init_time);
1107 vec_serialize (m, em->event_types, serialize_elog_event_type);
1108 vec_serialize (m, em->tracks, serialize_elog_track);
1109 vec_serialize (m, em->string_table, serialize_vec_8);
1111 /* Free old events (cached) in case they have changed. */
1114 vec_free (em->events);
1115 elog_get_events (em);
1118 serialize_integer (m, vec_len (em->events), sizeof (u32));
1120 /* SMP logs can easily have local time paradoxes... */
1121 vec_sort_with_function (em->events, elog_cmp);
1123 vec_foreach (e, em->events) serialize (m, serialize_elog_event, em, e);
1127 unserialize_elog_main (serialize_main_t * m, va_list * va)
1129 elog_main_t *em = va_arg (*va, elog_main_t *);
1133 unserialize_check_magic (m, elog_serialize_magic,
1134 strlen (elog_serialize_magic));
1136 unserialize_integer (m, &rs, sizeof (u32));
1137 em->event_ring_size = rs;
1138 elog_init (em, em->event_ring_size);
1140 unserialize (m, unserialize_elog_time_stamp, &em->serialize_time);
1141 unserialize (m, unserialize_elog_time_stamp, &em->init_time);
1142 em->nsec_per_cpu_clock = elog_nsec_per_clock (em);
1144 vec_unserialize (m, &em->event_types, unserialize_elog_event_type);
1145 for (i = 0; i < vec_len (em->event_types); i++)
1146 new_event_type (em, i);
1148 vec_unserialize (m, &em->tracks, unserialize_elog_track);
1149 vec_unserialize (m, &em->string_table, unserialize_vec_8);
1155 unserialize_integer (m, &ne, sizeof (u32));
1156 vec_resize (em->events, ne);
1157 vec_foreach (e, em->events)
1158 unserialize (m, unserialize_elog_event, em, e);
1163 * fd.io coding-style-patch-verification: ON
1166 * eval: (c-set-style "gnu")