blob: 12e3f5d4bd81ab58e224f96496b9bc144ba47658 [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
Dave Barach903fd512017-04-01 11:07:40 -040080 t->type_index_plus_one = i + 1;
Ed Warnickecb9cada2015-12-08 15:45:58 -070081 hash_set_mem (em->event_type_by_format, t->format, i);
82}
83
84static uword
85find_or_create_type (elog_main_t * em, elog_event_type_t * t)
86{
Dave Barachc3799992016-08-15 11:12:27 -040087 uword *p = hash_get_mem (em->event_type_by_format, t->format);
Ed Warnickecb9cada2015-12-08 15:45:58 -070088 uword i;
89
90 if (p)
91 i = p[0];
92 else
93 {
94 i = vec_len (em->event_types);
95 vec_add1 (em->event_types, t[0]);
96 new_event_type (em, i);
97 }
98
99 return i;
100}
101
102/* External function to register types. */
Dave Barachc3799992016-08-15 11:12:27 -0400103word
104elog_event_type_register (elog_main_t * em, elog_event_type_t * t)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700105{
Dave Barachc3799992016-08-15 11:12:27 -0400106 elog_event_type_t *static_type = t;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700107 word l;
108
109 elog_lock (em);
110
111 l = vec_len (em->event_types);
112
113 t->type_index_plus_one = 1 + l;
114
115 ASSERT (t->format);
116
117 /* If format args are not specified try to be smart about providing defaults
118 so most of the time user does not have to specify them. */
Dave Barachc3799992016-08-15 11:12:27 -0400119 if (!t->format_args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700120 {
121 uword i, l;
Dave Barachc3799992016-08-15 11:12:27 -0400122 char *this_arg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700123
124 l = strlen (t->format);
125 for (i = 0; i < l; i++)
126 {
127 if (t->format[i] != '%')
128 continue;
129 if (i + 1 >= l)
130 continue;
Dave Barachc3799992016-08-15 11:12:27 -0400131 if (t->format[i + 1] == '%') /* %% */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700132 continue;
133
Dave Barachc3799992016-08-15 11:12:27 -0400134 switch (t->format[i + 1])
135 {
136 default:
137 case 'd':
138 case 'x':
139 case 'u':
140 this_arg = "i4"; /* size of u32 */
141 break;
142 case 'f':
143 this_arg = "f8"; /* defaults to f64 */
144 break;
145 case 's':
146 this_arg = "s0"; /* defaults to null terminated string. */
147 break;
148 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700149
Dave Barachc3799992016-08-15 11:12:27 -0400150 t->format_args =
151 (char *) format ((u8 *) t->format_args, "%s", this_arg);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700152 }
153
154 /* Null terminate. */
155 vec_add1 (t->format_args, 0);
Dave Barachc3799992016-08-15 11:12:27 -0400156 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700157
158 vec_add1 (em->event_types, t[0]);
159
160 t = em->event_types + l;
161
162 /* Make copies of strings for hashing etc. */
163 if (t->function)
164 t->format = (char *) format (0, "%s %s%c", t->function, t->format, 0);
165 else
166 t->format = (char *) format (0, "%s%c", t->format, 0);
167
168 t->format_args = (char *) format (0, "%s%c", t->format_args, 0);
169
170 /* Construct string table. */
171 {
172 uword i;
173 t->n_enum_strings = static_type->n_enum_strings;
174 for (i = 0; i < t->n_enum_strings; i++)
175 {
Dave Barachc3799992016-08-15 11:12:27 -0400176 if (!static_type->enum_strings[i])
Ed Warnickecb9cada2015-12-08 15:45:58 -0700177 static_type->enum_strings[i] = "MISSING";
Dave Barachc3799992016-08-15 11:12:27 -0400178 vec_add1 (t->enum_strings_vector,
179 (char *) format (0, "%s%c", static_type->enum_strings[i],
180 0));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700181 }
182 }
183
184 new_event_type (em, l);
Dave Barachc3799992016-08-15 11:12:27 -0400185 elog_unlock (em);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700186
187 return l;
188}
189
Dave Barachc3799992016-08-15 11:12:27 -0400190word
191elog_track_register (elog_main_t * em, elog_track_t * t)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700192{
193 word l;
194
195 elog_lock (em);
196
197 l = vec_len (em->tracks);
198
199 t->track_index_plus_one = 1 + l;
200
201 ASSERT (t->name);
202
203 vec_add1 (em->tracks, t[0]);
204
205 t = em->tracks + l;
206
207 t->name = (char *) format (0, "%s%c", t->name, 0);
208
209 elog_unlock (em);
210
211 return l;
212}
213
Dave Barachc3799992016-08-15 11:12:27 -0400214static uword
215parse_2digit_decimal (char *p, uword * number)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700216{
217 uword i = 0;
218 u8 digits[2];
219
220 digits[0] = digits[1] = 0;
221 while (p[i] >= '0' && p[i] <= '9')
222 {
223 if (i >= 2)
224 break;
225 digits[i] = p[i] - '0';
226 i++;
227 }
228
229 if (i >= 1 && i <= 2)
230 {
231 if (i == 1)
232 *number = digits[0];
233 else
234 *number = 10 * digits[0] + digits[1];
235 return i;
236 }
237 else
238 return 0;
239}
240
Dave Barachc3799992016-08-15 11:12:27 -0400241static u8 *
242fixed_format (u8 * s, char *fmt, char *result, uword * result_len)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700243{
Dave Barachc3799992016-08-15 11:12:27 -0400244 char *f = fmt;
245 char *percent;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700246 uword l = 0;
247
248 while (1)
249 {
250 if (f[0] == 0)
251 break;
252 if (f[0] == '%' && f[1] != '%')
253 break;
254 f++;
255 }
256 if (f > fmt)
257 vec_add (s, fmt, f - fmt);
258
259 if (f[0] != '%')
260 goto done;
261
262 /* Skip percent. */
263 percent = f++;
264
265 /* Skip possible +-= justification. */
266 f += f[0] == '+' || f[0] == '-' || f[0] == '=';
267
268 /* Skip possible X.Y width. */
269 while ((f[0] >= '0' && f[0] <= '9') || f[0] == '.')
270 f++;
271
272 /* Skip wlL as in e.g. %Ld. */
273 f += f[0] == 'w' || f[0] == 'l' || f[0] == 'L';
274
275 /* Finally skip format letter. */
276 f += f[0] != 0;
277
278 ASSERT (*result_len > f - percent);
279 l = clib_min (f - percent, *result_len - 1);
Damjan Marionf1213b82016-03-13 02:22:06 +0100280 clib_memcpy (result, percent, l);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700281 result[l] = 0;
282
Dave Barachc3799992016-08-15 11:12:27 -0400283done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700284 *result_len = f - fmt;
285 return s;
286}
287
Dave Barachc3799992016-08-15 11:12:27 -0400288u8 *
289format_elog_event (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700290{
Dave Barachc3799992016-08-15 11:12:27 -0400291 elog_main_t *em = va_arg (*va, elog_main_t *);
292 elog_event_t *e = va_arg (*va, elog_event_t *);
293 elog_event_type_t *t;
294 char *a, *f;
295 void *d = (u8 *) e->data;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700296 char arg_format[64];
297
298 t = vec_elt_at_index (em->event_types, e->type);
299
300 f = t->format;
301 a = t->format_args;
302 while (1)
303 {
304 uword n_bytes = 0, n_digits, f_bytes = 0;
305
306 f_bytes = sizeof (arg_format);
307 s = fixed_format (s, f, arg_format, &f_bytes);
308 f += f_bytes;
309
310 if (a == 0 || a[0] == 0)
311 {
312 /* Format must also be at end. */
313 ASSERT (f[0] == 0);
314 break;
315 }
316
317 /* Don't go past end of event data. */
318 ASSERT (d < (void *) (e->data + sizeof (e->data)));
319
320 n_digits = parse_2digit_decimal (a + 1, &n_bytes);
321 switch (a[0])
322 {
323 case 'i':
324 case 't':
325 case 'T':
326 {
327 u32 i = 0;
328 u64 l = 0;
329
330 if (n_bytes == 1)
331 i = ((u8 *) d)[0];
332 else if (n_bytes == 2)
333 i = clib_mem_unaligned (d, u16);
334 else if (n_bytes == 4)
335 i = clib_mem_unaligned (d, u32);
336 else if (n_bytes == 8)
337 l = clib_mem_unaligned (d, u64);
338 else
339 ASSERT (0);
340 if (a[0] == 't')
341 {
Dave Barachc3799992016-08-15 11:12:27 -0400342 char *e =
343 vec_elt (t->enum_strings_vector, n_bytes == 8 ? l : i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700344 s = format (s, arg_format, e);
345 }
346 else if (a[0] == 'T')
347 {
Dave Barachc3799992016-08-15 11:12:27 -0400348 char *e =
349 vec_elt_at_index (em->string_table, n_bytes == 8 ? l : i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700350 s = format (s, arg_format, e);
351 }
352 else if (n_bytes == 8)
353 s = format (s, arg_format, l);
354 else
355 s = format (s, arg_format, i);
356 }
357 break;
358
359 case 'f':
360 {
361 f64 x = 0;
362 if (n_bytes == 4)
363 x = clib_mem_unaligned (d, f32);
364 else if (n_bytes == 8)
365 x = clib_mem_unaligned (d, f64);
366 else
367 ASSERT (0);
368 s = format (s, arg_format, x);
369 }
370 break;
371
372 case 's':
373 s = format (s, arg_format, d);
374 if (n_bytes == 0)
375 n_bytes = strlen (d) + 1;
376 break;
377
378 default:
379 ASSERT (0);
380 break;
381 }
382
383 ASSERT (n_digits > 0 && n_digits <= 2);
384 a += 1 + n_digits;
385 d += n_bytes;
386 }
387
388 return s;
389}
390
Dave Barachc3799992016-08-15 11:12:27 -0400391u8 *
392format_elog_track (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700393{
Dave Barachc3799992016-08-15 11:12:27 -0400394 elog_main_t *em = va_arg (*va, elog_main_t *);
395 elog_event_t *e = va_arg (*va, elog_event_t *);
396 elog_track_t *t = vec_elt_at_index (em->tracks, e->track);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700397 return format (s, "%s", t->name);
398}
399
Dave Barachc3799992016-08-15 11:12:27 -0400400void
401elog_time_now (elog_time_stamp_t * et)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700402{
403 u64 cpu_time_now, os_time_now_nsec;
Dave Barach903fd512017-04-01 11:07:40 -0400404 struct timespec ts;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700405
406#ifdef CLIB_UNIX
407 {
408#include <sys/syscall.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -0700409 syscall (SYS_clock_gettime, CLOCK_REALTIME, &ts);
410 cpu_time_now = clib_cpu_time_now ();
Dave Barach903fd512017-04-01 11:07:40 -0400411 /* Subtract 3/30/2017's worth of seconds to retain precision */
412 os_time_now_nsec = 1e9 * (ts.tv_sec - 1490885108) + ts.tv_nsec;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700413 }
414#else
415 cpu_time_now = clib_cpu_time_now ();
416 os_time_now_nsec = 0;
417#endif
418
419 et->cpu = cpu_time_now;
420 et->os_nsec = os_time_now_nsec;
421}
422
423always_inline i64
Dave Barachc3799992016-08-15 11:12:27 -0400424elog_time_stamp_diff_os_nsec (elog_time_stamp_t * t1, elog_time_stamp_t * t2)
425{
426 return (i64) t1->os_nsec - (i64) t2->os_nsec;
427}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700428
429always_inline i64
Dave Barachc3799992016-08-15 11:12:27 -0400430elog_time_stamp_diff_cpu (elog_time_stamp_t * t1, elog_time_stamp_t * t2)
431{
432 return (i64) t1->cpu - (i64) t2->cpu;
433}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700434
435always_inline f64
436elog_nsec_per_clock (elog_main_t * em)
437{
438 return ((f64) elog_time_stamp_diff_os_nsec (&em->serialize_time,
439 &em->init_time)
440 / (f64) elog_time_stamp_diff_cpu (&em->serialize_time,
441 &em->init_time));
442}
443
Dave Barachc3799992016-08-15 11:12:27 -0400444void
445elog_alloc (elog_main_t * em, u32 n_events)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700446{
447 if (em->event_ring)
448 vec_free (em->event_ring);
Dave Barachc3799992016-08-15 11:12:27 -0400449
Ed Warnickecb9cada2015-12-08 15:45:58 -0700450 /* Ring size must be a power of 2. */
451 em->event_ring_size = n_events = max_pow2 (n_events);
452
453 /* Leave an empty ievent at end so we can always speculatively write
454 and event there (possibly a long form event). */
455 vec_resize_aligned (em->event_ring, n_events, CLIB_CACHE_LINE_BYTES);
456}
457
Dave Barachc3799992016-08-15 11:12:27 -0400458void
459elog_init (elog_main_t * em, u32 n_events)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700460{
461 memset (em, 0, sizeof (em[0]));
462
463 em->lock = 0;
464
465 if (n_events > 0)
466 elog_alloc (em, n_events);
467
468 clib_time_init (&em->cpu_timer);
469
470 em->n_total_events_disable_limit = ~0;
471
472 /* Make track 0. */
473 em->default_track.name = "default";
474 elog_track_register (em, &em->default_track);
475
476 elog_time_now (&em->init_time);
477}
478
479/* Returns number of events in ring and start index. */
Dave Barachc3799992016-08-15 11:12:27 -0400480static uword
481elog_event_range (elog_main_t * em, uword * lo)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700482{
483 uword l = em->event_ring_size;
484 u64 i = em->n_total_events;
485
486 /* Ring never wrapped? */
487 if (i <= (u64) l)
488 {
Dave Barachc3799992016-08-15 11:12:27 -0400489 if (lo)
490 *lo = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700491 return i;
492 }
493 else
494 {
Dave Barachc3799992016-08-15 11:12:27 -0400495 if (lo)
496 *lo = i & (l - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700497 return l;
498 }
499}
500
Dave Barachc3799992016-08-15 11:12:27 -0400501elog_event_t *
502elog_peek_events (elog_main_t * em)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700503{
Dave Barachc3799992016-08-15 11:12:27 -0400504 elog_event_t *e, *f, *es = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700505 uword i, j, n;
506
507 n = elog_event_range (em, &j);
508 for (i = 0; i < n; i++)
509 {
510 vec_add2 (es, e, 1);
511 f = vec_elt_at_index (em->event_ring, j);
512 e[0] = f[0];
513
514 /* Convert absolute time from cycles to seconds from start. */
Dave Barachc3799992016-08-15 11:12:27 -0400515 e->time =
516 (e->time_cycles -
517 em->init_time.cpu) * em->cpu_timer.seconds_per_clock;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700518
519 j = (j + 1) & (em->event_ring_size - 1);
520 }
521
522 return es;
523}
524
525/* Add a formatted string to the string table. */
Dave Barachc3799992016-08-15 11:12:27 -0400526u32
527elog_string (elog_main_t * em, char *fmt, ...)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700528{
529 u32 offset;
530 va_list va;
531
532 va_start (va, fmt);
533 offset = vec_len (em->string_table);
534 em->string_table = (char *) va_format ((u8 *) em->string_table, fmt, &va);
535 va_end (va);
536
537 /* Null terminate string if it is not already. */
538 if (vec_end (em->string_table)[-1] != 0)
539 vec_add1 (em->string_table, 0);
540
541 return offset;
542}
543
Dave Barachc3799992016-08-15 11:12:27 -0400544elog_event_t *
545elog_get_events (elog_main_t * em)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700546{
Dave Barachc3799992016-08-15 11:12:27 -0400547 if (!em->events)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700548 em->events = elog_peek_events (em);
549 return em->events;
550}
551
Dave Barachc3799992016-08-15 11:12:27 -0400552static void
553maybe_fix_string_table_offset (elog_event_t * e,
554 elog_event_type_t * t, u32 offset)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700555{
Dave Barachc3799992016-08-15 11:12:27 -0400556 void *d = (u8 *) e->data;
557 char *a;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700558
559 if (offset == 0)
560 return;
561
562 a = t->format_args;
563
564 while (1)
565 {
566 uword n_bytes = 0, n_digits;
567
568 if (a[0] == 0)
Dave Barachc3799992016-08-15 11:12:27 -0400569 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700570
571 /* Don't go past end of event data. */
572 ASSERT (d < (void *) (e->data + sizeof (e->data)));
573
574 n_digits = parse_2digit_decimal (a + 1, &n_bytes);
575 switch (a[0])
576 {
577 case 'T':
Dave Barachc3799992016-08-15 11:12:27 -0400578 ASSERT (n_bytes == 4);
579 clib_mem_unaligned (d, u32) += offset;
580 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700581
582 case 'i':
583 case 't':
584 case 'f':
585 case 's':
586 break;
587
588 default:
589 ASSERT (0);
590 break;
591 }
592
593 ASSERT (n_digits > 0 && n_digits <= 2);
594 a += 1 + n_digits;
595 d += n_bytes;
596 }
597}
598
Dave Barachc3799992016-08-15 11:12:27 -0400599static int
600elog_cmp (void *a1, void *a2)
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500601{
Dave Barachc3799992016-08-15 11:12:27 -0400602 elog_event_t *e1 = a1;
603 elog_event_t *e2 = a2;
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500604
Dave Barach903fd512017-04-01 11:07:40 -0400605 if (e1->time < e2->time)
606 return -1;
607
608 if (e1->time > e2->time)
609 return 1;
610
611 return 0;
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500612}
613
Dave Barach903fd512017-04-01 11:07:40 -0400614/*
615 * merge two event logs. Complicated and cranky.
616 */
Dave Barachc3799992016-08-15 11:12:27 -0400617void
Dave Barach903fd512017-04-01 11:07:40 -0400618elog_merge (elog_main_t * dst, u8 * dst_tag, elog_main_t * src, u8 * src_tag,
619 f64 align_tweak)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700620{
Dave Barachc3799992016-08-15 11:12:27 -0400621 elog_event_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700622 uword l;
623 u32 string_table_offset_for_src_events;
624 u32 track_offset_for_src_tracks;
625 elog_track_t newt;
626 int i;
627
Dave Barachc3799992016-08-15 11:12:27 -0400628 memset (&newt, 0, sizeof (newt));
Dave Barachf9c231e2016-08-05 10:10:18 -0400629
Dave Barach903fd512017-04-01 11:07:40 -0400630 /* Acquire src and dst events */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700631 elog_get_events (src);
632 elog_get_events (dst);
633
634 string_table_offset_for_src_events = vec_len (dst->string_table);
635 vec_append (dst->string_table, src->string_table);
636
637 l = vec_len (dst->events);
Dave Barach903fd512017-04-01 11:07:40 -0400638 vec_append (dst->events, src->events);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700639
640 /* Prepend the supplied tag (if any) to all dst track names */
641 if (dst_tag)
642 {
Dave Barachc3799992016-08-15 11:12:27 -0400643 for (i = 0; i < vec_len (dst->tracks); i++)
644 {
645 elog_track_t *t = vec_elt_at_index (dst->tracks, i);
646 char *new_name;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700647
Dave Barachc3799992016-08-15 11:12:27 -0400648 new_name = (char *) format (0, "%s:%s%c", dst_tag, t->name, 0);
649 vec_free (t->name);
650 t->name = new_name;
651 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700652 }
Dave Barachc3799992016-08-15 11:12:27 -0400653
Dave Barach903fd512017-04-01 11:07:40 -0400654 /*
655 * Remember where we started allocating new tracks while merging
656 */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700657 track_offset_for_src_tracks = vec_len (dst->tracks);
Dave Barachc3799992016-08-15 11:12:27 -0400658
Ed Warnickecb9cada2015-12-08 15:45:58 -0700659 /* Copy / tag source tracks */
660 for (i = 0; i < vec_len (src->tracks); i++)
661 {
Dave Barachc3799992016-08-15 11:12:27 -0400662 elog_track_t *t = vec_elt_at_index (src->tracks, i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700663 if (src_tag)
Dave Barachc3799992016-08-15 11:12:27 -0400664 newt.name = (char *) format (0, "%s:%s%c", src_tag, t->name, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700665 else
Dave Barachc3799992016-08-15 11:12:27 -0400666 newt.name = (char *) format (0, "%s%c", t->name, 0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700667 (void) elog_track_register (dst, &newt);
668 vec_free (newt.name);
669 }
Dave Barachc3799992016-08-15 11:12:27 -0400670
Ed Warnickecb9cada2015-12-08 15:45:58 -0700671 /* Across all (copied) src events... */
672 for (e = dst->events + l; e < vec_end (dst->events); e++)
673 {
Dave Barachc3799992016-08-15 11:12:27 -0400674 elog_event_type_t *t = vec_elt_at_index (src->event_types, e->type);
675
Ed Warnickecb9cada2015-12-08 15:45:58 -0700676 /* Remap type from src -> dst. */
677 e->type = find_or_create_type (dst, t);
678
679 /* Remap string table offsets for 'T' format args */
Dave Barachc3799992016-08-15 11:12:27 -0400680 maybe_fix_string_table_offset (e, t,
681 string_table_offset_for_src_events);
682
Ed Warnickecb9cada2015-12-08 15:45:58 -0700683 /* Remap track */
684 e->track += track_offset_for_src_tracks;
685 }
686
687 /* Adjust event times for relative starting times of event streams. */
688 {
689 f64 dt_event, dt_os_nsec, dt_clock_nsec;
690
691 /* Set clock parameters if dst was not generated by unserialize. */
692 if (dst->serialize_time.cpu == 0)
693 {
694 dst->init_time = src->init_time;
695 dst->serialize_time = src->serialize_time;
696 dst->nsec_per_cpu_clock = src->nsec_per_cpu_clock;
697 }
698
Dave Barachc3799992016-08-15 11:12:27 -0400699 dt_os_nsec =
700 elog_time_stamp_diff_os_nsec (&src->init_time, &dst->init_time);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700701
702 dt_event = dt_os_nsec;
Dave Barachc3799992016-08-15 11:12:27 -0400703 dt_clock_nsec =
704 (elog_time_stamp_diff_cpu (&src->init_time, &dst->init_time) * .5 *
705 (dst->nsec_per_cpu_clock + src->nsec_per_cpu_clock));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700706
Dave Barach903fd512017-04-01 11:07:40 -0400707 /*
708 * Heuristic to see if src/dst came from same time source.
709 * If frequencies are "the same" and os clock and cpu clock agree
710 * to within 100e-9 secs about time difference between src/dst
711 * init_time, then we use cpu clock. Otherwise we use OS clock.
712 *
713 * When merging event logs from different systems, time paradoxes
714 * at the O(1ms) level are to be expected. Hence, the "align_tweak"
715 * parameter. If two events logged on different processors are known
716 * to occur in a specific order - and with a reasonably-estimated
717 * interval - supply a non-zero "align_tweak" parameter
718 */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700719 if (fabs (src->nsec_per_cpu_clock - dst->nsec_per_cpu_clock) < 1e-2
720 && fabs (dt_os_nsec - dt_clock_nsec) < 100)
721 dt_event = dt_clock_nsec;
722
723 /* Convert to seconds. */
724 dt_event *= 1e-9;
725
Dave Barach903fd512017-04-01 11:07:40 -0400726 /*
727 * Move the earlier set of events later, to avoid creating
728 * events which preceed the Big Bang (aka have negative timestamps).
729 *
730 * Not to any scale, we have something like the following picture:
731 *
732 * DST capture start point
733 * ^
734 * +--- dt_event --+
735 * v
736 * SRC capture start point
737 *
738 * In this case dt_event is positive, src started after dst,
739 * to put src events onto a common timebase we have to move them
740 * forward in time. Naturally, the opposite case is
741 * possible, too: dt_event will be negative, and so we have to
742 * move dst events forward in time by the |dt_event|.
743 * In both cases, we add align_tweak.
744 */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700745 if (dt_event > 0)
746 {
747 /* Src started after dst. */
748 for (e = dst->events + l; e < vec_end (dst->events); e++)
Dave Barach903fd512017-04-01 11:07:40 -0400749 e->time += dt_event + align_tweak;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700750 }
751 else
752 {
753 /* Dst started after src. */
Dave Barach903fd512017-04-01 11:07:40 -0400754 dt_event = -dt_event;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700755 for (e = dst->events + 0; e < dst->events + l; e++)
Dave Barach903fd512017-04-01 11:07:40 -0400756 e->time += dt_event + align_tweak;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700757 }
758 }
759
760 /* Sort events by increasing time. */
Matus Fabiand2dc3df2015-12-14 10:31:33 -0500761 vec_sort_with_function (dst->events, elog_cmp);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700762
Dave Barach903fd512017-04-01 11:07:40 -0400763 dst->n_total_events = vec_len (dst->events);
764
Ed Warnickecb9cada2015-12-08 15:45:58 -0700765 /* Recreate the event ring or the results won't serialize */
766 {
767 int i;
768
769 ASSERT (dst->cpu_timer.seconds_per_clock);
770
771 elog_alloc (dst, vec_len (dst->events));
Dave Barachc3799992016-08-15 11:12:27 -0400772 for (i = 0; i < vec_len (dst->events); i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700773 {
Dave Barachc3799992016-08-15 11:12:27 -0400774 elog_event_t *es, *ed;
775
776 es = dst->events + i;
777 ed = dst->event_ring + i;
778
779 ed[0] = es[0];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700780 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700781 }
782}
783
784static void
785serialize_elog_event (serialize_main_t * m, va_list * va)
786{
Dave Barachc3799992016-08-15 11:12:27 -0400787 elog_main_t *em = va_arg (*va, elog_main_t *);
788 elog_event_t *e = va_arg (*va, elog_event_t *);
789 elog_event_type_t *t = vec_elt_at_index (em->event_types, e->type);
790 u8 *d = e->data;
791 u8 *p = (u8 *) t->format_args;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700792
793 serialize_integer (m, e->type, sizeof (e->type));
794 serialize_integer (m, e->track, sizeof (e->track));
795 serialize (m, serialize_f64, e->time);
796
797 while (*p)
798 {
799 uword n_digits, n_bytes = 0;
800
801 n_digits = parse_2digit_decimal ((char *) p + 1, &n_bytes);
802
803 switch (p[0])
804 {
805 case 'i':
806 case 't':
807 case 'T':
808 if (n_bytes == 1)
809 serialize_integer (m, d[0], sizeof (u8));
810 else if (n_bytes == 2)
811 serialize_integer (m, clib_mem_unaligned (d, u16), sizeof (u16));
812 else if (n_bytes == 4)
813 serialize_integer (m, clib_mem_unaligned (d, u32), sizeof (u32));
814 else if (n_bytes == 8)
815 serialize (m, serialize_64, clib_mem_unaligned (d, u64));
816 else
817 ASSERT (0);
818 break;
819
820 case 's':
821 serialize_cstring (m, (char *) d);
822 if (n_bytes == 0)
823 n_bytes = strlen ((char *) d) + 1;
824 break;
825
826 case 'f':
827 if (n_bytes == 4)
828 serialize (m, serialize_f32, clib_mem_unaligned (d, f32));
829 else if (n_bytes == 8)
830 serialize (m, serialize_f64, clib_mem_unaligned (d, f64));
831 else
832 ASSERT (0);
833 break;
834
835 default:
836 ASSERT (0);
837 break;
838 }
839
840 p += 1 + n_digits;
841 d += n_bytes;
842 }
843}
844
845static void
846unserialize_elog_event (serialize_main_t * m, va_list * va)
847{
Dave Barachc3799992016-08-15 11:12:27 -0400848 elog_main_t *em = va_arg (*va, elog_main_t *);
849 elog_event_t *e = va_arg (*va, elog_event_t *);
850 elog_event_type_t *t;
851 u8 *p, *d;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700852
853 {
854 u16 tmp[2];
855
856 unserialize_integer (m, &tmp[0], sizeof (e->type));
857 unserialize_integer (m, &tmp[1], sizeof (e->track));
858
859 e->type = tmp[0];
860 e->track = tmp[1];
861
862 /* Make sure it fits. */
863 ASSERT (e->type == tmp[0]);
864 ASSERT (e->track == tmp[1]);
865 }
866
867 t = vec_elt_at_index (em->event_types, e->type);
868
869 unserialize (m, unserialize_f64, &e->time);
870
871 d = e->data;
872 p = (u8 *) t->format_args;
873
874 while (p && *p)
875 {
876 uword n_digits, n_bytes = 0;
877 u32 tmp;
878
879 n_digits = parse_2digit_decimal ((char *) p + 1, &n_bytes);
880
881 switch (p[0])
882 {
883 case 'i':
884 case 't':
885 case 'T':
886 if (n_bytes == 1)
887 {
888 unserialize_integer (m, &tmp, sizeof (u8));
889 d[0] = tmp;
890 }
891 else if (n_bytes == 2)
892 {
893 unserialize_integer (m, &tmp, sizeof (u16));
894 clib_mem_unaligned (d, u16) = tmp;
895 }
896 else if (n_bytes == 4)
897 {
898 unserialize_integer (m, &tmp, sizeof (u32));
899 clib_mem_unaligned (d, u32) = tmp;
900 }
901 else if (n_bytes == 8)
902 {
903 u64 x;
904 unserialize (m, unserialize_64, &x);
905 clib_mem_unaligned (d, u64) = x;
906 }
907 else
908 ASSERT (0);
909 break;
910
Dave Barachc3799992016-08-15 11:12:27 -0400911 case 's':
912 {
913 char *t;
914 unserialize_cstring (m, &t);
915 if (n_bytes == 0)
916 n_bytes = strlen (t) + 1;
917 clib_memcpy (d, t, clib_min (n_bytes, vec_len (t)));
918 vec_free (t);
919 break;
920 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700921
922 case 'f':
923 if (n_bytes == 4)
924 {
925 f32 x;
926 unserialize (m, unserialize_f32, &x);
927 clib_mem_unaligned (d, f32) = x;
928 }
929 else if (n_bytes == 8)
930 {
931 f64 x;
932 unserialize (m, unserialize_f64, &x);
933 clib_mem_unaligned (d, f64) = x;
934 }
935 else
936 ASSERT (0);
937 break;
938
939 default:
940 ASSERT (0);
941 break;
942 }
943
944 p += 1 + n_digits;
945 d += n_bytes;
946 }
947}
948
949static void
950serialize_elog_event_type (serialize_main_t * m, va_list * va)
951{
Dave Barachc3799992016-08-15 11:12:27 -0400952 elog_event_type_t *t = va_arg (*va, elog_event_type_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700953 int n = va_arg (*va, int);
954 int i, j;
955 for (i = 0; i < n; i++)
956 {
957 serialize_cstring (m, t[i].format);
958 serialize_cstring (m, t[i].format_args);
Dave Barachc3799992016-08-15 11:12:27 -0400959 serialize_integer (m, t[i].type_index_plus_one,
960 sizeof (t->type_index_plus_one));
961 serialize_integer (m, t[i].n_enum_strings,
962 sizeof (t[i].n_enum_strings));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700963 for (j = 0; j < t[i].n_enum_strings; j++)
964 serialize_cstring (m, t[i].enum_strings_vector[j]);
965 }
966}
967
968static void
969unserialize_elog_event_type (serialize_main_t * m, va_list * va)
970{
Dave Barachc3799992016-08-15 11:12:27 -0400971 elog_event_type_t *t = va_arg (*va, elog_event_type_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700972 int n = va_arg (*va, int);
973 int i, j;
974 for (i = 0; i < n; i++)
975 {
976 unserialize_cstring (m, &t[i].format);
977 unserialize_cstring (m, &t[i].format_args);
Dave Barachc3799992016-08-15 11:12:27 -0400978 unserialize_integer (m, &t[i].type_index_plus_one,
979 sizeof (t->type_index_plus_one));
980 unserialize_integer (m, &t[i].n_enum_strings,
981 sizeof (t[i].n_enum_strings));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700982 vec_resize (t[i].enum_strings_vector, t[i].n_enum_strings);
983 for (j = 0; j < t[i].n_enum_strings; j++)
984 unserialize_cstring (m, &t[i].enum_strings_vector[j]);
985 }
986}
987
988static void
989serialize_elog_track (serialize_main_t * m, va_list * va)
990{
Dave Barachc3799992016-08-15 11:12:27 -0400991 elog_track_t *t = va_arg (*va, elog_track_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700992 int n = va_arg (*va, int);
993 int i;
994 for (i = 0; i < n; i++)
995 {
996 serialize_cstring (m, t[i].name);
997 }
998}
999
1000static void
1001unserialize_elog_track (serialize_main_t * m, va_list * va)
1002{
Dave Barachc3799992016-08-15 11:12:27 -04001003 elog_track_t *t = va_arg (*va, elog_track_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001004 int n = va_arg (*va, int);
1005 int i;
1006 for (i = 0; i < n; i++)
1007 {
1008 unserialize_cstring (m, &t[i].name);
1009 }
1010}
1011
1012static void
1013serialize_elog_time_stamp (serialize_main_t * m, va_list * va)
1014{
Dave Barachc3799992016-08-15 11:12:27 -04001015 elog_time_stamp_t *st = va_arg (*va, elog_time_stamp_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001016 serialize (m, serialize_64, st->os_nsec);
1017 serialize (m, serialize_64, st->cpu);
1018}
1019
1020static void
1021unserialize_elog_time_stamp (serialize_main_t * m, va_list * va)
1022{
Dave Barachc3799992016-08-15 11:12:27 -04001023 elog_time_stamp_t *st = va_arg (*va, elog_time_stamp_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001024 unserialize (m, unserialize_64, &st->os_nsec);
1025 unserialize (m, unserialize_64, &st->cpu);
1026}
1027
Dave Barachc3799992016-08-15 11:12:27 -04001028static char *elog_serialize_magic = "elog v0";
Ed Warnickecb9cada2015-12-08 15:45:58 -07001029
1030void
1031serialize_elog_main (serialize_main_t * m, va_list * va)
1032{
Dave Barachc3799992016-08-15 11:12:27 -04001033 elog_main_t *em = va_arg (*va, elog_main_t *);
Dave Barach903fd512017-04-01 11:07:40 -04001034 int flush_ring = va_arg (*va, int);
Dave Barachc3799992016-08-15 11:12:27 -04001035 elog_event_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001036
1037 serialize_magic (m, elog_serialize_magic, strlen (elog_serialize_magic));
1038
1039 serialize_integer (m, em->event_ring_size, sizeof (u32));
1040
1041 elog_time_now (&em->serialize_time);
1042 serialize (m, serialize_elog_time_stamp, &em->serialize_time);
1043 serialize (m, serialize_elog_time_stamp, &em->init_time);
1044
1045 vec_serialize (m, em->event_types, serialize_elog_event_type);
1046 vec_serialize (m, em->tracks, serialize_elog_track);
1047 vec_serialize (m, em->string_table, serialize_vec_8);
1048
1049 /* Free old events (cached) in case they have changed. */
Dave Barach903fd512017-04-01 11:07:40 -04001050 if (flush_ring)
1051 {
1052 vec_free (em->events);
1053 elog_get_events (em);
1054 }
Ed Warnickecb9cada2015-12-08 15:45:58 -07001055
1056 serialize_integer (m, vec_len (em->events), sizeof (u32));
1057
1058 /* SMP logs can easily have local time paradoxes... */
Matus Fabiand2dc3df2015-12-14 10:31:33 -05001059 vec_sort_with_function (em->events, elog_cmp);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001060
Dave Barachc3799992016-08-15 11:12:27 -04001061 vec_foreach (e, em->events) serialize (m, serialize_elog_event, em, e);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001062}
1063
1064void
1065unserialize_elog_main (serialize_main_t * m, va_list * va)
1066{
Dave Barachc3799992016-08-15 11:12:27 -04001067 elog_main_t *em = va_arg (*va, elog_main_t *);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001068 uword i;
1069 u32 rs;
1070
1071 unserialize_check_magic (m, elog_serialize_magic,
1072 strlen (elog_serialize_magic));
1073
1074 unserialize_integer (m, &rs, sizeof (u32));
1075 em->event_ring_size = rs;
1076 elog_init (em, em->event_ring_size);
1077
1078 unserialize (m, unserialize_elog_time_stamp, &em->serialize_time);
1079 unserialize (m, unserialize_elog_time_stamp, &em->init_time);
1080 em->nsec_per_cpu_clock = elog_nsec_per_clock (em);
1081
1082 vec_unserialize (m, &em->event_types, unserialize_elog_event_type);
1083 for (i = 0; i < vec_len (em->event_types); i++)
1084 new_event_type (em, i);
1085
1086 vec_unserialize (m, &em->tracks, unserialize_elog_track);
1087 vec_unserialize (m, &em->string_table, unserialize_vec_8);
1088
1089 {
1090 u32 ne;
Dave Barachc3799992016-08-15 11:12:27 -04001091 elog_event_t *e;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001092
1093 unserialize_integer (m, &ne, sizeof (u32));
1094 vec_resize (em->events, ne);
1095 vec_foreach (e, em->events)
1096 unserialize (m, unserialize_elog_event, em, e);
1097 }
1098}
Dave Barachc3799992016-08-15 11:12:27 -04001099
1100/*
1101 * fd.io coding-style-patch-verification: ON
1102 *
1103 * Local Variables:
1104 * eval: (c-set-style "gnu")
1105 * End:
1106 */