1 /* 2 * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com> 3 * 4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; version 2 of the License (not later!) 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * 19 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 20 */ 21 #define _LARGEFILE64_SOURCE 22 23 #include <dirent.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <getopt.h> 28 #include <stdarg.h> 29 #include <sys/types.h> 30 #include <sys/stat.h> 31 #include <sys/wait.h> 32 #include <sys/mman.h> 33 #include <pthread.h> 34 #include <fcntl.h> 35 #include <unistd.h> 36 #include <ctype.h> 37 #include <errno.h> 38 39 #include "../perf.h" 40 #include "util.h" 41 #include "trace-event.h" 42 43 static int input_fd; 44 45 static int read_page; 46 47 int file_bigendian; 48 int host_bigendian; 49 static int long_size; 50 51 static unsigned long page_size; 52 53 static int read_or_die(void *data, int size) 54 { 55 int r; 56 57 r = read(input_fd, data, size); 58 if (r != size) 59 die("reading input file (size expected=%d received=%d)", 60 size, r); 61 return r; 62 } 63 64 static unsigned int read4(void) 65 { 66 unsigned int data; 67 68 read_or_die(&data, 4); 69 return __data2host4(data); 70 } 71 72 static unsigned long long read8(void) 73 { 74 unsigned long long data; 75 76 read_or_die(&data, 8); 77 return __data2host8(data); 78 } 79 80 static char *read_string(void) 81 { 82 char buf[BUFSIZ]; 83 char *str = NULL; 84 int size = 0; 85 int i; 86 int r; 87 88 for (;;) { 89 r = read(input_fd, buf, BUFSIZ); 90 if (r < 0) 91 die("reading input file"); 92 93 if (!r) 94 die("no data"); 95 96 for (i = 0; i < r; i++) { 97 if (!buf[i]) 98 break; 99 } 100 if (i < r) 101 break; 102 103 if (str) { 104 size += BUFSIZ; 105 str = realloc(str, size); 106 if (!str) 107 die("malloc of size %d", size); 108 memcpy(str + (size - BUFSIZ), buf, BUFSIZ); 109 } else { 110 size = BUFSIZ; 111 str = malloc_or_die(size); 112 memcpy(str, buf, size); 113 } 114 } 115 116 /* trailing \0: */ 117 i++; 118 119 /* move the file descriptor to the end of the string */ 120 r = lseek(input_fd, -(r - i), SEEK_CUR); 121 if (r < 0) 122 die("lseek"); 123 124 if (str) { 125 size += i; 126 str = realloc(str, size); 127 if (!str) 128 die("malloc of size %d", size); 129 memcpy(str + (size - i), buf, i); 130 } else { 131 size = i; 132 str = malloc_or_die(i); 133 memcpy(str, buf, i); 134 } 135 136 return str; 137 } 138 139 static void read_proc_kallsyms(void) 140 { 141 unsigned int size; 142 char *buf; 143 144 size = read4(); 145 if (!size) 146 return; 147 148 buf = malloc_or_die(size); 149 read_or_die(buf, size); 150 151 parse_proc_kallsyms(buf, size); 152 153 free(buf); 154 } 155 156 static void read_ftrace_printk(void) 157 { 158 unsigned int size; 159 char *buf; 160 161 size = read4(); 162 if (!size) 163 return; 164 165 buf = malloc_or_die(size); 166 read_or_die(buf, size); 167 168 parse_ftrace_printk(buf, size); 169 170 free(buf); 171 } 172 173 static void read_header_files(void) 174 { 175 unsigned long long size; 176 char *header_page; 177 char *header_event; 178 char buf[BUFSIZ]; 179 180 read_or_die(buf, 12); 181 182 if (memcmp(buf, "header_page", 12) != 0) 183 die("did not read header page"); 184 185 size = read8(); 186 header_page = malloc_or_die(size); 187 read_or_die(header_page, size); 188 parse_header_page(header_page, size); 189 free(header_page); 190 191 /* 192 * The size field in the page is of type long, 193 * use that instead, since it represents the kernel. 194 */ 195 long_size = header_page_size_size; 196 197 read_or_die(buf, 13); 198 if (memcmp(buf, "header_event", 13) != 0) 199 die("did not read header event"); 200 201 size = read8(); 202 header_event = malloc_or_die(size); 203 read_or_die(header_event, size); 204 free(header_event); 205 } 206 207 static void read_ftrace_file(unsigned long long size) 208 { 209 char *buf; 210 211 buf = malloc_or_die(size); 212 read_or_die(buf, size); 213 parse_ftrace_file(buf, size); 214 free(buf); 215 } 216 217 static void read_event_file(char *sys, unsigned long long size) 218 { 219 char *buf; 220 221 buf = malloc_or_die(size); 222 read_or_die(buf, size); 223 parse_event_file(buf, size, sys); 224 free(buf); 225 } 226 227 static void read_ftrace_files(void) 228 { 229 unsigned long long size; 230 int count; 231 int i; 232 233 count = read4(); 234 235 for (i = 0; i < count; i++) { 236 size = read8(); 237 read_ftrace_file(size); 238 } 239 } 240 241 static void read_event_files(void) 242 { 243 unsigned long long size; 244 char *sys; 245 int systems; 246 int count; 247 int i,x; 248 249 systems = read4(); 250 251 for (i = 0; i < systems; i++) { 252 sys = read_string(); 253 254 count = read4(); 255 for (x=0; x < count; x++) { 256 size = read8(); 257 read_event_file(sys, size); 258 } 259 } 260 } 261 262 struct cpu_data { 263 unsigned long long offset; 264 unsigned long long size; 265 unsigned long long timestamp; 266 struct record *next; 267 char *page; 268 int cpu; 269 int index; 270 int page_size; 271 }; 272 273 static struct cpu_data *cpu_data; 274 275 static void update_cpu_data_index(int cpu) 276 { 277 cpu_data[cpu].offset += page_size; 278 cpu_data[cpu].size -= page_size; 279 cpu_data[cpu].index = 0; 280 } 281 282 static void get_next_page(int cpu) 283 { 284 off64_t save_seek; 285 off64_t ret; 286 287 if (!cpu_data[cpu].page) 288 return; 289 290 if (read_page) { 291 if (cpu_data[cpu].size <= page_size) { 292 free(cpu_data[cpu].page); 293 cpu_data[cpu].page = NULL; 294 return; 295 } 296 297 update_cpu_data_index(cpu); 298 299 /* other parts of the code may expect the pointer to not move */ 300 save_seek = lseek64(input_fd, 0, SEEK_CUR); 301 302 ret = lseek64(input_fd, cpu_data[cpu].offset, SEEK_SET); 303 if (ret < 0) 304 die("failed to lseek"); 305 ret = read(input_fd, cpu_data[cpu].page, page_size); 306 if (ret < 0) 307 die("failed to read page"); 308 309 /* reset the file pointer back */ 310 lseek64(input_fd, save_seek, SEEK_SET); 311 312 return; 313 } 314 315 munmap(cpu_data[cpu].page, page_size); 316 cpu_data[cpu].page = NULL; 317 318 if (cpu_data[cpu].size <= page_size) 319 return; 320 321 update_cpu_data_index(cpu); 322 323 cpu_data[cpu].page = mmap(NULL, page_size, PROT_READ, MAP_PRIVATE, 324 input_fd, cpu_data[cpu].offset); 325 if (cpu_data[cpu].page == MAP_FAILED) 326 die("failed to mmap cpu %d at offset 0x%llx", 327 cpu, cpu_data[cpu].offset); 328 } 329 330 static unsigned int type_len4host(unsigned int type_len_ts) 331 { 332 if (file_bigendian) 333 return (type_len_ts >> 27) & ((1 << 5) - 1); 334 else 335 return type_len_ts & ((1 << 5) - 1); 336 } 337 338 static unsigned int ts4host(unsigned int type_len_ts) 339 { 340 if (file_bigendian) 341 return type_len_ts & ((1 << 27) - 1); 342 else 343 return type_len_ts >> 5; 344 } 345 346 static int calc_index(void *ptr, int cpu) 347 { 348 return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page; 349 } 350 351 struct record *trace_peek_data(int cpu) 352 { 353 struct record *data; 354 void *page = cpu_data[cpu].page; 355 int idx = cpu_data[cpu].index; 356 void *ptr = page + idx; 357 unsigned long long extend; 358 unsigned int type_len_ts; 359 unsigned int type_len; 360 unsigned int delta; 361 unsigned int length = 0; 362 363 if (cpu_data[cpu].next) 364 return cpu_data[cpu].next; 365 366 if (!page) 367 return NULL; 368 369 if (!idx) { 370 /* FIXME: handle header page */ 371 if (header_page_ts_size != 8) 372 die("expected a long long type for timestamp"); 373 cpu_data[cpu].timestamp = data2host8(ptr); 374 ptr += 8; 375 switch (header_page_size_size) { 376 case 4: 377 cpu_data[cpu].page_size = data2host4(ptr); 378 ptr += 4; 379 break; 380 case 8: 381 cpu_data[cpu].page_size = data2host8(ptr); 382 ptr += 8; 383 break; 384 default: 385 die("bad long size"); 386 } 387 ptr = cpu_data[cpu].page + header_page_data_offset; 388 } 389 390 read_again: 391 idx = calc_index(ptr, cpu); 392 393 if (idx >= cpu_data[cpu].page_size) { 394 get_next_page(cpu); 395 return trace_peek_data(cpu); 396 } 397 398 type_len_ts = data2host4(ptr); 399 ptr += 4; 400 401 type_len = type_len4host(type_len_ts); 402 delta = ts4host(type_len_ts); 403 404 switch (type_len) { 405 case RINGBUF_TYPE_PADDING: 406 if (!delta) 407 die("error, hit unexpected end of page"); 408 length = data2host4(ptr); 409 ptr += 4; 410 length *= 4; 411 ptr += length; 412 goto read_again; 413 414 case RINGBUF_TYPE_TIME_EXTEND: 415 extend = data2host4(ptr); 416 ptr += 4; 417 extend <<= TS_SHIFT; 418 extend += delta; 419 cpu_data[cpu].timestamp += extend; 420 goto read_again; 421 422 case RINGBUF_TYPE_TIME_STAMP: 423 ptr += 12; 424 break; 425 case 0: 426 length = data2host4(ptr); 427 ptr += 4; 428 die("here! length=%d", length); 429 break; 430 default: 431 length = type_len * 4; 432 break; 433 } 434 435 cpu_data[cpu].timestamp += delta; 436 437 data = malloc_or_die(sizeof(*data)); 438 memset(data, 0, sizeof(*data)); 439 440 data->ts = cpu_data[cpu].timestamp; 441 data->size = length; 442 data->data = ptr; 443 ptr += length; 444 445 cpu_data[cpu].index = calc_index(ptr, cpu); 446 cpu_data[cpu].next = data; 447 448 return data; 449 } 450 451 struct record *trace_read_data(int cpu) 452 { 453 struct record *data; 454 455 data = trace_peek_data(cpu); 456 cpu_data[cpu].next = NULL; 457 458 return data; 459 } 460 461 void trace_report(void) 462 { 463 const char *input_file = "trace.info"; 464 char buf[BUFSIZ]; 465 char test[] = { 23, 8, 68 }; 466 char *version; 467 int show_version = 0; 468 int show_funcs = 0; 469 int show_printk = 0; 470 471 input_fd = open(input_file, O_RDONLY); 472 if (input_fd < 0) 473 die("opening '%s'\n", input_file); 474 475 read_or_die(buf, 3); 476 if (memcmp(buf, test, 3) != 0) 477 die("not an trace data file"); 478 479 read_or_die(buf, 7); 480 if (memcmp(buf, "tracing", 7) != 0) 481 die("not a trace file (missing tracing)"); 482 483 version = read_string(); 484 if (show_version) 485 printf("version = %s\n", version); 486 free(version); 487 488 read_or_die(buf, 1); 489 file_bigendian = buf[0]; 490 host_bigendian = bigendian(); 491 492 read_or_die(buf, 1); 493 long_size = buf[0]; 494 495 page_size = read4(); 496 497 read_header_files(); 498 499 read_ftrace_files(); 500 read_event_files(); 501 read_proc_kallsyms(); 502 read_ftrace_printk(); 503 504 if (show_funcs) { 505 print_funcs(); 506 return; 507 } 508 if (show_printk) { 509 print_printk(); 510 return; 511 } 512 513 return; 514 } 515