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_internal (elog_main_t * em, u32 n_events, int free_ring)
490 if (free_ring && em->event_ring)
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 vec_validate_aligned (em->event_ring, n_events, CLIB_CACHE_LINE_BYTES);
497 vec_set_len (em->event_ring, n_events);
501 elog_alloc (elog_main_t * em, u32 n_events)
503 elog_alloc_internal (em, n_events, 1 /* free ring */ );
507 elog_resize (elog_main_t * em, u32 n_events)
509 elog_alloc_internal (em, n_events, 0 /* do not free ring */ );
513 elog_init (elog_main_t * em, u32 n_events)
515 clib_memset (em, 0, sizeof (em[0]));
520 elog_alloc (em, n_events);
522 clib_time_init (&em->cpu_timer);
524 em->n_total_events_disable_limit = ~0;
527 em->default_track.name = "default";
528 elog_track_register (em, &em->default_track);
530 elog_time_now (&em->init_time);
531 em->string_table_hash = hash_create_string (0, sizeof (uword));
534 /* Returns number of events in ring and start index. */
536 elog_event_range (elog_main_t * em, uword * lo)
538 uword l = em->event_ring_size;
539 u64 i = em->n_total_events;
541 /* Ring never wrapped? */
556 __clib_export elog_event_t *
557 elog_peek_events (elog_main_t * em)
559 elog_event_t *e, *f, *es = 0;
562 n = elog_event_range (em, &j);
563 for (i = 0; i < n; i++)
566 f = vec_elt_at_index (em->event_ring, j);
569 /* Convert absolute time from cycles to seconds from start. */
572 em->init_time.cpu) * em->cpu_timer.seconds_per_clock;
574 j = (j + 1) & (em->event_ring_size - 1);
580 /* Add a formatted string to the string table. */
582 elog_string (elog_main_t * em, char *fmt, ...)
590 vec_reset_length (em->string_table_tmp);
592 em->string_table_tmp = va_format (em->string_table_tmp, fmt, &va);
595 /* String table entries MUST be NULL terminated */
596 len = vec_len (em->string_table_tmp);
598 if (em->string_table_tmp[len - 1] != 0)
599 vec_add1 (em->string_table_tmp, 0);
601 /* See if we already have this string in the string table */
602 p = hash_get_mem (em->string_table_hash, em->string_table_tmp);
604 /* We already have the string, so give the caller its offset */
611 /* We don't, so add it. */
613 offset = vec_len (em->string_table);
614 vec_append (em->string_table, em->string_table_tmp);
616 hash_set_mem (em->string_table_hash, em->string_table_tmp, offset);
618 /* We gave the key to the string table hash, so we can't reuse it! */
619 em->string_table_tmp = 0;
625 __clib_export elog_event_t *
626 elog_get_events (elog_main_t * em)
628 vec_free (em->events);
629 em->events = elog_peek_events (em);
634 maybe_fix_string_table_offset (elog_event_t * e,
635 elog_event_type_t * t, u32 offset)
637 void *d = (u8 *) e->data;
647 uword n_bytes = 0, n_digits;
652 /* Don't go past end of event data. */
653 ASSERT (d < (void *) (e->data + sizeof (e->data)));
655 n_digits = parse_2digit_decimal (a + 1, &n_bytes);
659 ASSERT (n_bytes == 4);
660 clib_mem_unaligned (d, u32) += offset;
674 ASSERT (n_digits > 0 && n_digits <= 2);
681 elog_cmp (void *a1, void *a2)
683 elog_event_t *e1 = a1;
684 elog_event_t *e2 = a2;
686 if (e1->time < e2->time)
689 if (e1->time > e2->time)
696 * merge two event logs. Complicated and cranky.
699 elog_merge (elog_main_t *dst, u8 *dst_tag, elog_main_t *src, u8 *src_tag,
704 u32 string_table_offset_for_src_events;
705 u32 track_offset_for_src_tracks;
709 clib_memset (&newt, 0, sizeof (newt));
711 /* Acquire src and dst events */
712 elog_get_events (src);
713 elog_get_events (dst);
715 string_table_offset_for_src_events = vec_len (dst->string_table);
716 vec_append (dst->string_table, src->string_table);
718 l = vec_len (dst->events);
719 vec_append (dst->events, src->events);
721 /* Prepend the supplied tag (if any) to all dst track names */
724 for (i = 0; i < vec_len (dst->tracks); i++)
726 elog_track_t *t = vec_elt_at_index (dst->tracks, i);
729 new_name = (char *) format (0, "%s:%s%c", dst_tag, t->name, 0);
736 * Remember where we started allocating new tracks while merging
738 track_offset_for_src_tracks = vec_len (dst->tracks);
740 /* Copy / tag source tracks */
741 for (i = 0; i < vec_len (src->tracks); i++)
743 elog_track_t *t = vec_elt_at_index (src->tracks, i);
745 newt.name = (char *) format (0, "%s:%s%c", src_tag, t->name, 0);
747 newt.name = (char *) format (0, "%s%c", t->name, 0);
748 (void) elog_track_register (dst, &newt);
749 vec_free (newt.name);
752 /* Across all (copied) src events... */
753 for (e = dst->events + l; e < vec_end (dst->events); e++)
755 elog_event_type_t *t =
756 vec_elt_at_index (src->event_types, e->event_type);
758 /* Remap type from src -> dst. */
759 e->event_type = find_or_create_type (dst, t);
761 /* Remap string table offsets for 'T' format args */
762 maybe_fix_string_table_offset (e, t,
763 string_table_offset_for_src_events);
766 e->track += track_offset_for_src_tracks;
769 /* Adjust event times for relative starting times of event streams. */
771 f64 dt_event, dt_os_nsec, dt_clock_nsec;
773 /* Set clock parameters if dst was not generated by unserialize. */
774 if (dst->serialize_time.cpu == 0)
776 dst->init_time = src->init_time;
777 dst->serialize_time = src->serialize_time;
778 dst->nsec_per_cpu_clock = src->nsec_per_cpu_clock;
782 elog_time_stamp_diff_os_nsec (&src->init_time, &dst->init_time);
784 dt_event = dt_os_nsec;
786 (elog_time_stamp_diff_cpu (&src->init_time, &dst->init_time) * .5 *
787 (dst->nsec_per_cpu_clock + src->nsec_per_cpu_clock));
790 * Heuristic to see if src/dst came from same time source.
791 * If frequencies are "the same" and os clock and cpu clock agree
792 * to within 100e-9 secs about time difference between src/dst
793 * init_time, then we use cpu clock. Otherwise we use OS clock.
795 * When merging event logs from different systems, time paradoxes
796 * at the O(1ms) level are to be expected. Hence, the "align_tweak"
797 * parameter. If two events logged on different processors are known
798 * to occur in a specific order - and with a reasonably-estimated
799 * interval - supply a non-zero "align_tweak" parameter
801 if (fabs (src->nsec_per_cpu_clock - dst->nsec_per_cpu_clock) < 1e-2
802 && fabs (dt_os_nsec - dt_clock_nsec) < 100)
803 dt_event = dt_clock_nsec;
805 /* Convert to seconds. */
809 * Move the earlier set of events later, to avoid creating
810 * events which precede the Big Bang (aka have negative timestamps).
812 * Not to any scale, we have something like the following picture:
814 * DST capture start point
818 * SRC capture start point
820 * In this case dt_event is positive, src started after dst,
821 * to put src events onto a common timebase we have to move them
822 * forward in time. Naturally, the opposite case is
823 * possible, too: dt_event will be negative, and so we have to
824 * move dst events forward in time by the |dt_event|.
825 * In both cases, we add align_tweak.
829 /* Src started after dst. */
830 for (e = dst->events + l; e < vec_end (dst->events); e++)
831 e->time += dt_event + align_tweak;
835 /* Dst started after src. */
836 dt_event = -dt_event;
837 for (e = dst->events + 0; e < dst->events + l; e++)
838 e->time += dt_event + align_tweak;
842 /* Sort events by increasing time. */
843 vec_sort_with_function (dst->events, elog_cmp);
845 dst->n_total_events = vec_len (dst->events);
847 /* Recreate the event ring or the results won't serialize */
851 ASSERT (dst->cpu_timer.seconds_per_clock);
853 elog_alloc (dst, vec_len (dst->events));
854 for (i = 0; i < vec_len (dst->events); i++)
856 elog_event_t *es, *ed;
858 es = dst->events + i;
859 ed = dst->event_ring + i;
867 serialize_elog_event (serialize_main_t * m, va_list * va)
869 elog_main_t *em = va_arg (*va, elog_main_t *);
870 elog_event_t *e = va_arg (*va, elog_event_t *);
871 elog_event_type_t *t = vec_elt_at_index (em->event_types, e->event_type);
873 u8 *p = (u8 *) t->format_args;
875 serialize_integer (m, e->event_type, sizeof (e->event_type));
876 serialize_integer (m, e->track, sizeof (e->track));
877 serialize (m, serialize_f64, e->time);
881 uword n_digits, n_bytes = 0;
883 n_digits = parse_2digit_decimal ((char *) p + 1, &n_bytes);
891 serialize_integer (m, d[0], sizeof (u8));
892 else if (n_bytes == 2)
893 serialize_integer (m, clib_mem_unaligned (d, u16), sizeof (u16));
894 else if (n_bytes == 4)
895 serialize_integer (m, clib_mem_unaligned (d, u32), sizeof (u32));
896 else if (n_bytes == 8)
897 serialize (m, serialize_64, clib_mem_unaligned (d, u64));
903 serialize_cstring (m, (char *) d);
905 n_bytes = strlen ((char *) d) + 1;
910 serialize (m, serialize_f32, clib_mem_unaligned (d, f32));
911 else if (n_bytes == 8)
912 serialize (m, serialize_f64, clib_mem_unaligned (d, f64));
928 unserialize_elog_event (serialize_main_t * m, va_list * va)
930 elog_main_t *em = va_arg (*va, elog_main_t *);
931 elog_event_t *e = va_arg (*va, elog_event_t *);
932 elog_event_type_t *t;
938 unserialize_integer (m, &tmp[0], sizeof (e->event_type));
939 unserialize_integer (m, &tmp[1], sizeof (e->track));
941 e->event_type = tmp[0];
944 /* Make sure it fits. */
945 ASSERT (e->event_type == tmp[0]);
946 ASSERT (e->track == tmp[1]);
949 t = vec_elt_at_index (em->event_types, e->event_type);
951 unserialize (m, unserialize_f64, &e->time);
954 p = (u8 *) t->format_args;
958 uword n_digits, n_bytes = 0;
961 n_digits = parse_2digit_decimal ((char *) p + 1, &n_bytes);
970 unserialize_integer (m, &tmp, sizeof (u8));
973 else if (n_bytes == 2)
975 unserialize_integer (m, &tmp, sizeof (u16));
976 clib_mem_unaligned (d, u16) = tmp;
978 else if (n_bytes == 4)
980 unserialize_integer (m, &tmp, sizeof (u32));
981 clib_mem_unaligned (d, u32) = tmp;
983 else if (n_bytes == 8)
986 unserialize (m, unserialize_64, &x);
987 clib_mem_unaligned (d, u64) = x;
996 unserialize_cstring (m, &t);
998 n_bytes = strlen (t) + 1;
999 clib_memcpy (d, t, clib_min (n_bytes, vec_len (t)));
1008 unserialize (m, unserialize_f32, &x);
1009 clib_mem_unaligned (d, f32) = x;
1011 else if (n_bytes == 8)
1014 unserialize (m, unserialize_f64, &x);
1015 clib_mem_unaligned (d, f64) = x;
1032 serialize_elog_event_type (serialize_main_t * m, va_list * va)
1034 elog_event_type_t *t = va_arg (*va, elog_event_type_t *);
1035 int n = va_arg (*va, int);
1037 for (i = 0; i < n; i++)
1039 serialize_cstring (m, t[i].format);
1040 serialize_cstring (m, t[i].format_args);
1041 serialize_integer (m, t[i].type_index_plus_one,
1042 sizeof (t->type_index_plus_one));
1043 serialize_integer (m, t[i].n_enum_strings,
1044 sizeof (t[i].n_enum_strings));
1045 for (j = 0; j < t[i].n_enum_strings; j++)
1046 serialize_cstring (m, t[i].enum_strings_vector[j]);
1051 unserialize_elog_event_type (serialize_main_t * m, va_list * va)
1053 elog_event_type_t *t = va_arg (*va, elog_event_type_t *);
1054 int n = va_arg (*va, int);
1056 for (i = 0; i < n; i++)
1058 unserialize_cstring (m, &t[i].format);
1059 unserialize_cstring (m, &t[i].format_args);
1060 unserialize_integer (m, &t[i].type_index_plus_one,
1061 sizeof (t->type_index_plus_one));
1062 unserialize_integer (m, &t[i].n_enum_strings,
1063 sizeof (t[i].n_enum_strings));
1064 vec_resize (t[i].enum_strings_vector, t[i].n_enum_strings);
1065 for (j = 0; j < t[i].n_enum_strings; j++)
1066 unserialize_cstring (m, &t[i].enum_strings_vector[j]);
1071 serialize_elog_track (serialize_main_t * m, va_list * va)
1073 elog_track_t *t = va_arg (*va, elog_track_t *);
1074 int n = va_arg (*va, int);
1076 for (i = 0; i < n; i++)
1078 serialize_cstring (m, t[i].name);
1083 unserialize_elog_track (serialize_main_t * m, va_list * va)
1085 elog_track_t *t = va_arg (*va, elog_track_t *);
1086 int n = va_arg (*va, int);
1088 for (i = 0; i < n; i++)
1090 unserialize_cstring (m, &t[i].name);
1095 serialize_elog_time_stamp (serialize_main_t * m, va_list * va)
1097 elog_time_stamp_t *st = va_arg (*va, elog_time_stamp_t *);
1098 serialize (m, serialize_64, st->os_nsec);
1099 serialize (m, serialize_64, st->cpu);
1103 unserialize_elog_time_stamp (serialize_main_t * m, va_list * va)
1105 elog_time_stamp_t *st = va_arg (*va, elog_time_stamp_t *);
1106 unserialize (m, unserialize_64, &st->os_nsec);
1107 unserialize (m, unserialize_64, &st->cpu);
1110 static char *elog_serialize_magic = "elog v0";
1113 serialize_elog_main (serialize_main_t * m, va_list * va)
1115 elog_main_t *em = va_arg (*va, elog_main_t *);
1116 int flush_ring = va_arg (*va, int);
1119 serialize_magic (m, elog_serialize_magic, strlen (elog_serialize_magic));
1121 serialize_integer (m, em->event_ring_size, sizeof (u32));
1123 elog_time_now (&em->serialize_time);
1124 serialize (m, serialize_elog_time_stamp, &em->serialize_time);
1125 serialize (m, serialize_elog_time_stamp, &em->init_time);
1127 vec_serialize (m, em->event_types, serialize_elog_event_type);
1128 vec_serialize (m, em->tracks, serialize_elog_track);
1129 vec_serialize (m, em->string_table, serialize_vec_8);
1131 /* Free old events (cached) in case they have changed. */
1134 vec_free (em->events);
1135 elog_get_events (em);
1138 serialize_integer (m, vec_len (em->events), sizeof (u32));
1140 /* SMP logs can easily have local time paradoxes... */
1141 vec_sort_with_function (em->events, elog_cmp);
1143 vec_foreach (e, em->events) serialize (m, serialize_elog_event, em, e);
1147 unserialize_elog_main (serialize_main_t *m, va_list *va)
1149 elog_main_t *em = va_arg (*va, elog_main_t *);
1153 unserialize_check_magic (m, elog_serialize_magic,
1154 strlen (elog_serialize_magic));
1156 unserialize_integer (m, &rs, sizeof (u32));
1157 em->event_ring_size = rs;
1158 elog_init (em, em->event_ring_size);
1160 unserialize (m, unserialize_elog_time_stamp, &em->serialize_time);
1161 unserialize (m, unserialize_elog_time_stamp, &em->init_time);
1162 em->nsec_per_cpu_clock = elog_nsec_per_clock (em);
1164 vec_unserialize (m, &em->event_types, unserialize_elog_event_type);
1165 for (i = 0; i < vec_len (em->event_types); i++)
1166 new_event_type (em, i);
1168 vec_unserialize (m, &em->tracks, unserialize_elog_track);
1169 vec_unserialize (m, &em->string_table, unserialize_vec_8);
1175 unserialize_integer (m, &ne, sizeof (u32));
1176 vec_resize (em->events, ne);
1177 vec_foreach (e, em->events)
1178 unserialize (m, unserialize_elog_event, em, e);
1184 elog_write_file_not_inline (elog_main_t * em, char *clib_file, int flush_ring)
1187 clib_error_t *error;
1189 error = serialize_open_clib_file (&m, clib_file);
1192 error = serialize (&m, serialize_elog_main, em, flush_ring);
1194 serialize_close (&m);
1198 __clib_export clib_error_t *
1199 elog_read_file_not_inline (elog_main_t * em, char *clib_file)
1201 serialize_main_t m = { 0 };
1202 clib_error_t *error;
1204 error = unserialize_open_clib_file (&m, clib_file);
1207 error = unserialize (&m, unserialize_elog_main, em);
1209 unserialize_close (&m);
1212 #endif /* CLIB_UNIX */
1216 * fd.io coding-style-patch-verification: ON
1219 * eval: (c-set-style "gnu")