Dave Barach | 3e07a4a | 2020-04-04 10:05:48 -0400 | [diff] [blame] | 1 | /* |
Dave Barach | 52642c3 | 2016-02-11 19:28:19 -0500 | [diff] [blame] | 2 | *------------------------------------------------------------------ |
| 3 | * Copyright (c) 2005-2016 Cisco and/or its affiliates. |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at: |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include <stdlib.h> |
| 18 | #include <unistd.h> |
| 19 | #include <sys/stat.h> |
Dave Barach | 52642c3 | 2016-02-11 19:28:19 -0500 | [diff] [blame] | 20 | #include <sys/mman.h> |
| 21 | #include <arpa/inet.h> |
| 22 | #include <stdio.h> |
| 23 | #include <gtk/gtk.h> |
| 24 | #include "g2.h" |
| 25 | #include <sys/types.h> |
| 26 | #include <sys/stat.h> |
| 27 | #include <fcntl.h> |
| 28 | #include <string.h> |
| 29 | |
| 30 | /* |
| 31 | * globals |
| 32 | */ |
| 33 | boolean g_little_endian; |
| 34 | event_t *g_events; |
| 35 | ulong g_nevents; |
| 36 | pid_sort_t *g_pids; |
| 37 | pid_sort_t *g_original_pids; |
| 38 | int g_npids; |
| 39 | pid_data_t *g_pid_data_list; |
| 40 | |
| 41 | /* |
| 42 | * locals |
| 43 | */ |
| 44 | pid_data_t **s_pidhash; |
| 45 | |
| 46 | /* |
| 47 | * config parameters |
| 48 | */ |
| 49 | |
| 50 | double ticks_per_ns=1000.0; |
| 51 | boolean ticks_per_ns_set; |
| 52 | |
| 53 | /**************************************************************************** |
| 54 | * event_init |
| 55 | ****************************************************************************/ |
| 56 | |
| 57 | void event_init(void) |
| 58 | { |
| 59 | ulong endian; |
| 60 | char *ep; |
| 61 | char *askstr; |
| 62 | int tmp; |
| 63 | |
| 64 | ep = (char *)&endian; |
| 65 | endian = 0x12345678; |
| 66 | if (*ep != 0x12) |
| 67 | g_little_endian = TRUE; |
| 68 | else |
| 69 | g_little_endian = FALSE; |
| 70 | |
| 71 | askstr = getprop("dont_ask_ticks_per_ns_initially"); |
Dave Barach | 3e07a4a | 2020-04-04 10:05:48 -0400 | [diff] [blame] | 72 | |
Dave Barach | 52642c3 | 2016-02-11 19:28:19 -0500 | [diff] [blame] | 73 | if (askstr && (*askstr == 't' || *askstr == 'T')) { |
| 74 | tmp = atol(getprop_default("ticks_per_ns", 0)); |
| 75 | if (tmp > 0) { |
| 76 | ticks_per_ns = tmp; |
| 77 | ticks_per_ns_set = TRUE; |
| 78 | } |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | /**************************************************************************** |
| 83 | * find_or_add_pid |
| 84 | ****************************************************************************/ |
| 85 | |
| 86 | pid_data_t *find_or_add_pid (ulong pid) |
| 87 | { |
| 88 | pid_data_t *pp; |
| 89 | ulong bucket; |
| 90 | |
| 91 | bucket = pid % PIDHASH_NBUCKETS; |
| 92 | |
| 93 | pp = s_pidhash[bucket]; |
| 94 | |
| 95 | if (pp == 0) { |
| 96 | pp = g_malloc0(sizeof(pid_data_t)); |
| 97 | pp->pid_value = pid; |
| 98 | s_pidhash[bucket] = pp; |
| 99 | g_npids++; |
| 100 | return(pp); |
| 101 | } |
| 102 | while (pp) { |
| 103 | if (pp->pid_value == pid) |
| 104 | return(pp); |
| 105 | pp = pp->next; |
| 106 | } |
| 107 | |
| 108 | pp = g_malloc0(sizeof(pid_data_t)); |
| 109 | pp->pid_value = pid; |
| 110 | pp->next = s_pidhash[bucket]; |
| 111 | s_pidhash[bucket] = pp; |
| 112 | g_npids++; |
| 113 | return(pp); |
| 114 | } |
| 115 | |
| 116 | /**************************************************************************** |
| 117 | * pid_cmp |
| 118 | ****************************************************************************/ |
| 119 | |
| 120 | int pid_cmp(const void *a1, const void *a2) |
| 121 | { |
| 122 | pid_sort_t *p1 = (pid_sort_t *)a1; |
| 123 | pid_sort_t *p2 = (pid_sort_t *)a2; |
| 124 | |
| 125 | if (p1->pid_value < p2->pid_value) |
| 126 | return(-1); |
| 127 | else if (p1->pid_value == p2->pid_value) |
| 128 | return(0); |
| 129 | else |
| 130 | return(1); |
| 131 | } |
| 132 | |
| 133 | /**************************************************************************** |
| 134 | * make_sorted_pid_vector |
| 135 | ****************************************************************************/ |
| 136 | |
| 137 | static void make_sorted_pid_vector(void) |
| 138 | { |
| 139 | pid_data_t *pp; |
| 140 | pid_data_t **p_previous; |
| 141 | pid_sort_t *psp; |
| 142 | int i; |
| 143 | |
Dave Barach | a8ed6bd | 2017-04-04 08:00:23 -0400 | [diff] [blame] | 144 | psp = g_pids = g_malloc0(sizeof(pid_sort_t)*g_npids); |
Dave Barach | 52642c3 | 2016-02-11 19:28:19 -0500 | [diff] [blame] | 145 | |
| 146 | for (i = 0; i < PIDHASH_NBUCKETS; i++) { |
| 147 | pp = s_pidhash[i]; |
| 148 | while(pp) { |
| 149 | psp->pid = pp; |
| 150 | psp->pid_value = pp->pid_value; |
| 151 | psp++; |
| 152 | pp = pp->next; |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | qsort(&g_pids[0], g_npids, sizeof(pid_sort_t), pid_cmp); |
| 157 | |
| 158 | /* put the sort order into the pid objects */ |
| 159 | psp = g_pids; |
| 160 | |
| 161 | /* |
| 162 | * This is rather gross. |
| 163 | * |
| 164 | * We happen to know that whenever this function is called, the hash table |
| 165 | * structure itself is immediately torn down. So the "next" pointers in the |
| 166 | * pid_data_t elements are about to become useless. |
| 167 | * |
| 168 | * So we re-use them, to link all the pid_data_t elements together into a |
| 169 | * single unified linked list, with g_pid_data_list pointing to the head. |
| 170 | * This means we can walk all the pid_data_t objects if we really want to. |
| 171 | * Reading snapshots from disk is one example. |
| 172 | * |
| 173 | * Alternatively we could just leave the hash table in place; this is |
| 174 | * far nicer, but as it happens, trading O(n) lookups for O(1) lookups |
| 175 | * isn't actually a problem for the restricted post-tear-down usage. So for |
| 176 | * now we take the memory savings and swap our hash table for a list. |
| 177 | */ |
| 178 | p_previous = &g_pid_data_list; |
| 179 | for (i = 0; i < g_npids; i++) { |
| 180 | pp = psp->pid; |
| 181 | pp->pid_index = i; |
| 182 | *p_previous = pp; |
| 183 | p_previous = &pp->next; |
| 184 | psp++; |
| 185 | } |
| 186 | *p_previous = NULL; |
| 187 | |
| 188 | /* |
| 189 | * Squirrel away original (sorted) vector, so we can |
| 190 | * toggle between "chase" mode, snapshots, and the original |
Dave Barach | 3e07a4a | 2020-04-04 10:05:48 -0400 | [diff] [blame] | 191 | * display method on short notice |
Dave Barach | 52642c3 | 2016-02-11 19:28:19 -0500 | [diff] [blame] | 192 | */ |
Dave Barach | a8ed6bd | 2017-04-04 08:00:23 -0400 | [diff] [blame] | 193 | g_original_pids = g_malloc0(sizeof(pid_sort_t)*g_npids); |
Dave Barach | 3e07a4a | 2020-04-04 10:05:48 -0400 | [diff] [blame] | 194 | memcpy (g_original_pids, g_pids, sizeof(pid_sort_t)*g_npids); |
Dave Barach | 52642c3 | 2016-02-11 19:28:19 -0500 | [diff] [blame] | 195 | } |
| 196 | |
| 197 | /**************************************************************************** |
| 198 | * read_events |
| 199 | ****************************************************************************/ |
| 200 | |
| 201 | void read_events(char *filename) |
| 202 | { |
| 203 | ulong *ulp; |
| 204 | ulong size; |
| 205 | event_t *ep; |
| 206 | raw_event_t *rep; |
| 207 | ulonglong start_time=0ULL; |
| 208 | ulonglong low_time; |
| 209 | boolean once=TRUE; |
| 210 | int i; |
| 211 | char tmpbuf [128]; |
| 212 | |
| 213 | ulp = (ulong *)mapfile(filename, &size); |
| 214 | |
| 215 | if (ulp == NULL) { |
Dave Barach | 3e07a4a | 2020-04-04 10:05:48 -0400 | [diff] [blame] | 216 | snprintf(tmpbuf, sizeof(tmpbuf), "Couldn't open %s\n", filename); |
Dave Barach | 52642c3 | 2016-02-11 19:28:19 -0500 | [diff] [blame] | 217 | infobox("Read Event Log Failure", tmpbuf); |
| 218 | return; |
| 219 | } |
| 220 | |
| 221 | g_nevents = ntohl(*ulp); |
| 222 | |
| 223 | if (size != (g_nevents*sizeof(raw_event_t) + sizeof(g_nevents))) { |
Dave Barach | 3e07a4a | 2020-04-04 10:05:48 -0400 | [diff] [blame] | 224 | snprintf(tmpbuf, sizeof(tmpbuf), |
| 225 | "%s was damaged, or isn't an event log.\n", filename); |
Dave Barach | 52642c3 | 2016-02-11 19:28:19 -0500 | [diff] [blame] | 226 | infobox("Bad Input File", tmpbuf); |
| 227 | g_nevents = 0; |
| 228 | unmapfile((char *)ulp, size); |
| 229 | return; |
| 230 | } |
| 231 | |
| 232 | rep = (raw_event_t *)(ulp+1); |
| 233 | |
| 234 | if (g_events) |
| 235 | g_free(g_events); |
| 236 | |
| 237 | g_events = (event_t *)g_malloc(g_nevents * sizeof(event_t)); |
| 238 | ep = g_events; |
| 239 | |
| 240 | while (g_npids > 0) { |
| 241 | g_free((g_pids + g_npids-1)->pid); |
| 242 | g_npids--; |
| 243 | } |
| 244 | if (g_pids) { |
| 245 | g_free(g_pids); |
| 246 | g_free(g_original_pids); |
| 247 | g_pids = 0; |
| 248 | g_original_pids = 0; |
| 249 | } |
| 250 | |
| 251 | s_pidhash = (pid_data_t **)g_malloc0( |
| 252 | PIDHASH_NBUCKETS*sizeof(pid_data_t *)); |
| 253 | |
| 254 | /* $$$ add a SEGV handler... */ |
| 255 | for (i = 0; i < g_nevents; i++) { |
| 256 | if (once) { |
| 257 | once = FALSE; |
| 258 | start_time = ((ulonglong)ntohl(rep->time[0])); |
| 259 | start_time <<= 32; |
| 260 | low_time = ntohl(rep->time[1]); |
| 261 | low_time &= 0xFFFFFFFF; |
| 262 | start_time |= low_time; |
| 263 | ep->time = 0LL; |
| 264 | } else { |
| 265 | ep->time = ((ulonglong)ntohl(rep->time[0])); |
| 266 | ep->time <<= 32; |
| 267 | low_time = ntohl(rep->time[1]); |
| 268 | low_time &= 0xFFFFFFFF; |
| 269 | ep->time |= low_time; |
| 270 | ep->time -= start_time; |
| 271 | ep->time /= ticks_per_ns; |
| 272 | } |
| 273 | ep->code = ntohl(rep->code); |
| 274 | ep->pid = find_or_add_pid(ntohl(rep->pid)); |
| 275 | ep->datum = ntohl(rep->datum); |
| 276 | ep->flags = 0; |
| 277 | ep++; |
| 278 | rep++; |
| 279 | } |
| 280 | |
| 281 | unmapfile((char *)ulp, size); |
Dave Barach | 3e07a4a | 2020-04-04 10:05:48 -0400 | [diff] [blame] | 282 | |
Dave Barach | 52642c3 | 2016-02-11 19:28:19 -0500 | [diff] [blame] | 283 | make_sorted_pid_vector(); |
| 284 | g_free(s_pidhash); |
| 285 | s_pidhash = 0; |
| 286 | |
| 287 | /* Give the view-1 world a chance to reset a few things... */ |
| 288 | view1_read_events_callback(); |
| 289 | } |
| 290 | |
| 291 | static event_t *add_ep; |
| 292 | |
| 293 | /**************************************************************************** |
| 294 | * cpel_event_init |
| 295 | ****************************************************************************/ |
| 296 | void cpel_event_init (ulong nevents) |
| 297 | { |
| 298 | g_nevents = nevents; |
| 299 | if (g_events) |
| 300 | g_free(g_events); |
| 301 | add_ep = g_events = (event_t *)g_malloc(g_nevents * sizeof(event_t)); |
| 302 | while (g_npids > 0) { |
| 303 | g_free((g_pids + g_npids-1)->pid); |
| 304 | g_npids--; |
| 305 | } |
| 306 | if (g_pids) { |
| 307 | g_free(g_pids); |
| 308 | g_free(g_original_pids); |
| 309 | g_pids = 0; |
| 310 | g_original_pids = 0; |
| 311 | } |
| 312 | s_pidhash = (pid_data_t **)g_malloc0( |
| 313 | PIDHASH_NBUCKETS*sizeof(pid_data_t *)); |
| 314 | } |
| 315 | |
| 316 | /**************************************************************************** |
| 317 | * add_cpel_event |
| 318 | ****************************************************************************/ |
| 319 | |
| 320 | void add_cpel_event(ulonglong delta, ulong track, ulong event, ulong datum) |
| 321 | { |
| 322 | event_t *ep; |
| 323 | |
| 324 | ep = add_ep++; |
| 325 | ep->time = delta; |
| 326 | ep->pid = find_or_add_pid(track); |
| 327 | ep->code = event; |
| 328 | ep->datum = datum; |
| 329 | ep->flags = 0; |
| 330 | } |
| 331 | |
| 332 | /**************************************************************************** |
| 333 | * add_clib_event |
| 334 | ****************************************************************************/ |
| 335 | |
Dave Barach | 3e07a4a | 2020-04-04 10:05:48 -0400 | [diff] [blame] | 336 | void add_clib_event(double delta, unsigned short track, |
Dave Barach | 52642c3 | 2016-02-11 19:28:19 -0500 | [diff] [blame] | 337 | unsigned short event, unsigned int index) |
| 338 | { |
| 339 | event_t *ep; |
| 340 | |
| 341 | ep = add_ep++; |
Paul Vinciguerra | 8feeaff | 2019-03-27 11:25:48 -0700 | [diff] [blame] | 342 | ep->time = (ulonglong) (delta * 1e9); /* time in integer nanoseconds */ |
Dave Barach | 52642c3 | 2016-02-11 19:28:19 -0500 | [diff] [blame] | 343 | ep->pid = find_or_add_pid(track); |
| 344 | ep->code = event; |
| 345 | ep->datum = index; |
| 346 | ep->flags = EVENT_FLAG_CLIB; |
| 347 | } |
| 348 | |
| 349 | /**************************************************************************** |
| 350 | * cpel_event_finalize |
| 351 | ****************************************************************************/ |
| 352 | |
| 353 | void cpel_event_finalize(void) |
| 354 | { |
| 355 | make_sorted_pid_vector(); |
| 356 | g_free(s_pidhash); |
| 357 | s_pidhash = 0; |
Dave Barach | 3e07a4a | 2020-04-04 10:05:48 -0400 | [diff] [blame] | 358 | |
Dave Barach | 52642c3 | 2016-02-11 19:28:19 -0500 | [diff] [blame] | 359 | /* Give the view-1 world a chance to reset a few things... */ |
| 360 | view1_read_events_callback(); |
| 361 | } |
| 362 | |
| 363 | /**************************************************************************** |
| 364 | * mapfile |
| 365 | ****************************************************************************/ |
| 366 | |
| 367 | char *mapfile (char *file, ulong *sizep) |
| 368 | { |
| 369 | struct stat statb; |
| 370 | char *rv; |
| 371 | int maphfile; |
| 372 | size_t mapfsize; |
Dave Barach | 3e07a4a | 2020-04-04 10:05:48 -0400 | [diff] [blame] | 373 | |
Dave Barach | 52642c3 | 2016-02-11 19:28:19 -0500 | [diff] [blame] | 374 | maphfile = open (file, O_RDONLY); |
| 375 | |
| 376 | if (maphfile < 0) |
| 377 | return (NULL); |
| 378 | |
| 379 | if (fstat (maphfile, &statb) < 0) { |
| 380 | return (NULL); |
| 381 | } |
| 382 | |
| 383 | /* Don't try to mmap directories, FIFOs, semaphores, etc. */ |
| 384 | if (! (statb.st_mode & S_IFREG)) { |
| 385 | return (NULL); |
| 386 | } |
| 387 | |
| 388 | mapfsize = statb.st_size; |
| 389 | |
| 390 | if (mapfsize < 3) { |
| 391 | close (maphfile); |
| 392 | return (NULL); |
| 393 | } |
| 394 | |
| 395 | rv = mmap (0, mapfsize, PROT_READ, MAP_SHARED, maphfile, 0); |
| 396 | |
| 397 | if (rv == 0) { |
| 398 | g_error ("%s mapping problem, I quit...\n", file); |
| 399 | } |
| 400 | |
| 401 | close (maphfile); |
| 402 | |
| 403 | if (madvise (rv, mapfsize, MADV_SEQUENTIAL) < 0) { |
| 404 | return (rv); |
| 405 | } |
| 406 | |
| 407 | if (sizep) { |
| 408 | *sizep = mapfsize; |
| 409 | } |
| 410 | return (rv); |
| 411 | } |
| 412 | |
| 413 | /**************************************************************************** |
| 414 | * unmapfile |
| 415 | ****************************************************************************/ |
| 416 | |
| 417 | boolean unmapfile (char *addr, ulong size) |
| 418 | { |
| 419 | if (munmap (addr, size) < 0) { |
Dave Barach | 3e07a4a | 2020-04-04 10:05:48 -0400 | [diff] [blame] | 420 | g_warning("Unmap error, addr 0x%lx size 0x%x\n", |
Dave Barach | 52642c3 | 2016-02-11 19:28:19 -0500 | [diff] [blame] | 421 | (unsigned long) addr, (unsigned int)size); |
| 422 | return(FALSE); |
| 423 | } |
| 424 | return(TRUE); |
| 425 | } |
| 426 | |
| 427 | /**************************************************************************** |
| 428 | * find_event_index |
| 429 | * Binary search for first event whose time is >= t |
| 430 | ****************************************************************************/ |
| 431 | |
| 432 | int find_event_index (ulonglong t) |
| 433 | { |
| 434 | int index, bottom, top; |
| 435 | event_t *ep; |
| 436 | |
| 437 | bottom = g_nevents-1; |
| 438 | top = 0; |
| 439 | |
| 440 | while (1) { |
| 441 | index = (bottom + top) / 2; |
| 442 | |
| 443 | ep = (g_events + index); |
| 444 | |
| 445 | if (ep->time == t) |
| 446 | return(index); |
| 447 | |
| 448 | if (top >= bottom) { |
| 449 | while (index > 0 && ep->time > t) { |
| 450 | ep--; |
| 451 | index--; |
| 452 | } |
| 453 | while (index < g_nevents && ep->time < t) { |
| 454 | ep++; |
| 455 | index++; |
| 456 | } |
| 457 | return(index); |
| 458 | } |
| 459 | |
| 460 | if (ep->time < t) |
| 461 | top = index + 1; |
Dave Barach | 3e07a4a | 2020-04-04 10:05:48 -0400 | [diff] [blame] | 462 | else |
Dave Barach | 52642c3 | 2016-02-11 19:28:19 -0500 | [diff] [blame] | 463 | bottom = index - 1; |
| 464 | } |
| 465 | } |
| 466 | |
| 467 | /**************************************************************************** |
| 468 | * events_about |
| 469 | ****************************************************************************/ |
| 470 | |
| 471 | void events_about (char *tmpbuf) |
| 472 | { |
Dave Barach | 3e07a4a | 2020-04-04 10:05:48 -0400 | [diff] [blame] | 473 | snprintf(tmpbuf+strlen(tmpbuf), 1024 - strlen(tmpbuf), |
| 474 | "%d total events, %.3f ticks per us\n", |
| 475 | (int)g_nevents, ticks_per_ns); |
Dave Barach | 52642c3 | 2016-02-11 19:28:19 -0500 | [diff] [blame] | 476 | } |