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->event_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,
424 e->time + dt, 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 =
736 vec_elt_at_index (src->event_types, e->event_type);
738 /* Remap type from src -> dst. */
739 e->event_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->event_type);
853 u8 *p = (u8 *) t->format_args;
855 serialize_integer (m, e->event_type, sizeof (e->event_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->event_type));
919 unserialize_integer (m, &tmp[1], sizeof (e->track));
921 e->event_type = tmp[0];
924 /* Make sure it fits. */
925 ASSERT (e->event_type == tmp[0]);
926 ASSERT (e->track == tmp[1]);
929 t = vec_elt_at_index (em->event_types, e->event_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);
1164 elog_write_file_not_inline (elog_main_t * em, char *clib_file, int flush_ring)
1167 clib_error_t *error;
1169 error = serialize_open_clib_file (&m, clib_file);
1172 error = serialize (&m, serialize_elog_main, em, flush_ring);
1174 serialize_close (&m);
1179 elog_read_file_not_inline (elog_main_t * em, char *clib_file)
1182 clib_error_t *error;
1184 error = unserialize_open_clib_file (&m, clib_file);
1187 error = unserialize (&m, unserialize_elog_main, em);
1189 unserialize_close (&m);
1192 #endif /* CLIB_UNIX */
1196 * fd.io coding-style-patch-verification: ON
1199 * eval: (c-set-style "gnu")