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 format_one_elog_event (void *em_arg, void *ep_arg)
433 elog_main_t *em = (elog_main_t *) em_arg;
434 elog_event_t *ep = (elog_event_t *) ep_arg;
436 return (char *) format (0, "%U", format_elog_event, em, ep);
440 elog_time_now (elog_time_stamp_t * et)
442 u64 cpu_time_now, os_time_now_nsec;
447 #include <sys/syscall.h>
449 clock_gettime (CLOCK_REALTIME, &ts);
451 syscall (SYS_clock_gettime, CLOCK_REALTIME, &ts);
453 cpu_time_now = clib_cpu_time_now ();
454 /* Subtract 3/30/2017's worth of seconds to retain precision */
455 os_time_now_nsec = 1e9 * (ts.tv_sec - 1490885108) + ts.tv_nsec;
458 cpu_time_now = clib_cpu_time_now ();
459 os_time_now_nsec = 0;
462 et->cpu = cpu_time_now;
463 et->os_nsec = os_time_now_nsec;
467 elog_time_stamp_diff_os_nsec (elog_time_stamp_t * t1, elog_time_stamp_t * t2)
469 return (i64) t1->os_nsec - (i64) t2->os_nsec;
473 elog_time_stamp_diff_cpu (elog_time_stamp_t * t1, elog_time_stamp_t * t2)
475 return (i64) t1->cpu - (i64) t2->cpu;
479 elog_nsec_per_clock (elog_main_t * em)
481 return ((f64) elog_time_stamp_diff_os_nsec (&em->serialize_time,
483 / (f64) elog_time_stamp_diff_cpu (&em->serialize_time,
488 elog_alloc (elog_main_t * em, u32 n_events)
491 vec_free (em->event_ring);
493 /* Ring size must be a power of 2. */
494 em->event_ring_size = n_events = max_pow2 (n_events);
496 /* Leave an empty ievent at end so we can always speculatively write
497 and event there (possibly a long form event). */
498 vec_resize_aligned (em->event_ring, n_events, CLIB_CACHE_LINE_BYTES);
502 elog_init (elog_main_t * em, u32 n_events)
504 clib_memset (em, 0, sizeof (em[0]));
509 elog_alloc (em, n_events);
511 clib_time_init (&em->cpu_timer);
513 em->n_total_events_disable_limit = ~0;
516 em->default_track.name = "default";
517 elog_track_register (em, &em->default_track);
519 elog_time_now (&em->init_time);
520 em->string_table_hash = hash_create_string (0, sizeof (uword));
523 /* Returns number of events in ring and start index. */
525 elog_event_range (elog_main_t * em, uword * lo)
527 uword l = em->event_ring_size;
528 u64 i = em->n_total_events;
530 /* Ring never wrapped? */
546 elog_peek_events (elog_main_t * em)
548 elog_event_t *e, *f, *es = 0;
551 n = elog_event_range (em, &j);
552 for (i = 0; i < n; i++)
555 f = vec_elt_at_index (em->event_ring, j);
558 /* Convert absolute time from cycles to seconds from start. */
561 em->init_time.cpu) * em->cpu_timer.seconds_per_clock;
563 j = (j + 1) & (em->event_ring_size - 1);
569 /* Add a formatted string to the string table. */
571 elog_string (elog_main_t * em, char *fmt, ...)
579 vec_reset_length (em->string_table_tmp);
581 em->string_table_tmp = va_format (em->string_table_tmp, fmt, &va);
584 /* String table entries MUST be NULL terminated */
585 len = vec_len (em->string_table_tmp);
587 if (em->string_table_tmp[len - 1] != 0)
588 vec_add1 (em->string_table_tmp, 0);
590 /* See if we already have this string in the string table */
591 p = hash_get_mem (em->string_table_hash, em->string_table_tmp);
593 /* We already have the string, so give the caller its offset */
600 /* We don't, so add it. */
602 offset = vec_len (em->string_table);
603 vec_append (em->string_table, em->string_table_tmp);
605 hash_set_mem (em->string_table_hash, em->string_table_tmp, offset);
607 /* We gave the key to the string table hash, so we can't reuse it! */
608 em->string_table_tmp = 0;
615 elog_get_events (elog_main_t * em)
618 em->events = elog_peek_events (em);
623 maybe_fix_string_table_offset (elog_event_t * e,
624 elog_event_type_t * t, u32 offset)
626 void *d = (u8 *) e->data;
636 uword n_bytes = 0, n_digits;
641 /* Don't go past end of event data. */
642 ASSERT (d < (void *) (e->data + sizeof (e->data)));
644 n_digits = parse_2digit_decimal (a + 1, &n_bytes);
648 ASSERT (n_bytes == 4);
649 clib_mem_unaligned (d, u32) += offset;
663 ASSERT (n_digits > 0 && n_digits <= 2);
670 elog_cmp (void *a1, void *a2)
672 elog_event_t *e1 = a1;
673 elog_event_t *e2 = a2;
675 if (e1->time < e2->time)
678 if (e1->time > e2->time)
685 * merge two event logs. Complicated and cranky.
688 elog_merge (elog_main_t * dst, u8 * dst_tag, elog_main_t * src, u8 * src_tag,
693 u32 string_table_offset_for_src_events;
694 u32 track_offset_for_src_tracks;
698 clib_memset (&newt, 0, sizeof (newt));
700 /* Acquire src and dst events */
701 elog_get_events (src);
702 elog_get_events (dst);
704 string_table_offset_for_src_events = vec_len (dst->string_table);
705 vec_append (dst->string_table, src->string_table);
707 l = vec_len (dst->events);
708 vec_append (dst->events, src->events);
710 /* Prepend the supplied tag (if any) to all dst track names */
713 for (i = 0; i < vec_len (dst->tracks); i++)
715 elog_track_t *t = vec_elt_at_index (dst->tracks, i);
718 new_name = (char *) format (0, "%s:%s%c", dst_tag, t->name, 0);
725 * Remember where we started allocating new tracks while merging
727 track_offset_for_src_tracks = vec_len (dst->tracks);
729 /* Copy / tag source tracks */
730 for (i = 0; i < vec_len (src->tracks); i++)
732 elog_track_t *t = vec_elt_at_index (src->tracks, i);
734 newt.name = (char *) format (0, "%s:%s%c", src_tag, t->name, 0);
736 newt.name = (char *) format (0, "%s%c", t->name, 0);
737 (void) elog_track_register (dst, &newt);
738 vec_free (newt.name);
741 /* Across all (copied) src events... */
742 for (e = dst->events + l; e < vec_end (dst->events); e++)
744 elog_event_type_t *t =
745 vec_elt_at_index (src->event_types, e->event_type);
747 /* Remap type from src -> dst. */
748 e->event_type = find_or_create_type (dst, t);
750 /* Remap string table offsets for 'T' format args */
751 maybe_fix_string_table_offset (e, t,
752 string_table_offset_for_src_events);
755 e->track += track_offset_for_src_tracks;
758 /* Adjust event times for relative starting times of event streams. */
760 f64 dt_event, dt_os_nsec, dt_clock_nsec;
762 /* Set clock parameters if dst was not generated by unserialize. */
763 if (dst->serialize_time.cpu == 0)
765 dst->init_time = src->init_time;
766 dst->serialize_time = src->serialize_time;
767 dst->nsec_per_cpu_clock = src->nsec_per_cpu_clock;
771 elog_time_stamp_diff_os_nsec (&src->init_time, &dst->init_time);
773 dt_event = dt_os_nsec;
775 (elog_time_stamp_diff_cpu (&src->init_time, &dst->init_time) * .5 *
776 (dst->nsec_per_cpu_clock + src->nsec_per_cpu_clock));
779 * Heuristic to see if src/dst came from same time source.
780 * If frequencies are "the same" and os clock and cpu clock agree
781 * to within 100e-9 secs about time difference between src/dst
782 * init_time, then we use cpu clock. Otherwise we use OS clock.
784 * When merging event logs from different systems, time paradoxes
785 * at the O(1ms) level are to be expected. Hence, the "align_tweak"
786 * parameter. If two events logged on different processors are known
787 * to occur in a specific order - and with a reasonably-estimated
788 * interval - supply a non-zero "align_tweak" parameter
790 if (fabs (src->nsec_per_cpu_clock - dst->nsec_per_cpu_clock) < 1e-2
791 && fabs (dt_os_nsec - dt_clock_nsec) < 100)
792 dt_event = dt_clock_nsec;
794 /* Convert to seconds. */
798 * Move the earlier set of events later, to avoid creating
799 * events which precede the Big Bang (aka have negative timestamps).
801 * Not to any scale, we have something like the following picture:
803 * DST capture start point
807 * SRC capture start point
809 * In this case dt_event is positive, src started after dst,
810 * to put src events onto a common timebase we have to move them
811 * forward in time. Naturally, the opposite case is
812 * possible, too: dt_event will be negative, and so we have to
813 * move dst events forward in time by the |dt_event|.
814 * In both cases, we add align_tweak.
818 /* Src started after dst. */
819 for (e = dst->events + l; e < vec_end (dst->events); e++)
820 e->time += dt_event + align_tweak;
824 /* Dst started after src. */
825 dt_event = -dt_event;
826 for (e = dst->events + 0; e < dst->events + l; e++)
827 e->time += dt_event + align_tweak;
831 /* Sort events by increasing time. */
832 vec_sort_with_function (dst->events, elog_cmp);
834 dst->n_total_events = vec_len (dst->events);
836 /* Recreate the event ring or the results won't serialize */
840 ASSERT (dst->cpu_timer.seconds_per_clock);
842 elog_alloc (dst, vec_len (dst->events));
843 for (i = 0; i < vec_len (dst->events); i++)
845 elog_event_t *es, *ed;
847 es = dst->events + i;
848 ed = dst->event_ring + i;
856 serialize_elog_event (serialize_main_t * m, va_list * va)
858 elog_main_t *em = va_arg (*va, elog_main_t *);
859 elog_event_t *e = va_arg (*va, elog_event_t *);
860 elog_event_type_t *t = vec_elt_at_index (em->event_types, e->event_type);
862 u8 *p = (u8 *) t->format_args;
864 serialize_integer (m, e->event_type, sizeof (e->event_type));
865 serialize_integer (m, e->track, sizeof (e->track));
866 serialize (m, serialize_f64, e->time);
870 uword n_digits, n_bytes = 0;
872 n_digits = parse_2digit_decimal ((char *) p + 1, &n_bytes);
880 serialize_integer (m, d[0], sizeof (u8));
881 else if (n_bytes == 2)
882 serialize_integer (m, clib_mem_unaligned (d, u16), sizeof (u16));
883 else if (n_bytes == 4)
884 serialize_integer (m, clib_mem_unaligned (d, u32), sizeof (u32));
885 else if (n_bytes == 8)
886 serialize (m, serialize_64, clib_mem_unaligned (d, u64));
892 serialize_cstring (m, (char *) d);
894 n_bytes = strlen ((char *) d) + 1;
899 serialize (m, serialize_f32, clib_mem_unaligned (d, f32));
900 else if (n_bytes == 8)
901 serialize (m, serialize_f64, clib_mem_unaligned (d, f64));
917 unserialize_elog_event (serialize_main_t * m, va_list * va)
919 elog_main_t *em = va_arg (*va, elog_main_t *);
920 elog_event_t *e = va_arg (*va, elog_event_t *);
921 elog_event_type_t *t;
927 unserialize_integer (m, &tmp[0], sizeof (e->event_type));
928 unserialize_integer (m, &tmp[1], sizeof (e->track));
930 e->event_type = tmp[0];
933 /* Make sure it fits. */
934 ASSERT (e->event_type == tmp[0]);
935 ASSERT (e->track == tmp[1]);
938 t = vec_elt_at_index (em->event_types, e->event_type);
940 unserialize (m, unserialize_f64, &e->time);
943 p = (u8 *) t->format_args;
947 uword n_digits, n_bytes = 0;
950 n_digits = parse_2digit_decimal ((char *) p + 1, &n_bytes);
959 unserialize_integer (m, &tmp, sizeof (u8));
962 else if (n_bytes == 2)
964 unserialize_integer (m, &tmp, sizeof (u16));
965 clib_mem_unaligned (d, u16) = tmp;
967 else if (n_bytes == 4)
969 unserialize_integer (m, &tmp, sizeof (u32));
970 clib_mem_unaligned (d, u32) = tmp;
972 else if (n_bytes == 8)
975 unserialize (m, unserialize_64, &x);
976 clib_mem_unaligned (d, u64) = x;
985 unserialize_cstring (m, &t);
987 n_bytes = strlen (t) + 1;
988 clib_memcpy (d, t, clib_min (n_bytes, vec_len (t)));
997 unserialize (m, unserialize_f32, &x);
998 clib_mem_unaligned (d, f32) = x;
1000 else if (n_bytes == 8)
1003 unserialize (m, unserialize_f64, &x);
1004 clib_mem_unaligned (d, f64) = x;
1021 serialize_elog_event_type (serialize_main_t * m, va_list * va)
1023 elog_event_type_t *t = va_arg (*va, elog_event_type_t *);
1024 int n = va_arg (*va, int);
1026 for (i = 0; i < n; i++)
1028 serialize_cstring (m, t[i].format);
1029 serialize_cstring (m, t[i].format_args);
1030 serialize_integer (m, t[i].type_index_plus_one,
1031 sizeof (t->type_index_plus_one));
1032 serialize_integer (m, t[i].n_enum_strings,
1033 sizeof (t[i].n_enum_strings));
1034 for (j = 0; j < t[i].n_enum_strings; j++)
1035 serialize_cstring (m, t[i].enum_strings_vector[j]);
1040 unserialize_elog_event_type (serialize_main_t * m, va_list * va)
1042 elog_event_type_t *t = va_arg (*va, elog_event_type_t *);
1043 int n = va_arg (*va, int);
1045 for (i = 0; i < n; i++)
1047 unserialize_cstring (m, &t[i].format);
1048 unserialize_cstring (m, &t[i].format_args);
1049 unserialize_integer (m, &t[i].type_index_plus_one,
1050 sizeof (t->type_index_plus_one));
1051 unserialize_integer (m, &t[i].n_enum_strings,
1052 sizeof (t[i].n_enum_strings));
1053 vec_resize (t[i].enum_strings_vector, t[i].n_enum_strings);
1054 for (j = 0; j < t[i].n_enum_strings; j++)
1055 unserialize_cstring (m, &t[i].enum_strings_vector[j]);
1060 serialize_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 serialize_cstring (m, t[i].name);
1072 unserialize_elog_track (serialize_main_t * m, va_list * va)
1074 elog_track_t *t = va_arg (*va, elog_track_t *);
1075 int n = va_arg (*va, int);
1077 for (i = 0; i < n; i++)
1079 unserialize_cstring (m, &t[i].name);
1084 serialize_elog_time_stamp (serialize_main_t * m, va_list * va)
1086 elog_time_stamp_t *st = va_arg (*va, elog_time_stamp_t *);
1087 serialize (m, serialize_64, st->os_nsec);
1088 serialize (m, serialize_64, st->cpu);
1092 unserialize_elog_time_stamp (serialize_main_t * m, va_list * va)
1094 elog_time_stamp_t *st = va_arg (*va, elog_time_stamp_t *);
1095 unserialize (m, unserialize_64, &st->os_nsec);
1096 unserialize (m, unserialize_64, &st->cpu);
1099 static char *elog_serialize_magic = "elog v0";
1102 serialize_elog_main (serialize_main_t * m, va_list * va)
1104 elog_main_t *em = va_arg (*va, elog_main_t *);
1105 int flush_ring = va_arg (*va, int);
1108 serialize_magic (m, elog_serialize_magic, strlen (elog_serialize_magic));
1110 serialize_integer (m, em->event_ring_size, sizeof (u32));
1112 elog_time_now (&em->serialize_time);
1113 serialize (m, serialize_elog_time_stamp, &em->serialize_time);
1114 serialize (m, serialize_elog_time_stamp, &em->init_time);
1116 vec_serialize (m, em->event_types, serialize_elog_event_type);
1117 vec_serialize (m, em->tracks, serialize_elog_track);
1118 vec_serialize (m, em->string_table, serialize_vec_8);
1120 /* Free old events (cached) in case they have changed. */
1123 vec_free (em->events);
1124 elog_get_events (em);
1127 serialize_integer (m, vec_len (em->events), sizeof (u32));
1129 /* SMP logs can easily have local time paradoxes... */
1130 vec_sort_with_function (em->events, elog_cmp);
1132 vec_foreach (e, em->events) serialize (m, serialize_elog_event, em, e);
1136 unserialize_elog_main (serialize_main_t * m, va_list * va)
1138 elog_main_t *em = va_arg (*va, elog_main_t *);
1142 unserialize_check_magic (m, elog_serialize_magic,
1143 strlen (elog_serialize_magic));
1145 unserialize_integer (m, &rs, sizeof (u32));
1146 em->event_ring_size = rs;
1147 elog_init (em, em->event_ring_size);
1149 unserialize (m, unserialize_elog_time_stamp, &em->serialize_time);
1150 unserialize (m, unserialize_elog_time_stamp, &em->init_time);
1151 em->nsec_per_cpu_clock = elog_nsec_per_clock (em);
1153 vec_unserialize (m, &em->event_types, unserialize_elog_event_type);
1154 for (i = 0; i < vec_len (em->event_types); i++)
1155 new_event_type (em, i);
1157 vec_unserialize (m, &em->tracks, unserialize_elog_track);
1158 vec_unserialize (m, &em->string_table, unserialize_vec_8);
1164 unserialize_integer (m, &ne, sizeof (u32));
1165 vec_resize (em->events, ne);
1166 vec_foreach (e, em->events)
1167 unserialize (m, unserialize_elog_event, em, e);
1173 elog_write_file_not_inline (elog_main_t * em, char *clib_file, int flush_ring)
1176 clib_error_t *error;
1178 error = serialize_open_clib_file (&m, clib_file);
1181 error = serialize (&m, serialize_elog_main, em, flush_ring);
1183 serialize_close (&m);
1188 elog_read_file_not_inline (elog_main_t * em, char *clib_file)
1191 clib_error_t *error;
1193 error = unserialize_open_clib_file (&m, clib_file);
1196 error = unserialize (&m, unserialize_elog_main, em);
1198 unserialize_close (&m);
1201 #endif /* CLIB_UNIX */
1205 * fd.io coding-style-patch-verification: ON
1208 * eval: (c-set-style "gnu")