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 /* move the file descriptor to the end of the string */ 117 r = lseek(input_fd, -(r - (i+1)), SEEK_CUR); 118 if (r < 0) 119 die("lseek"); 120 121 if (str) { 122 size += i; 123 str = realloc(str, size); 124 if (!str) 125 die("malloc of size %d", size); 126 memcpy(str + (size - i), buf, i); 127 } else { 128 size = i; 129 str = malloc_or_die(i); 130 memcpy(str, buf, i); 131 } 132 133 return str; 134 } 135 136 static void read_proc_kallsyms(void) 137 { 138 unsigned int size; 139 char *buf; 140 141 size = read4(); 142 if (!size) 143 return; 144 145 buf = malloc_or_die(size); 146 read_or_die(buf, size); 147 148 parse_proc_kallsyms(buf, size); 149 150 free(buf); 151 } 152 153 static void read_ftrace_printk(void) 154 { 155 unsigned int size; 156 char *buf; 157 158 size = read4(); 159 if (!size) 160 return; 161 162 buf = malloc_or_die(size); 163 read_or_die(buf, size); 164 165 parse_ftrace_printk(buf, size); 166 167 free(buf); 168 } 169 170 static void read_header_files(void) 171 { 172 unsigned long long size; 173 char *header_page; 174 char *header_event; 175 char buf[BUFSIZ]; 176 177 read_or_die(buf, 12); 178 179 if (memcmp(buf, "header_page", 12) != 0) 180 die("did not read header page"); 181 182 size = read8(); 183 header_page = malloc_or_die(size); 184 read_or_die(header_page, size); 185 parse_header_page(header_page, size); 186 free(header_page); 187 188 /* 189 * The size field in the page is of type long, 190 * use that instead, since it represents the kernel. 191 */ 192 long_size = header_page_size_size; 193 194 read_or_die(buf, 13); 195 if (memcmp(buf, "header_event", 13) != 0) 196 die("did not read header event"); 197 198 size = read8(); 199 header_event = malloc_or_die(size); 200 read_or_die(header_event, size); 201 free(header_event); 202 } 203 204 static void read_ftrace_file(unsigned long long size) 205 { 206 char *buf; 207 208 buf = malloc_or_die(size); 209 read_or_die(buf, size); 210 parse_ftrace_file(buf, size); 211 free(buf); 212 } 213 214 static void read_event_file(char *sys, unsigned long long size) 215 { 216 char *buf; 217 218 buf = malloc_or_die(size); 219 read_or_die(buf, size); 220 parse_event_file(buf, size, sys); 221 free(buf); 222 } 223 224 static void read_ftrace_files(void) 225 { 226 unsigned long long size; 227 int count; 228 int i; 229 230 count = read4(); 231 232 for (i = 0; i < count; i++) { 233 size = read8(); 234 read_ftrace_file(size); 235 } 236 } 237 238 static void read_event_files(void) 239 { 240 unsigned long long size; 241 char *sys; 242 int systems; 243 int count; 244 int i,x; 245 246 systems = read4(); 247 248 for (i = 0; i < systems; i++) { 249 sys = read_string(); 250 251 count = read4(); 252 for (x=0; x < count; x++) { 253 size = read8(); 254 read_event_file(sys, size); 255 } 256 } 257 } 258 259 struct cpu_data { 260 unsigned long long offset; 261 unsigned long long size; 262 unsigned long long timestamp; 263 struct record *next; 264 char *page; 265 int cpu; 266 int index; 267 int page_size; 268 }; 269 270 static struct cpu_data *cpu_data; 271 272 static void update_cpu_data_index(int cpu) 273 { 274 cpu_data[cpu].offset += page_size; 275 cpu_data[cpu].size -= page_size; 276 cpu_data[cpu].index = 0; 277 } 278 279 static void get_next_page(int cpu) 280 { 281 off64_t save_seek; 282 off64_t ret; 283 284 if (!cpu_data[cpu].page) 285 return; 286 287 if (read_page) { 288 if (cpu_data[cpu].size <= page_size) { 289 free(cpu_data[cpu].page); 290 cpu_data[cpu].page = NULL; 291 return; 292 } 293 294 update_cpu_data_index(cpu); 295 296 /* other parts of the code may expect the pointer to not move */ 297 save_seek = lseek64(input_fd, 0, SEEK_CUR); 298 299 ret = lseek64(input_fd, cpu_data[cpu].offset, SEEK_SET); 300 if (ret < 0) 301 die("failed to lseek"); 302 ret = read(input_fd, cpu_data[cpu].page, page_size); 303 if (ret < 0) 304 die("failed to read page"); 305 306 /* reset the file pointer back */ 307 lseek64(input_fd, save_seek, SEEK_SET); 308 309 return; 310 } 311 312 munmap(cpu_data[cpu].page, page_size); 313 cpu_data[cpu].page = NULL; 314 315 if (cpu_data[cpu].size <= page_size) 316 return; 317 318 update_cpu_data_index(cpu); 319 320 cpu_data[cpu].page = mmap(NULL, page_size, PROT_READ, MAP_PRIVATE, 321 input_fd, cpu_data[cpu].offset); 322 if (cpu_data[cpu].page == MAP_FAILED) 323 die("failed to mmap cpu %d at offset 0x%llx", 324 cpu, cpu_data[cpu].offset); 325 } 326 327 static unsigned int type_len4host(unsigned int type_len_ts) 328 { 329 if (file_bigendian) 330 return (type_len_ts >> 27) & ((1 << 5) - 1); 331 else 332 return type_len_ts & ((1 << 5) - 1); 333 } 334 335 static unsigned int ts4host(unsigned int type_len_ts) 336 { 337 if (file_bigendian) 338 return type_len_ts & ((1 << 27) - 1); 339 else 340 return type_len_ts >> 5; 341 } 342 343 static int calc_index(void *ptr, int cpu) 344 { 345 return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page; 346 } 347 348 struct record *trace_peek_data(int cpu) 349 { 350 struct record *data; 351 void *page = cpu_data[cpu].page; 352 int idx = cpu_data[cpu].index; 353 void *ptr = page + idx; 354 unsigned long long extend; 355 unsigned int type_len_ts; 356 unsigned int type_len; 357 unsigned int delta; 358 unsigned int length = 0; 359 360 if (cpu_data[cpu].next) 361 return cpu_data[cpu].next; 362 363 if (!page) 364 return NULL; 365 366 if (!idx) { 367 /* FIXME: handle header page */ 368 if (header_page_ts_size != 8) 369 die("expected a long long type for timestamp"); 370 cpu_data[cpu].timestamp = data2host8(ptr); 371 ptr += 8; 372 switch (header_page_size_size) { 373 case 4: 374 cpu_data[cpu].page_size = data2host4(ptr); 375 ptr += 4; 376 break; 377 case 8: 378 cpu_data[cpu].page_size = data2host8(ptr); 379 ptr += 8; 380 break; 381 default: 382 die("bad long size"); 383 } 384 ptr = cpu_data[cpu].page + header_page_data_offset; 385 } 386 387 read_again: 388 idx = calc_index(ptr, cpu); 389 390 if (idx >= cpu_data[cpu].page_size) { 391 get_next_page(cpu); 392 return trace_peek_data(cpu); 393 } 394 395 type_len_ts = data2host4(ptr); 396 ptr += 4; 397 398 type_len = type_len4host(type_len_ts); 399 delta = ts4host(type_len_ts); 400 401 switch (type_len) { 402 case RINGBUF_TYPE_PADDING: 403 if (!delta) 404 die("error, hit unexpected end of page"); 405 length = data2host4(ptr); 406 ptr += 4; 407 length *= 4; 408 ptr += length; 409 goto read_again; 410 411 case RINGBUF_TYPE_TIME_EXTEND: 412 extend = data2host4(ptr); 413 ptr += 4; 414 extend <<= TS_SHIFT; 415 extend += delta; 416 cpu_data[cpu].timestamp += extend; 417 goto read_again; 418 419 case RINGBUF_TYPE_TIME_STAMP: 420 ptr += 12; 421 break; 422 case 0: 423 length = data2host4(ptr); 424 ptr += 4; 425 die("here! length=%d", length); 426 break; 427 default: 428 length = type_len * 4; 429 break; 430 } 431 432 cpu_data[cpu].timestamp += delta; 433 434 data = malloc_or_die(sizeof(*data)); 435 memset(data, 0, sizeof(*data)); 436 437 data->ts = cpu_data[cpu].timestamp; 438 data->size = length; 439 data->data = ptr; 440 ptr += length; 441 442 cpu_data[cpu].index = calc_index(ptr, cpu); 443 cpu_data[cpu].next = data; 444 445 return data; 446 } 447 448 struct record *trace_read_data(int cpu) 449 { 450 struct record *data; 451 452 data = trace_peek_data(cpu); 453 cpu_data[cpu].next = NULL; 454 455 return data; 456 } 457 458 void trace_report (void) 459 { 460 const char *input_file = "trace.info"; 461 char buf[BUFSIZ]; 462 char test[] = { 23, 8, 68 }; 463 char *version; 464 int show_funcs = 0; 465 int show_printk = 0; 466 467 input_fd = open(input_file, O_RDONLY); 468 if (input_fd < 0) 469 die("opening '%s'\n", input_file); 470 471 read_or_die(buf, 3); 472 if (memcmp(buf, test, 3) != 0) 473 die("not an trace data file"); 474 475 read_or_die(buf, 7); 476 if (memcmp(buf, "tracing", 7) != 0) 477 die("not a trace file (missing tracing)"); 478 479 version = read_string(); 480 printf("version = %s\n", version); 481 free(version); 482 483 read_or_die(buf, 1); 484 file_bigendian = buf[0]; 485 host_bigendian = bigendian(); 486 487 read_or_die(buf, 1); 488 long_size = buf[0]; 489 490 page_size = read4(); 491 492 read_header_files(); 493 494 read_ftrace_files(); 495 read_event_files(); 496 read_proc_kallsyms(); 497 read_ftrace_printk(); 498 499 if (show_funcs) { 500 print_funcs(); 501 return; 502 } 503 if (show_printk) { 504 print_printk(); 505 return; 506 } 507 508 return; 509 } 510