Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.1-rc9 503 lines 10 kB view raw
1/* 2 * Copyright (C) 2008,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 _GNU_SOURCE 22#include <dirent.h> 23#include <mntent.h> 24#include <stdio.h> 25#include <stdlib.h> 26#include <string.h> 27#include <stdarg.h> 28#include <sys/types.h> 29#include <sys/stat.h> 30#include <sys/wait.h> 31#include <pthread.h> 32#include <fcntl.h> 33#include <unistd.h> 34#include <ctype.h> 35#include <errno.h> 36#include <stdbool.h> 37#include <linux/list.h> 38#include <linux/kernel.h> 39 40#include "../perf.h" 41#include "trace-event.h" 42#include "debugfs.h" 43#include "evsel.h" 44 45#define VERSION "0.5" 46 47#define _STR(x) #x 48#define STR(x) _STR(x) 49#define MAX_PATH 256 50 51#define TRACE_CTRL "tracing_on" 52#define TRACE "trace" 53#define AVAILABLE "available_tracers" 54#define CURRENT "current_tracer" 55#define ITER_CTRL "trace_options" 56#define MAX_LATENCY "tracing_max_latency" 57 58unsigned int page_size; 59 60static const char *output_file = "trace.info"; 61static int output_fd; 62 63struct event_list { 64 struct event_list *next; 65 const char *event; 66}; 67 68struct events { 69 struct events *sibling; 70 struct events *children; 71 struct events *next; 72 char *name; 73}; 74 75 76 77static void die(const char *fmt, ...) 78{ 79 va_list ap; 80 int ret = errno; 81 82 if (errno) 83 perror("trace-cmd"); 84 else 85 ret = -1; 86 87 va_start(ap, fmt); 88 fprintf(stderr, " "); 89 vfprintf(stderr, fmt, ap); 90 va_end(ap); 91 92 fprintf(stderr, "\n"); 93 exit(ret); 94} 95 96void *malloc_or_die(unsigned int size) 97{ 98 void *data; 99 100 data = malloc(size); 101 if (!data) 102 die("malloc"); 103 return data; 104} 105 106static const char *find_debugfs(void) 107{ 108 const char *path = debugfs_mount(NULL); 109 110 if (!path) 111 die("Your kernel not support debugfs filesystem"); 112 113 return path; 114} 115 116/* 117 * Finds the path to the debugfs/tracing 118 * Allocates the string and stores it. 119 */ 120static const char *find_tracing_dir(void) 121{ 122 static char *tracing; 123 static int tracing_found; 124 const char *debugfs; 125 126 if (tracing_found) 127 return tracing; 128 129 debugfs = find_debugfs(); 130 131 tracing = malloc_or_die(strlen(debugfs) + 9); 132 133 sprintf(tracing, "%s/tracing", debugfs); 134 135 tracing_found = 1; 136 return tracing; 137} 138 139static char *get_tracing_file(const char *name) 140{ 141 const char *tracing; 142 char *file; 143 144 tracing = find_tracing_dir(); 145 if (!tracing) 146 return NULL; 147 148 file = malloc_or_die(strlen(tracing) + strlen(name) + 2); 149 150 sprintf(file, "%s/%s", tracing, name); 151 return file; 152} 153 154static void put_tracing_file(char *file) 155{ 156 free(file); 157} 158 159static ssize_t calc_data_size; 160 161static ssize_t write_or_die(const void *buf, size_t len) 162{ 163 int ret; 164 165 if (calc_data_size) { 166 calc_data_size += len; 167 return len; 168 } 169 170 ret = write(output_fd, buf, len); 171 if (ret < 0) 172 die("writing to '%s'", output_file); 173 174 return ret; 175} 176 177int bigendian(void) 178{ 179 unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0}; 180 unsigned int *ptr; 181 182 ptr = (unsigned int *)(void *)str; 183 return *ptr == 0x01020304; 184} 185 186/* unfortunately, you can not stat debugfs or proc files for size */ 187static void record_file(const char *file, size_t hdr_sz) 188{ 189 unsigned long long size = 0; 190 char buf[BUFSIZ], *sizep; 191 off_t hdr_pos = lseek(output_fd, 0, SEEK_CUR); 192 int r, fd; 193 194 fd = open(file, O_RDONLY); 195 if (fd < 0) 196 die("Can't read '%s'", file); 197 198 /* put in zeros for file size, then fill true size later */ 199 write_or_die(&size, hdr_sz); 200 201 do { 202 r = read(fd, buf, BUFSIZ); 203 if (r > 0) { 204 size += r; 205 write_or_die(buf, r); 206 } 207 } while (r > 0); 208 close(fd); 209 210 /* ugh, handle big-endian hdr_size == 4 */ 211 sizep = (char*)&size; 212 if (bigendian()) 213 sizep += sizeof(u64) - hdr_sz; 214 215 if (pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0) 216 die("writing to %s", output_file); 217} 218 219static void read_header_files(void) 220{ 221 char *path; 222 struct stat st; 223 224 path = get_tracing_file("events/header_page"); 225 if (stat(path, &st) < 0) 226 die("can't read '%s'", path); 227 228 write_or_die("header_page", 12); 229 record_file(path, 8); 230 put_tracing_file(path); 231 232 path = get_tracing_file("events/header_event"); 233 if (stat(path, &st) < 0) 234 die("can't read '%s'", path); 235 236 write_or_die("header_event", 13); 237 record_file(path, 8); 238 put_tracing_file(path); 239} 240 241static bool name_in_tp_list(char *sys, struct tracepoint_path *tps) 242{ 243 while (tps) { 244 if (!strcmp(sys, tps->name)) 245 return true; 246 tps = tps->next; 247 } 248 249 return false; 250} 251 252static void copy_event_system(const char *sys, struct tracepoint_path *tps) 253{ 254 struct dirent *dent; 255 struct stat st; 256 char *format; 257 DIR *dir; 258 int count = 0; 259 int ret; 260 261 dir = opendir(sys); 262 if (!dir) 263 die("can't read directory '%s'", sys); 264 265 while ((dent = readdir(dir))) { 266 if (dent->d_type != DT_DIR || 267 strcmp(dent->d_name, ".") == 0 || 268 strcmp(dent->d_name, "..") == 0 || 269 !name_in_tp_list(dent->d_name, tps)) 270 continue; 271 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10); 272 sprintf(format, "%s/%s/format", sys, dent->d_name); 273 ret = stat(format, &st); 274 free(format); 275 if (ret < 0) 276 continue; 277 count++; 278 } 279 280 write_or_die(&count, 4); 281 282 rewinddir(dir); 283 while ((dent = readdir(dir))) { 284 if (dent->d_type != DT_DIR || 285 strcmp(dent->d_name, ".") == 0 || 286 strcmp(dent->d_name, "..") == 0 || 287 !name_in_tp_list(dent->d_name, tps)) 288 continue; 289 format = malloc_or_die(strlen(sys) + strlen(dent->d_name) + 10); 290 sprintf(format, "%s/%s/format", sys, dent->d_name); 291 ret = stat(format, &st); 292 293 if (ret >= 0) 294 record_file(format, 8); 295 296 free(format); 297 } 298 closedir(dir); 299} 300 301static void read_ftrace_files(struct tracepoint_path *tps) 302{ 303 char *path; 304 305 path = get_tracing_file("events/ftrace"); 306 307 copy_event_system(path, tps); 308 309 put_tracing_file(path); 310} 311 312static bool system_in_tp_list(char *sys, struct tracepoint_path *tps) 313{ 314 while (tps) { 315 if (!strcmp(sys, tps->system)) 316 return true; 317 tps = tps->next; 318 } 319 320 return false; 321} 322 323static void read_event_files(struct tracepoint_path *tps) 324{ 325 struct dirent *dent; 326 struct stat st; 327 char *path; 328 char *sys; 329 DIR *dir; 330 int count = 0; 331 int ret; 332 333 path = get_tracing_file("events"); 334 335 dir = opendir(path); 336 if (!dir) 337 die("can't read directory '%s'", path); 338 339 while ((dent = readdir(dir))) { 340 if (dent->d_type != DT_DIR || 341 strcmp(dent->d_name, ".") == 0 || 342 strcmp(dent->d_name, "..") == 0 || 343 strcmp(dent->d_name, "ftrace") == 0 || 344 !system_in_tp_list(dent->d_name, tps)) 345 continue; 346 count++; 347 } 348 349 write_or_die(&count, 4); 350 351 rewinddir(dir); 352 while ((dent = readdir(dir))) { 353 if (dent->d_type != DT_DIR || 354 strcmp(dent->d_name, ".") == 0 || 355 strcmp(dent->d_name, "..") == 0 || 356 strcmp(dent->d_name, "ftrace") == 0 || 357 !system_in_tp_list(dent->d_name, tps)) 358 continue; 359 sys = malloc_or_die(strlen(path) + strlen(dent->d_name) + 2); 360 sprintf(sys, "%s/%s", path, dent->d_name); 361 ret = stat(sys, &st); 362 if (ret >= 0) { 363 write_or_die(dent->d_name, strlen(dent->d_name) + 1); 364 copy_event_system(sys, tps); 365 } 366 free(sys); 367 } 368 369 closedir(dir); 370 put_tracing_file(path); 371} 372 373static void read_proc_kallsyms(void) 374{ 375 unsigned int size; 376 const char *path = "/proc/kallsyms"; 377 struct stat st; 378 int ret; 379 380 ret = stat(path, &st); 381 if (ret < 0) { 382 /* not found */ 383 size = 0; 384 write_or_die(&size, 4); 385 return; 386 } 387 record_file(path, 4); 388} 389 390static void read_ftrace_printk(void) 391{ 392 unsigned int size; 393 char *path; 394 struct stat st; 395 int ret; 396 397 path = get_tracing_file("printk_formats"); 398 ret = stat(path, &st); 399 if (ret < 0) { 400 /* not found */ 401 size = 0; 402 write_or_die(&size, 4); 403 goto out; 404 } 405 record_file(path, 4); 406 407out: 408 put_tracing_file(path); 409} 410 411static struct tracepoint_path * 412get_tracepoints_path(struct list_head *pattrs) 413{ 414 struct tracepoint_path path, *ppath = &path; 415 struct perf_evsel *pos; 416 int nr_tracepoints = 0; 417 418 list_for_each_entry(pos, pattrs, node) { 419 if (pos->attr.type != PERF_TYPE_TRACEPOINT) 420 continue; 421 ++nr_tracepoints; 422 ppath->next = tracepoint_id_to_path(pos->attr.config); 423 if (!ppath->next) 424 die("%s\n", "No memory to alloc tracepoints list"); 425 ppath = ppath->next; 426 } 427 428 return nr_tracepoints > 0 ? path.next : NULL; 429} 430 431bool have_tracepoints(struct list_head *pattrs) 432{ 433 struct perf_evsel *pos; 434 435 list_for_each_entry(pos, pattrs, node) 436 if (pos->attr.type == PERF_TYPE_TRACEPOINT) 437 return true; 438 439 return false; 440} 441 442int read_tracing_data(int fd, struct list_head *pattrs) 443{ 444 char buf[BUFSIZ]; 445 struct tracepoint_path *tps = get_tracepoints_path(pattrs); 446 447 /* 448 * What? No tracepoints? No sense writing anything here, bail out. 449 */ 450 if (tps == NULL) 451 return -1; 452 453 output_fd = fd; 454 455 buf[0] = 23; 456 buf[1] = 8; 457 buf[2] = 68; 458 memcpy(buf + 3, "tracing", 7); 459 460 write_or_die(buf, 10); 461 462 write_or_die(VERSION, strlen(VERSION) + 1); 463 464 /* save endian */ 465 if (bigendian()) 466 buf[0] = 1; 467 else 468 buf[0] = 0; 469 470 write_or_die(buf, 1); 471 472 /* save size of long */ 473 buf[0] = sizeof(long); 474 write_or_die(buf, 1); 475 476 /* save page_size */ 477 page_size = sysconf(_SC_PAGESIZE); 478 write_or_die(&page_size, 4); 479 480 read_header_files(); 481 read_ftrace_files(tps); 482 read_event_files(tps); 483 read_proc_kallsyms(); 484 read_ftrace_printk(); 485 486 return 0; 487} 488 489ssize_t read_tracing_data_size(int fd, struct list_head *pattrs) 490{ 491 ssize_t size; 492 int err = 0; 493 494 calc_data_size = 1; 495 err = read_tracing_data(fd, pattrs); 496 size = calc_data_size - 1; 497 calc_data_size = 0; 498 499 if (err < 0) 500 return err; 501 502 return size; 503}