blob: e9f06d0948cac97df5360565f1dbfeef14339d96 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
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:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
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.
14 */
15/*
16 Copyright (c) 2005,2009 Eliot Dresselhaus
17
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:
25
26 The above copyright notice and this permission notice shall be
27 included in all copies or substantial portions of the Software.
28
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.
36*/
37
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
Dave Barachc3799992016-08-15 11:12:27 -040045static inline void
46elog_lock (elog_main_t * em)
Ed Warnickecb9cada2015-12-08 15:45:58 -070047{
Dave Barachc3799992016-08-15 11:12:27 -040048 if (PREDICT_FALSE (em->lock != 0))
49 while (__sync_lock_test_and_set (em->lock, 1))
50 ;
Ed Warnickecb9cada2015-12-08 15:45:58 -070051}
52
Dave Barachc3799992016-08-15 11:12:27 -040053static inline void
54elog_unlock (elog_main_t * em)
Ed Warnickecb9cada2015-12-08 15:45:58 -070055{
Dave Barachc3799992016-08-15 11:12:27 -040056 if (PREDICT_FALSE (em->lock != 0))
Dave Barachfb6e59d2016-03-26 18:45:42 -040057 {
Dave Barachc3799992016-08-15 11:12:27 -040058 CLIB_MEMORY_BARRIER ();
Dave Barachfb6e59d2016-03-26 18:45:42 -040059 *em->lock = 0;
60 }
Ed Warnickecb9cada2015-12-08 15:45:58 -070061}
62
63/* Non-inline version. */
64void *
65elog_event_data (elog_main_t * em,
Dave Barachc3799992016-08-15 11:12:27 -040066 elog_event_type_t * type, elog_track_t * track, u64 cpu_time)
Ed Warnickecb9cada2015-12-08 15:45:58 -070067{
Dave Barachc3799992016-08-15 11:12:27 -040068 return elog_event_data_inline (em, type, track, cpu_time);
69}
Ed Warnickecb9cada2015-12-08 15:45:58 -070070
Dave Barachc3799992016-08-15 11:12:27 -040071static void
72new_event_type (elog_main_t * em, uword i)
73{
74 elog_event_type_t *t = vec_elt_at_index (em->event_types, i);
75
76 if (!em->event_type_by_format)
77 em->event_type_by_format =
78 hash_create_vec ( /* size */ 0, sizeof (u8), sizeof (uword));
Ed Warnickecb9cada2015-12-08 15:45:58 -070079
80 hash_set_mem (em->event_type_by_format, t->format, i);
81}
82
83static uword
84find_or_create_type (elog_main_t * em, elog_event_type_t * t)
85{
Dave Barachc3799992016-08-15 11:12:27 -040086 uword *p = hash_get_mem (em->event_type_by_format, t->format);
Ed Warnickecb9cada2015-12-08 15:45:58 -070087 uword i;
88
89 if (p)
90 i = p[0];
91 else
92 {
93 i = vec_len (em->event_types);
94 vec_add1 (em->event_types, t[0]);
95 new_event_type (em, i);
96 }
97
98 return i;
99}
100
101/* External function to register types. */
Dave Barachc3799992016-08-15 11:12:27 -0400102word
103elog_event_type_register (elog_main_t * em, elog_event_type_t * t)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700104{
Dave Barachc3799992016-08-15 11:12:27 -0400105 elog_event_type_t *static_type = t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700106 word l;
107
108 elog_lock (em);
109
110 l = vec_len (em->event_types);
111
112 t->type_index_plus_one = 1 + l;
113
114 ASSERT (t->format);
115
116 /* If format args are not specified try to be smart about providing defaults
117 so most of the time user does not have to specify them. */
Dave Barachc3799992016-08-15 11:12:27 -0400118 if (!t->format_args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700119 {
120 uword i, l;
Dave Barachc3799992016-08-15 11:12:27 -0400121 char *this_arg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700122
123 l = strlen (t->format);
124 for (i = 0; i < l; i++)
125 {
126 if (t->format[i] != '%')
127 continue;
128 if (i + 1 >= l)
129 continue;
Dave Barachc3799992016-08-15 11:12:27 -0400130 if (t->format[i + 1] == '%') /* %% */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700131 continue;
132
Dave Barachc3799992016-08-15 11:12:27 -0400133 switch (t->format[i + 1])
134 {
135 default:
136 case 'd':
137 case 'x':
138 case 'u':
139 this_arg = "i4"; /* size of u32 */
140 break;
141 case 'f':
142 this_arg = "f8"; /* defaults to f64 */
143 break;
144 case 's':
145 this_arg = "s0"; /* defaults to null terminated string. */
146 break;
147 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700148
Dave Barachc3799992016-08-15 11:12:27 -0400149 t->format_args =
150 (char *) format ((u8 *) t->format_args, "%s", this_arg);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700151 }
152
153 /* Null terminate. */
154 vec_add1 (t->format_args, 0);
Dave Barachc3799992016-08-15 11:12:27 -0400155 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700156
157 vec_add1 (em->event_types, t[0]);
158
159 t = em->event_types + l;
160
161 /* Make copies of strings for hashing etc. */
162 if (t->function)
163 t->format = (char *) format (0, "%s %s%c", t->function, t->format, 0);
164 else
165 t->format = (char *) format (0, "%s%c", t->format, 0);
166
167 t->format_args = (char *) format (0, "%s%c", t->format_args, 0);
168
169 /* Construct string table. */
170 {
171 uword i;
172 t->n_enum_strings = static_type->n_enum_strings;
173 for (i = 0; i < t->n_enum_strings; i++)
174 {
Dave Barachc3799992016-08-15 11:12:27 -0400175 if (!static_type->enum_strings[i])
Ed Warnickecb9cada2015-12-08 15:45:58 -0700176 static_type->enum_strings[i] = "MISSING";
Dave Barachc3799992016-08-15 11:12:27 -0400177 vec_add1 (t->enum_strings_vector,
178 (char *) format (0, "%s%c", static_type->enum_strings[i],
179 0));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700180 }
181 }
182
183 new_event_type (em, l);
Dave Barachc3799992016-08-15 11:12:27 -0400184 elog_unlock (em);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700185
186 return l;
187}
188
Dave Barachc3799992016-08-15 11:12:27 -0400189word
190elog_track_register (elog_main_t * em, elog_track_t * t)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700191{
192 word l;
193
194 elog_lock (em);
195
196 l = vec_len (em->tracks);
197
198 t->track_index_plus_one = 1 + l;
199
200 ASSERT (t->name);
201
202 vec_add1 (em->tracks, t[0]);
203
204 t = em->tracks + l;
205
206 t->name = (char *) format (0, "%s%c", t->name, 0);
207
208 elog_unlock (em);
209
210 return l;
211}
212
Dave Barachc3799992016-08-15 11:12:27 -0400213static uword
214parse_2digit_decimal (char *p, uword * number)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700215{
216 uword i = 0;
217 u8 digits[2];
218
219 digits[0] = digits[1] = 0;
220 while (p[i] >= '0' && p[i] <= '9')
221 {
222 if (i >= 2)
223 break;
224 digits[i] = p[i] - '0';
225 i++;
226 }
227
228 if (i >= 1 && i <= 2)
229 {
230 if (i == 1)
231 *number = digits[0];
232 else
233 *number = 10 * digits[0] + digits[1];
234 return i;
235 }
236 else
237 return 0;
238}
239
Dave Barachc3799992016-08-15 11:12:27 -0400240static u8 *
241fixed_format (u8 * s, char *fmt, char *result, uword * result_len)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700242{
Dave Barachc3799992016-08-15 11:12:27 -0400243 char *f = fmt;
244 char *percent;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700245 uword l = 0;
246
247 while (1)
248 {
249 if (f[0] == 0)
250 break;
251 if (f[0] == '%' && f[1] != '%')
252 break;
253 f++;
254 }
255 if (f > fmt)
256 vec_add (s, fmt, f - fmt);
257
258 if (f[0] != '%')
259 goto done;
260
261 /* Skip percent. */
262 percent = f++;
263
264 /* Skip possible +-= justification. */
265 f += f[0] == '+' || f[0] == '-' || f[0] == '=';
266
267 /* Skip possible X.Y width. */
268 while ((f[0] >= '0' && f[0] <= '9') || f[0] == '.')
269 f++;
270
271 /* Skip wlL as in e.g. %Ld. */
272 f += f[0] == 'w' || f[0] == 'l' || f[0] == 'L';
273
274 /* Finally skip format letter. */
275 f += f[0] != 0;
276
277 ASSERT (*result_len > f - percent);
278 l = clib_min (f - percent, *result_len - 1);
Damjan Marionf1213b82016-03-13 02:22:06 +0100279 clib_memcpy (result, percent, l);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700280 result[l] = 0;
281
Dave Barachc3799992016-08-15 11:12:27 -0400282done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700283 *result_len = f - fmt;
284 return s;
285}
286
Dave Barachc3799992016-08-15 11:12:27 -0400287u8 *
288format_elog_event (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700289{
Dave Barachc3799992016-08-15 11:12:27 -0400290 elog_main_t *em = va_arg (*va, elog_main_t *);
291 elog_event_t *e = va_arg (*va, elog_event_t *);
292 elog_event_type_t *t;
293 char *a, *f;
294 void *d = (u8 *) e->data;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700295 char arg_format[64];
296
297 t = vec_elt_at_index (em->event_types, e->type);
298
299 f = t->format;
300 a = t->format_args;
301 while (1)
302 {
303 uword n_bytes = 0, n_digits, f_bytes = 0;
304
305 f_bytes = sizeof (arg_format);
306 s = fixed_format (s, f, arg_format, &f_bytes);
307 f += f_bytes;
308
309 if (a == 0 || a[0] == 0)
310 {
311 /* Format must also be at end. */
312 ASSERT (f[0] == 0);
313 break;
314 }
315
316 /* Don't go past end of event data. */
317 ASSERT (d < (void *) (e->data + sizeof (e->data)));
318
319 n_digits = parse_2digit_decimal (a + 1, &n_bytes);
320 switch (a[0])
321 {
322 case 'i':
323 case 't':
324 case 'T':
325 {
326 u32 i = 0;
327 u64 l = 0;
328
329 if (n_bytes == 1)
330 i = ((u8 *) d)[0];
331 else if (n_bytes == 2)
332 i = clib_mem_unaligned (d, u16);
333 else if (n_bytes == 4)
334 i = clib_mem_unaligned (d, u32);
335 else if (n_bytes == 8)
336 l = clib_mem_unaligned (d, u64);
337 else
338 ASSERT (0);
339 if (a[0] == 't')
340 {
Dave Barachc3799992016-08-15 11:12:27 -0400341 char *e =
342 vec_elt (t->enum_strings_vector, n_bytes == 8 ? l : i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700343 s = format (s, arg_format, e);
344 }
345 else if (a[0] == 'T')
346 {
Dave Barachc3799992016-08-15 11:12:27 -0400347 char *e =
348 vec_elt_at_index (em->string_table, n_bytes == 8 ? l : i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700349 s = format (s, arg_format, e);
350 }
351 else if (n_bytes == 8)
352 s = format (s, arg_format, l);
353 else
354 s = format (s, arg_format, i);
355 }
356 break;
357
358 case 'f':
359 {
360 f64 x = 0;
361 if (n_bytes == 4)
362 x = clib_mem_unaligned (d, f32);
363 else if (n_bytes == 8)
364 x = clib_mem_unaligned (d, f64);
365 else
366 ASSERT (0);
367 s = format (s, arg_format, x);
368 }
369 break;
370
371 case 's':
372 s = format (s, arg_format, d);
373 if (n_bytes == 0)
374 n_bytes = strlen (d) + 1;
375 break;
376
377 default:
378 ASSERT (0);
379 break;
380 }
381
382 ASSERT (n_digits > 0 && n_digits <= 2);
383 a += 1 + n_digits;
384 d += n_bytes;
385 }
386
387 return s;
388}
389
Dave Barachc3799992016-08-15 11:12:27 -0400390u8 *
391format_elog_track (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700392{
Dave Barachc3799992016-08-15 11:12:27 -0400393 elog_main_t *em = va_arg (*va, elog_main_t *);
394 elog_event_t *e = va_arg (*va, elog_event_t *);
395 elog_track_t *t = vec_elt_at_index (em->tracks, e->track);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700396 return format (s, "%s", t->name);
397}
398
Dave Barachc3799992016-08-15 11:12:27 -0400399void
400elog_time_now (elog_time_stamp_t * et)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700401{
402 u64 cpu_time_now, os_time_now_nsec;
403
404#ifdef CLIB_UNIX
405 {
406#include <sys/syscall.h>
407 struct timespec ts;
408 syscall (SYS_clock_gettime, CLOCK_REALTIME, &ts);
409 cpu_time_now = clib_cpu_time_now ();
410 os_time_now_nsec = 1e9 * ts.tv_sec + ts.tv_nsec;
411 }
412#else
413 cpu_time_now = clib_cpu_time_now ();
414 os_time_now_nsec = 0;
415#endif
416
417 et->cpu = cpu_time_now;
418 et->os_nsec = os_time_now_nsec;
419}
420
421always_inline i64
Dave Barachc3799992016-08-15 11:12:27 -0400422elog_time_stamp_diff_os_nsec (elog_time_stamp_t * t1, elog_time_stamp_t * t2)
423{
424 return (i64) t1->os_nsec - (i64) t2->os_nsec;
425}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700426
427always_inline i64
Dave Barachc3799992016-08-15 11:12:27 -0400428elog_time_stamp_diff_cpu (elog_time_stamp_t * t1, elog_time_stamp_t * t2)
429{
430 return (i64) t1->cpu - (i64) t2->cpu;
431}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700432
433always_inline f64
434elog_nsec_per_clock (elog_main_t * em)
435{
436 return ((f64) elog_time_stamp_diff_os_nsec (&em->serialize_time,
437 &em->init_time)
438 / (f64) elog_time_stamp_diff_cpu (&em->serialize_time,
439 &em->init_time));
440}
441
Dave Barachc3799992016-08-15 11:12:27 -0400442void
443elog_alloc (elog_main_t * em, u32 n_events)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700444{
445 if (em->event_ring)
446 vec_free (em->event_ring);
Dave Barachc3799992016-08-15 11:12:27 -0400447
Ed Warnickecb9cada2015-12-08 15:45:58 -0700448 /* Ring size must be a power of 2. */
449 em->event_ring_size = n_events = max_pow2 (n_events);
450
451 /* Leave an empty ievent at end so we can always speculatively write
452 and event there (possibly a long form event). */
453 vec_resize_aligned (em->event_ring, n_events, CLIB_CACHE_LINE_BYTES);
454}
455
Dave Barachc3799992016-08-15 11:12:27 -0400456void
457elog_init (elog_main_t * em, u32 n_events)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700458{
459 memset (em, 0, sizeof (em[0]));
460
461 em->lock = 0;
462
463 if (n_events > 0)
464 elog_alloc (em, n_events);
465
466 clib_time_init (&em->cpu_timer);
467
468 em->n_total_events_disable_limit = ~0;
469
470 /* Make track 0. */
471 em->default_track.name = "default";
472 elog_track_register (em, &em->default_track);
473
474 elog_time_now (&em->init_time);
475}
476
477/* Returns number of events in ring and start index. */
Dave Barachc3799992016-08-15 11:12:27 -0400478static uword
479elog_event_range (elog_main_t * em, uword * lo)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700480{
481 uword l = em->event_ring_size;
482 u64 i = em->n_total_events;
483
484 /* Ring never wrapped? */
485 if (i <= (u64) l)
486 {
Dave Barachc3799992016-08-15 11:12:27 -0400487 if (lo)
488 *lo = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700489 return i;
490 }
491 else
492 {
Dave Barachc3799992016-08-15 11:12:27 -0400493 if (lo)
494 *lo = i & (l - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700495 return l;
496 }
497}
498
Dave Barachc3799992016-08-15 11:12:27 -0400499elog_event_t *
500elog_peek_events (elog_main_t * em)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700501{
Dave Barachc3799992016-08-15 11:12:27 -0400502 elog_event_t *e, *f, *es = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700503 uword i, j, n;
504
505 n = elog_event_range (em, &j);
506 for (i = 0; i < n; i++)
507 {
508 vec_add2 (es, e, 1);
509 f = vec_elt_at_index (em->event_ring, j);
510 e[0] = f[0];
511
512 /* Convert absolute time from cycles to seconds from start. */
Dave Barachc3799992016-08-15 11:12:27 -0400513 e->time =
514 (e->time_cycles -
515 em->init_time.cpu) * em->cpu_timer.seconds_per_clock;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700516
517 j = (j + 1) & (em->event_ring_size - 1);
518 }
519
520 return es;
521}
522
523/* Add a formatted string to the string table. */
Dave Barachc3799992016-08-15 11:12:27 -0400524u32
525elog_string (elog_main_t * em, char *fmt, ...)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700526{
527 u32 offset;
528 va_list va;
529
530 va_start (va, fmt);
531 offset = vec_len (em->string_table);
532 em->string_table = (char *) va_format ((u8 *) em->string_table, fmt, &va);
533 va_end (va);
534
535 /* Null terminate string if it is not already. */
536 if (vec_end (em->string_table)[-1] != 0)
537 vec_add1 (em->string_table, 0);
538
539 return offset;
540}
541
Dave Barachc3799992016-08-15 11:12:27 -0400542elog_event_t *
543elog_get_events (elog_main_t * em)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700544{
Dave Barachc3799992016-08-15 11:12:27 -0400545 if (!em->events)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700546 em->events = elog_peek_events (em);
547 return em->events;
548}
549
Dave Barachc3799992016-08-15 11:12:27 -0400550static void
551maybe_fix_string_table_offset (elog_event_t * e,
552 elog_event_type_t * t, u32 offset)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700553{
Dave Barachc3799992016-08-15 11:12:27 -0400554 void *d = (u8 *) e->data;
555 char *a;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700556
557 if (offset == 0)
558 return;
559
560 a = t->format_args;
561
562 while (1)
563 {
564 uword n_bytes = 0, n_digits;
565
566 if (a[0] == 0)
Dave Barachc3799992016-08-15 11:12:27 -0400567 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700568
569 /* Don't go past end of event data. */
570 ASSERT (d < (void *) (e->data + sizeof (e->data)));
571
572 n_digits = parse_2digit_decimal (a + 1, &n_bytes);
573 switch (a[0])
574 {
575 case 'T':
Dave Barachc3799992016-08-15 11:12:27 -0400576 ASSERT (n_bytes == 4);
577 clib_mem_unaligned (d, u32) += offset;
578 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700579
580 case 'i':
581 case 't':
582 case 'f':
583 case 's':
584 break;
585
586 default:
587 ASSERT (0);
588 break;
589 }
590
591 ASSERT (n_digits > 0 && n_digits <= 2);
592 a += 1 + n_digits;
593 d += n_bytes;
594 }
595}
596
Dave Barachc3799992016-08-15 11:12:27 -0400597static int
598elog_cmp (void *a1, void *a2)
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500599{
Dave Barachc3799992016-08-15 11:12:27 -0400600 elog_event_t *e1 = a1;
601 elog_event_t *e2 = a2;
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500602
603 return e1->time - e2->time;
604}
605
Dave Barachc3799992016-08-15 11:12:27 -0400606void
607elog_merge (elog_main_t * dst, u8 * dst_tag, elog_main_t * src, u8 * src_tag)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700608{
Dave Barachc3799992016-08-15 11:12:27 -0400609 elog_event_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700610 uword l;
611 u32 string_table_offset_for_src_events;
612 u32 track_offset_for_src_tracks;
613 elog_track_t newt;
614 int i;
615
Dave Barachc3799992016-08-15 11:12:27 -0400616 memset (&newt, 0, sizeof (newt));
Dave Barachf9c231e2016-08-05 10:10:18 -0400617
Ed Warnickecb9cada2015-12-08 15:45:58 -0700618 elog_get_events (src);
619 elog_get_events (dst);
620
621 string_table_offset_for_src_events = vec_len (dst->string_table);
622 vec_append (dst->string_table, src->string_table);
623
624 l = vec_len (dst->events);
625 vec_add (dst->events, src->events, vec_len (src->events));
626
627 /* Prepend the supplied tag (if any) to all dst track names */
628 if (dst_tag)
629 {
Dave Barachc3799992016-08-15 11:12:27 -0400630 for (i = 0; i < vec_len (dst->tracks); i++)
631 {
632 elog_track_t *t = vec_elt_at_index (dst->tracks, i);
633 char *new_name;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700634
Dave Barachc3799992016-08-15 11:12:27 -0400635 new_name = (char *) format (0, "%s:%s%c", dst_tag, t->name, 0);
636 vec_free (t->name);
637 t->name = new_name;
638 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700639 }
Dave Barachc3799992016-08-15 11:12:27 -0400640
Ed Warnickecb9cada2015-12-08 15:45:58 -0700641 track_offset_for_src_tracks = vec_len (dst->tracks);
Dave Barachc3799992016-08-15 11:12:27 -0400642
Ed Warnickecb9cada2015-12-08 15:45:58 -0700643 /* Copy / tag source tracks */
644 for (i = 0; i < vec_len (src->tracks); i++)
645 {
Dave Barachc3799992016-08-15 11:12:27 -0400646 elog_track_t *t = vec_elt_at_index (src->tracks, i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700647 if (src_tag)
Dave Barachc3799992016-08-15 11:12:27 -0400648 newt.name = (char *) format (0, "%s:%s%c", src_tag, t->name, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700649 else
Dave Barachc3799992016-08-15 11:12:27 -0400650 newt.name = (char *) format (0, "%s%c", t->name, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700651 (void) elog_track_register (dst, &newt);
652 vec_free (newt.name);
653 }
Dave Barachc3799992016-08-15 11:12:27 -0400654
Ed Warnickecb9cada2015-12-08 15:45:58 -0700655 /* Across all (copied) src events... */
656 for (e = dst->events + l; e < vec_end (dst->events); e++)
657 {
Dave Barachc3799992016-08-15 11:12:27 -0400658 elog_event_type_t *t = vec_elt_at_index (src->event_types, e->type);
659
Ed Warnickecb9cada2015-12-08 15:45:58 -0700660 /* Remap type from src -> dst. */
661 e->type = find_or_create_type (dst, t);
662
663 /* Remap string table offsets for 'T' format args */
Dave Barachc3799992016-08-15 11:12:27 -0400664 maybe_fix_string_table_offset (e, t,
665 string_table_offset_for_src_events);
666
Ed Warnickecb9cada2015-12-08 15:45:58 -0700667 /* Remap track */
668 e->track += track_offset_for_src_tracks;
669 }
670
671 /* Adjust event times for relative starting times of event streams. */
672 {
673 f64 dt_event, dt_os_nsec, dt_clock_nsec;
674
675 /* Set clock parameters if dst was not generated by unserialize. */
676 if (dst->serialize_time.cpu == 0)
677 {
678 dst->init_time = src->init_time;
679 dst->serialize_time = src->serialize_time;
680 dst->nsec_per_cpu_clock = src->nsec_per_cpu_clock;
681 }
682
Dave Barachc3799992016-08-15 11:12:27 -0400683 dt_os_nsec =
684 elog_time_stamp_diff_os_nsec (&src->init_time, &dst->init_time);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700685
686 dt_event = dt_os_nsec;
Dave Barachc3799992016-08-15 11:12:27 -0400687 dt_clock_nsec =
688 (elog_time_stamp_diff_cpu (&src->init_time, &dst->init_time) * .5 *
689 (dst->nsec_per_cpu_clock + src->nsec_per_cpu_clock));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700690
691 /* Heuristic to see if src/dst came from same time source.
692 If frequencies are "the same" and os clock and cpu clock agree
693 to within 100e-9 secs about time difference between src/dst
694 init_time, then we use cpu clock. Otherwise we use OS clock. */
695 if (fabs (src->nsec_per_cpu_clock - dst->nsec_per_cpu_clock) < 1e-2
696 && fabs (dt_os_nsec - dt_clock_nsec) < 100)
697 dt_event = dt_clock_nsec;
698
699 /* Convert to seconds. */
700 dt_event *= 1e-9;
701
702 if (dt_event > 0)
703 {
704 /* Src started after dst. */
705 for (e = dst->events + l; e < vec_end (dst->events); e++)
706 e->time += dt_event;
707 }
708 else
709 {
710 /* Dst started after src. */
711 for (e = dst->events + 0; e < dst->events + l; e++)
712 e->time += dt_event;
713 }
714 }
715
716 /* Sort events by increasing time. */
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500717 vec_sort_with_function (dst->events, elog_cmp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700718
719 /* Recreate the event ring or the results won't serialize */
720 {
721 int i;
722
723 ASSERT (dst->cpu_timer.seconds_per_clock);
724
725 elog_alloc (dst, vec_len (dst->events));
Dave Barachc3799992016-08-15 11:12:27 -0400726 for (i = 0; i < vec_len (dst->events); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700727 {
Dave Barachc3799992016-08-15 11:12:27 -0400728 elog_event_t *es, *ed;
729
730 es = dst->events + i;
731 ed = dst->event_ring + i;
732
733 ed[0] = es[0];
734
735 /* Invert elog_peek_events calculation */
736 ed->time_cycles =
737 (es->time / dst->cpu_timer.seconds_per_clock) + dst->init_time.cpu;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700738 }
739 dst->n_total_events = vec_len (dst->events);
740 }
741}
742
743static void
744serialize_elog_event (serialize_main_t * m, va_list * va)
745{
Dave Barachc3799992016-08-15 11:12:27 -0400746 elog_main_t *em = va_arg (*va, elog_main_t *);
747 elog_event_t *e = va_arg (*va, elog_event_t *);
748 elog_event_type_t *t = vec_elt_at_index (em->event_types, e->type);
749 u8 *d = e->data;
750 u8 *p = (u8 *) t->format_args;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700751
752 serialize_integer (m, e->type, sizeof (e->type));
753 serialize_integer (m, e->track, sizeof (e->track));
754 serialize (m, serialize_f64, e->time);
755
756 while (*p)
757 {
758 uword n_digits, n_bytes = 0;
759
760 n_digits = parse_2digit_decimal ((char *) p + 1, &n_bytes);
761
762 switch (p[0])
763 {
764 case 'i':
765 case 't':
766 case 'T':
767 if (n_bytes == 1)
768 serialize_integer (m, d[0], sizeof (u8));
769 else if (n_bytes == 2)
770 serialize_integer (m, clib_mem_unaligned (d, u16), sizeof (u16));
771 else if (n_bytes == 4)
772 serialize_integer (m, clib_mem_unaligned (d, u32), sizeof (u32));
773 else if (n_bytes == 8)
774 serialize (m, serialize_64, clib_mem_unaligned (d, u64));
775 else
776 ASSERT (0);
777 break;
778
779 case 's':
780 serialize_cstring (m, (char *) d);
781 if (n_bytes == 0)
782 n_bytes = strlen ((char *) d) + 1;
783 break;
784
785 case 'f':
786 if (n_bytes == 4)
787 serialize (m, serialize_f32, clib_mem_unaligned (d, f32));
788 else if (n_bytes == 8)
789 serialize (m, serialize_f64, clib_mem_unaligned (d, f64));
790 else
791 ASSERT (0);
792 break;
793
794 default:
795 ASSERT (0);
796 break;
797 }
798
799 p += 1 + n_digits;
800 d += n_bytes;
801 }
802}
803
804static void
805unserialize_elog_event (serialize_main_t * m, va_list * va)
806{
Dave Barachc3799992016-08-15 11:12:27 -0400807 elog_main_t *em = va_arg (*va, elog_main_t *);
808 elog_event_t *e = va_arg (*va, elog_event_t *);
809 elog_event_type_t *t;
810 u8 *p, *d;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700811
812 {
813 u16 tmp[2];
814
815 unserialize_integer (m, &tmp[0], sizeof (e->type));
816 unserialize_integer (m, &tmp[1], sizeof (e->track));
817
818 e->type = tmp[0];
819 e->track = tmp[1];
820
821 /* Make sure it fits. */
822 ASSERT (e->type == tmp[0]);
823 ASSERT (e->track == tmp[1]);
824 }
825
826 t = vec_elt_at_index (em->event_types, e->type);
827
828 unserialize (m, unserialize_f64, &e->time);
829
830 d = e->data;
831 p = (u8 *) t->format_args;
832
833 while (p && *p)
834 {
835 uword n_digits, n_bytes = 0;
836 u32 tmp;
837
838 n_digits = parse_2digit_decimal ((char *) p + 1, &n_bytes);
839
840 switch (p[0])
841 {
842 case 'i':
843 case 't':
844 case 'T':
845 if (n_bytes == 1)
846 {
847 unserialize_integer (m, &tmp, sizeof (u8));
848 d[0] = tmp;
849 }
850 else if (n_bytes == 2)
851 {
852 unserialize_integer (m, &tmp, sizeof (u16));
853 clib_mem_unaligned (d, u16) = tmp;
854 }
855 else if (n_bytes == 4)
856 {
857 unserialize_integer (m, &tmp, sizeof (u32));
858 clib_mem_unaligned (d, u32) = tmp;
859 }
860 else if (n_bytes == 8)
861 {
862 u64 x;
863 unserialize (m, unserialize_64, &x);
864 clib_mem_unaligned (d, u64) = x;
865 }
866 else
867 ASSERT (0);
868 break;
869
Dave Barachc3799992016-08-15 11:12:27 -0400870 case 's':
871 {
872 char *t;
873 unserialize_cstring (m, &t);
874 if (n_bytes == 0)
875 n_bytes = strlen (t) + 1;
876 clib_memcpy (d, t, clib_min (n_bytes, vec_len (t)));
877 vec_free (t);
878 break;
879 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700880
881 case 'f':
882 if (n_bytes == 4)
883 {
884 f32 x;
885 unserialize (m, unserialize_f32, &x);
886 clib_mem_unaligned (d, f32) = x;
887 }
888 else if (n_bytes == 8)
889 {
890 f64 x;
891 unserialize (m, unserialize_f64, &x);
892 clib_mem_unaligned (d, f64) = x;
893 }
894 else
895 ASSERT (0);
896 break;
897
898 default:
899 ASSERT (0);
900 break;
901 }
902
903 p += 1 + n_digits;
904 d += n_bytes;
905 }
906}
907
908static void
909serialize_elog_event_type (serialize_main_t * m, va_list * va)
910{
Dave Barachc3799992016-08-15 11:12:27 -0400911 elog_event_type_t *t = va_arg (*va, elog_event_type_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700912 int n = va_arg (*va, int);
913 int i, j;
914 for (i = 0; i < n; i++)
915 {
916 serialize_cstring (m, t[i].format);
917 serialize_cstring (m, t[i].format_args);
Dave Barachc3799992016-08-15 11:12:27 -0400918 serialize_integer (m, t[i].type_index_plus_one,
919 sizeof (t->type_index_plus_one));
920 serialize_integer (m, t[i].n_enum_strings,
921 sizeof (t[i].n_enum_strings));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700922 for (j = 0; j < t[i].n_enum_strings; j++)
923 serialize_cstring (m, t[i].enum_strings_vector[j]);
924 }
925}
926
927static void
928unserialize_elog_event_type (serialize_main_t * m, va_list * va)
929{
Dave Barachc3799992016-08-15 11:12:27 -0400930 elog_event_type_t *t = va_arg (*va, elog_event_type_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700931 int n = va_arg (*va, int);
932 int i, j;
933 for (i = 0; i < n; i++)
934 {
935 unserialize_cstring (m, &t[i].format);
936 unserialize_cstring (m, &t[i].format_args);
Dave Barachc3799992016-08-15 11:12:27 -0400937 unserialize_integer (m, &t[i].type_index_plus_one,
938 sizeof (t->type_index_plus_one));
939 unserialize_integer (m, &t[i].n_enum_strings,
940 sizeof (t[i].n_enum_strings));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700941 vec_resize (t[i].enum_strings_vector, t[i].n_enum_strings);
942 for (j = 0; j < t[i].n_enum_strings; j++)
943 unserialize_cstring (m, &t[i].enum_strings_vector[j]);
944 }
945}
946
947static void
948serialize_elog_track (serialize_main_t * m, va_list * va)
949{
Dave Barachc3799992016-08-15 11:12:27 -0400950 elog_track_t *t = va_arg (*va, elog_track_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700951 int n = va_arg (*va, int);
952 int i;
953 for (i = 0; i < n; i++)
954 {
955 serialize_cstring (m, t[i].name);
956 }
957}
958
959static void
960unserialize_elog_track (serialize_main_t * m, va_list * va)
961{
Dave Barachc3799992016-08-15 11:12:27 -0400962 elog_track_t *t = va_arg (*va, elog_track_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700963 int n = va_arg (*va, int);
964 int i;
965 for (i = 0; i < n; i++)
966 {
967 unserialize_cstring (m, &t[i].name);
968 }
969}
970
971static void
972serialize_elog_time_stamp (serialize_main_t * m, va_list * va)
973{
Dave Barachc3799992016-08-15 11:12:27 -0400974 elog_time_stamp_t *st = va_arg (*va, elog_time_stamp_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700975 serialize (m, serialize_64, st->os_nsec);
976 serialize (m, serialize_64, st->cpu);
977}
978
979static void
980unserialize_elog_time_stamp (serialize_main_t * m, va_list * va)
981{
Dave Barachc3799992016-08-15 11:12:27 -0400982 elog_time_stamp_t *st = va_arg (*va, elog_time_stamp_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700983 unserialize (m, unserialize_64, &st->os_nsec);
984 unserialize (m, unserialize_64, &st->cpu);
985}
986
Dave Barachc3799992016-08-15 11:12:27 -0400987static char *elog_serialize_magic = "elog v0";
Ed Warnickecb9cada2015-12-08 15:45:58 -0700988
989void
990serialize_elog_main (serialize_main_t * m, va_list * va)
991{
Dave Barachc3799992016-08-15 11:12:27 -0400992 elog_main_t *em = va_arg (*va, elog_main_t *);
993 elog_event_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700994
995 serialize_magic (m, elog_serialize_magic, strlen (elog_serialize_magic));
996
997 serialize_integer (m, em->event_ring_size, sizeof (u32));
998
999 elog_time_now (&em->serialize_time);
1000 serialize (m, serialize_elog_time_stamp, &em->serialize_time);
1001 serialize (m, serialize_elog_time_stamp, &em->init_time);
1002
1003 vec_serialize (m, em->event_types, serialize_elog_event_type);
1004 vec_serialize (m, em->tracks, serialize_elog_track);
1005 vec_serialize (m, em->string_table, serialize_vec_8);
1006
1007 /* Free old events (cached) in case they have changed. */
1008 vec_free (em->events);
1009 elog_get_events (em);
1010
1011 serialize_integer (m, vec_len (em->events), sizeof (u32));
1012
1013 /* SMP logs can easily have local time paradoxes... */
Matus Fabiand2dc3df2015-12-14 10:31:33 -05001014 vec_sort_with_function (em->events, elog_cmp);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001015
Dave Barachc3799992016-08-15 11:12:27 -04001016 vec_foreach (e, em->events) serialize (m, serialize_elog_event, em, e);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001017}
1018
1019void
1020unserialize_elog_main (serialize_main_t * m, va_list * va)
1021{
Dave Barachc3799992016-08-15 11:12:27 -04001022 elog_main_t *em = va_arg (*va, elog_main_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001023 uword i;
1024 u32 rs;
1025
1026 unserialize_check_magic (m, elog_serialize_magic,
1027 strlen (elog_serialize_magic));
1028
1029 unserialize_integer (m, &rs, sizeof (u32));
1030 em->event_ring_size = rs;
1031 elog_init (em, em->event_ring_size);
1032
1033 unserialize (m, unserialize_elog_time_stamp, &em->serialize_time);
1034 unserialize (m, unserialize_elog_time_stamp, &em->init_time);
1035 em->nsec_per_cpu_clock = elog_nsec_per_clock (em);
1036
1037 vec_unserialize (m, &em->event_types, unserialize_elog_event_type);
1038 for (i = 0; i < vec_len (em->event_types); i++)
1039 new_event_type (em, i);
1040
1041 vec_unserialize (m, &em->tracks, unserialize_elog_track);
1042 vec_unserialize (m, &em->string_table, unserialize_vec_8);
1043
1044 {
1045 u32 ne;
Dave Barachc3799992016-08-15 11:12:27 -04001046 elog_event_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001047
1048 unserialize_integer (m, &ne, sizeof (u32));
1049 vec_resize (em->events, ne);
1050 vec_foreach (e, em->events)
1051 unserialize (m, unserialize_elog_event, em, e);
1052 }
1053}
Dave Barachc3799992016-08-15 11:12:27 -04001054
1055/*
1056 * fd.io coding-style-patch-verification: ON
1057 *
1058 * Local Variables:
1059 * eval: (c-set-style "gnu")
1060 * End:
1061 */