1*86470930SIngo Molnar /* 2*86470930SIngo Molnar * builtin-record.c 3*86470930SIngo Molnar * 4*86470930SIngo Molnar * Builtin record command: Record the profile of a workload 5*86470930SIngo Molnar * (or a CPU, or a PID) into the perf.data output file - for 6*86470930SIngo Molnar * later analysis via perf report. 7*86470930SIngo Molnar */ 8*86470930SIngo Molnar #include "builtin.h" 9*86470930SIngo Molnar 10*86470930SIngo Molnar #include "perf.h" 11*86470930SIngo Molnar 12*86470930SIngo Molnar #include "util/util.h" 13*86470930SIngo Molnar #include "util/parse-options.h" 14*86470930SIngo Molnar #include "util/parse-events.h" 15*86470930SIngo Molnar #include "util/string.h" 16*86470930SIngo Molnar 17*86470930SIngo Molnar #include <unistd.h> 18*86470930SIngo Molnar #include <sched.h> 19*86470930SIngo Molnar 20*86470930SIngo Molnar #define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1) 21*86470930SIngo Molnar #define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask)) 22*86470930SIngo Molnar 23*86470930SIngo Molnar static int fd[MAX_NR_CPUS][MAX_COUNTERS]; 24*86470930SIngo Molnar 25*86470930SIngo Molnar static long default_interval = 100000; 26*86470930SIngo Molnar 27*86470930SIngo Molnar static int nr_cpus = 0; 28*86470930SIngo Molnar static unsigned int page_size; 29*86470930SIngo Molnar static unsigned int mmap_pages = 128; 30*86470930SIngo Molnar static int freq = 0; 31*86470930SIngo Molnar static int output; 32*86470930SIngo Molnar static const char *output_name = "perf.data"; 33*86470930SIngo Molnar static int group = 0; 34*86470930SIngo Molnar static unsigned int realtime_prio = 0; 35*86470930SIngo Molnar static int system_wide = 0; 36*86470930SIngo Molnar static pid_t target_pid = -1; 37*86470930SIngo Molnar static int inherit = 1; 38*86470930SIngo Molnar static int force = 0; 39*86470930SIngo Molnar static int append_file = 0; 40*86470930SIngo Molnar 41*86470930SIngo Molnar static long samples; 42*86470930SIngo Molnar static struct timeval last_read; 43*86470930SIngo Molnar static struct timeval this_read; 44*86470930SIngo Molnar 45*86470930SIngo Molnar static __u64 bytes_written; 46*86470930SIngo Molnar 47*86470930SIngo Molnar static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; 48*86470930SIngo Molnar 49*86470930SIngo Molnar static int nr_poll; 50*86470930SIngo Molnar static int nr_cpu; 51*86470930SIngo Molnar 52*86470930SIngo Molnar struct mmap_event { 53*86470930SIngo Molnar struct perf_event_header header; 54*86470930SIngo Molnar __u32 pid; 55*86470930SIngo Molnar __u32 tid; 56*86470930SIngo Molnar __u64 start; 57*86470930SIngo Molnar __u64 len; 58*86470930SIngo Molnar __u64 pgoff; 59*86470930SIngo Molnar char filename[PATH_MAX]; 60*86470930SIngo Molnar }; 61*86470930SIngo Molnar 62*86470930SIngo Molnar struct comm_event { 63*86470930SIngo Molnar struct perf_event_header header; 64*86470930SIngo Molnar __u32 pid; 65*86470930SIngo Molnar __u32 tid; 66*86470930SIngo Molnar char comm[16]; 67*86470930SIngo Molnar }; 68*86470930SIngo Molnar 69*86470930SIngo Molnar 70*86470930SIngo Molnar struct mmap_data { 71*86470930SIngo Molnar int counter; 72*86470930SIngo Molnar void *base; 73*86470930SIngo Molnar unsigned int mask; 74*86470930SIngo Molnar unsigned int prev; 75*86470930SIngo Molnar }; 76*86470930SIngo Molnar 77*86470930SIngo Molnar static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; 78*86470930SIngo Molnar 79*86470930SIngo Molnar static unsigned int mmap_read_head(struct mmap_data *md) 80*86470930SIngo Molnar { 81*86470930SIngo Molnar struct perf_counter_mmap_page *pc = md->base; 82*86470930SIngo Molnar int head; 83*86470930SIngo Molnar 84*86470930SIngo Molnar head = pc->data_head; 85*86470930SIngo Molnar rmb(); 86*86470930SIngo Molnar 87*86470930SIngo Molnar return head; 88*86470930SIngo Molnar } 89*86470930SIngo Molnar 90*86470930SIngo Molnar static void mmap_read(struct mmap_data *md) 91*86470930SIngo Molnar { 92*86470930SIngo Molnar unsigned int head = mmap_read_head(md); 93*86470930SIngo Molnar unsigned int old = md->prev; 94*86470930SIngo Molnar unsigned char *data = md->base + page_size; 95*86470930SIngo Molnar unsigned long size; 96*86470930SIngo Molnar void *buf; 97*86470930SIngo Molnar int diff; 98*86470930SIngo Molnar 99*86470930SIngo Molnar gettimeofday(&this_read, NULL); 100*86470930SIngo Molnar 101*86470930SIngo Molnar /* 102*86470930SIngo Molnar * If we're further behind than half the buffer, there's a chance 103*86470930SIngo Molnar * the writer will bite our tail and mess up the samples under us. 104*86470930SIngo Molnar * 105*86470930SIngo Molnar * If we somehow ended up ahead of the head, we got messed up. 106*86470930SIngo Molnar * 107*86470930SIngo Molnar * In either case, truncate and restart at head. 108*86470930SIngo Molnar */ 109*86470930SIngo Molnar diff = head - old; 110*86470930SIngo Molnar if (diff > md->mask / 2 || diff < 0) { 111*86470930SIngo Molnar struct timeval iv; 112*86470930SIngo Molnar unsigned long msecs; 113*86470930SIngo Molnar 114*86470930SIngo Molnar timersub(&this_read, &last_read, &iv); 115*86470930SIngo Molnar msecs = iv.tv_sec*1000 + iv.tv_usec/1000; 116*86470930SIngo Molnar 117*86470930SIngo Molnar fprintf(stderr, "WARNING: failed to keep up with mmap data." 118*86470930SIngo Molnar " Last read %lu msecs ago.\n", msecs); 119*86470930SIngo Molnar 120*86470930SIngo Molnar /* 121*86470930SIngo Molnar * head points to a known good entry, start there. 122*86470930SIngo Molnar */ 123*86470930SIngo Molnar old = head; 124*86470930SIngo Molnar } 125*86470930SIngo Molnar 126*86470930SIngo Molnar last_read = this_read; 127*86470930SIngo Molnar 128*86470930SIngo Molnar if (old != head) 129*86470930SIngo Molnar samples++; 130*86470930SIngo Molnar 131*86470930SIngo Molnar size = head - old; 132*86470930SIngo Molnar 133*86470930SIngo Molnar if ((old & md->mask) + size != (head & md->mask)) { 134*86470930SIngo Molnar buf = &data[old & md->mask]; 135*86470930SIngo Molnar size = md->mask + 1 - (old & md->mask); 136*86470930SIngo Molnar old += size; 137*86470930SIngo Molnar 138*86470930SIngo Molnar while (size) { 139*86470930SIngo Molnar int ret = write(output, buf, size); 140*86470930SIngo Molnar 141*86470930SIngo Molnar if (ret < 0) 142*86470930SIngo Molnar die("failed to write"); 143*86470930SIngo Molnar 144*86470930SIngo Molnar size -= ret; 145*86470930SIngo Molnar buf += ret; 146*86470930SIngo Molnar 147*86470930SIngo Molnar bytes_written += ret; 148*86470930SIngo Molnar } 149*86470930SIngo Molnar } 150*86470930SIngo Molnar 151*86470930SIngo Molnar buf = &data[old & md->mask]; 152*86470930SIngo Molnar size = head - old; 153*86470930SIngo Molnar old += size; 154*86470930SIngo Molnar 155*86470930SIngo Molnar while (size) { 156*86470930SIngo Molnar int ret = write(output, buf, size); 157*86470930SIngo Molnar 158*86470930SIngo Molnar if (ret < 0) 159*86470930SIngo Molnar die("failed to write"); 160*86470930SIngo Molnar 161*86470930SIngo Molnar size -= ret; 162*86470930SIngo Molnar buf += ret; 163*86470930SIngo Molnar 164*86470930SIngo Molnar bytes_written += ret; 165*86470930SIngo Molnar } 166*86470930SIngo Molnar 167*86470930SIngo Molnar md->prev = old; 168*86470930SIngo Molnar } 169*86470930SIngo Molnar 170*86470930SIngo Molnar static volatile int done = 0; 171*86470930SIngo Molnar 172*86470930SIngo Molnar static void sig_handler(int sig) 173*86470930SIngo Molnar { 174*86470930SIngo Molnar done = 1; 175*86470930SIngo Molnar } 176*86470930SIngo Molnar 177*86470930SIngo Molnar static void pid_synthesize_comm_event(pid_t pid, int full) 178*86470930SIngo Molnar { 179*86470930SIngo Molnar struct comm_event comm_ev; 180*86470930SIngo Molnar char filename[PATH_MAX]; 181*86470930SIngo Molnar char bf[BUFSIZ]; 182*86470930SIngo Molnar int fd, ret; 183*86470930SIngo Molnar size_t size; 184*86470930SIngo Molnar char *field, *sep; 185*86470930SIngo Molnar DIR *tasks; 186*86470930SIngo Molnar struct dirent dirent, *next; 187*86470930SIngo Molnar 188*86470930SIngo Molnar snprintf(filename, sizeof(filename), "/proc/%d/stat", pid); 189*86470930SIngo Molnar 190*86470930SIngo Molnar fd = open(filename, O_RDONLY); 191*86470930SIngo Molnar if (fd < 0) { 192*86470930SIngo Molnar fprintf(stderr, "couldn't open %s\n", filename); 193*86470930SIngo Molnar exit(EXIT_FAILURE); 194*86470930SIngo Molnar } 195*86470930SIngo Molnar if (read(fd, bf, sizeof(bf)) < 0) { 196*86470930SIngo Molnar fprintf(stderr, "couldn't read %s\n", filename); 197*86470930SIngo Molnar exit(EXIT_FAILURE); 198*86470930SIngo Molnar } 199*86470930SIngo Molnar close(fd); 200*86470930SIngo Molnar 201*86470930SIngo Molnar /* 9027 (cat) R 6747 9027 6747 34816 9027 ... */ 202*86470930SIngo Molnar memset(&comm_ev, 0, sizeof(comm_ev)); 203*86470930SIngo Molnar field = strchr(bf, '('); 204*86470930SIngo Molnar if (field == NULL) 205*86470930SIngo Molnar goto out_failure; 206*86470930SIngo Molnar sep = strchr(++field, ')'); 207*86470930SIngo Molnar if (sep == NULL) 208*86470930SIngo Molnar goto out_failure; 209*86470930SIngo Molnar size = sep - field; 210*86470930SIngo Molnar memcpy(comm_ev.comm, field, size++); 211*86470930SIngo Molnar 212*86470930SIngo Molnar comm_ev.pid = pid; 213*86470930SIngo Molnar comm_ev.header.type = PERF_EVENT_COMM; 214*86470930SIngo Molnar size = ALIGN(size, sizeof(uint64_t)); 215*86470930SIngo Molnar comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size); 216*86470930SIngo Molnar 217*86470930SIngo Molnar if (!full) { 218*86470930SIngo Molnar comm_ev.tid = pid; 219*86470930SIngo Molnar 220*86470930SIngo Molnar ret = write(output, &comm_ev, comm_ev.header.size); 221*86470930SIngo Molnar if (ret < 0) { 222*86470930SIngo Molnar perror("failed to write"); 223*86470930SIngo Molnar exit(-1); 224*86470930SIngo Molnar } 225*86470930SIngo Molnar return; 226*86470930SIngo Molnar } 227*86470930SIngo Molnar 228*86470930SIngo Molnar snprintf(filename, sizeof(filename), "/proc/%d/task", pid); 229*86470930SIngo Molnar 230*86470930SIngo Molnar tasks = opendir(filename); 231*86470930SIngo Molnar while (!readdir_r(tasks, &dirent, &next) && next) { 232*86470930SIngo Molnar char *end; 233*86470930SIngo Molnar pid = strtol(dirent.d_name, &end, 10); 234*86470930SIngo Molnar if (*end) 235*86470930SIngo Molnar continue; 236*86470930SIngo Molnar 237*86470930SIngo Molnar comm_ev.tid = pid; 238*86470930SIngo Molnar 239*86470930SIngo Molnar ret = write(output, &comm_ev, comm_ev.header.size); 240*86470930SIngo Molnar if (ret < 0) { 241*86470930SIngo Molnar perror("failed to write"); 242*86470930SIngo Molnar exit(-1); 243*86470930SIngo Molnar } 244*86470930SIngo Molnar } 245*86470930SIngo Molnar closedir(tasks); 246*86470930SIngo Molnar return; 247*86470930SIngo Molnar 248*86470930SIngo Molnar out_failure: 249*86470930SIngo Molnar fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n", 250*86470930SIngo Molnar filename); 251*86470930SIngo Molnar exit(EXIT_FAILURE); 252*86470930SIngo Molnar } 253*86470930SIngo Molnar 254*86470930SIngo Molnar static void pid_synthesize_mmap_samples(pid_t pid) 255*86470930SIngo Molnar { 256*86470930SIngo Molnar char filename[PATH_MAX]; 257*86470930SIngo Molnar FILE *fp; 258*86470930SIngo Molnar 259*86470930SIngo Molnar snprintf(filename, sizeof(filename), "/proc/%d/maps", pid); 260*86470930SIngo Molnar 261*86470930SIngo Molnar fp = fopen(filename, "r"); 262*86470930SIngo Molnar if (fp == NULL) { 263*86470930SIngo Molnar fprintf(stderr, "couldn't open %s\n", filename); 264*86470930SIngo Molnar exit(EXIT_FAILURE); 265*86470930SIngo Molnar } 266*86470930SIngo Molnar while (1) { 267*86470930SIngo Molnar char bf[BUFSIZ], *pbf = bf; 268*86470930SIngo Molnar struct mmap_event mmap_ev = { 269*86470930SIngo Molnar .header.type = PERF_EVENT_MMAP, 270*86470930SIngo Molnar }; 271*86470930SIngo Molnar int n; 272*86470930SIngo Molnar size_t size; 273*86470930SIngo Molnar if (fgets(bf, sizeof(bf), fp) == NULL) 274*86470930SIngo Molnar break; 275*86470930SIngo Molnar 276*86470930SIngo Molnar /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 277*86470930SIngo Molnar n = hex2u64(pbf, &mmap_ev.start); 278*86470930SIngo Molnar if (n < 0) 279*86470930SIngo Molnar continue; 280*86470930SIngo Molnar pbf += n + 1; 281*86470930SIngo Molnar n = hex2u64(pbf, &mmap_ev.len); 282*86470930SIngo Molnar if (n < 0) 283*86470930SIngo Molnar continue; 284*86470930SIngo Molnar pbf += n + 3; 285*86470930SIngo Molnar if (*pbf == 'x') { /* vm_exec */ 286*86470930SIngo Molnar char *execname = strrchr(bf, ' '); 287*86470930SIngo Molnar 288*86470930SIngo Molnar if (execname == NULL || execname[1] != '/') 289*86470930SIngo Molnar continue; 290*86470930SIngo Molnar 291*86470930SIngo Molnar execname += 1; 292*86470930SIngo Molnar size = strlen(execname); 293*86470930SIngo Molnar execname[size - 1] = '\0'; /* Remove \n */ 294*86470930SIngo Molnar memcpy(mmap_ev.filename, execname, size); 295*86470930SIngo Molnar size = ALIGN(size, sizeof(uint64_t)); 296*86470930SIngo Molnar mmap_ev.len -= mmap_ev.start; 297*86470930SIngo Molnar mmap_ev.header.size = (sizeof(mmap_ev) - 298*86470930SIngo Molnar (sizeof(mmap_ev.filename) - size)); 299*86470930SIngo Molnar mmap_ev.pid = pid; 300*86470930SIngo Molnar mmap_ev.tid = pid; 301*86470930SIngo Molnar 302*86470930SIngo Molnar if (write(output, &mmap_ev, mmap_ev.header.size) < 0) { 303*86470930SIngo Molnar perror("failed to write"); 304*86470930SIngo Molnar exit(-1); 305*86470930SIngo Molnar } 306*86470930SIngo Molnar } 307*86470930SIngo Molnar } 308*86470930SIngo Molnar 309*86470930SIngo Molnar fclose(fp); 310*86470930SIngo Molnar } 311*86470930SIngo Molnar 312*86470930SIngo Molnar static void synthesize_samples(void) 313*86470930SIngo Molnar { 314*86470930SIngo Molnar DIR *proc; 315*86470930SIngo Molnar struct dirent dirent, *next; 316*86470930SIngo Molnar 317*86470930SIngo Molnar proc = opendir("/proc"); 318*86470930SIngo Molnar 319*86470930SIngo Molnar while (!readdir_r(proc, &dirent, &next) && next) { 320*86470930SIngo Molnar char *end; 321*86470930SIngo Molnar pid_t pid; 322*86470930SIngo Molnar 323*86470930SIngo Molnar pid = strtol(dirent.d_name, &end, 10); 324*86470930SIngo Molnar if (*end) /* only interested in proper numerical dirents */ 325*86470930SIngo Molnar continue; 326*86470930SIngo Molnar 327*86470930SIngo Molnar pid_synthesize_comm_event(pid, 1); 328*86470930SIngo Molnar pid_synthesize_mmap_samples(pid); 329*86470930SIngo Molnar } 330*86470930SIngo Molnar 331*86470930SIngo Molnar closedir(proc); 332*86470930SIngo Molnar } 333*86470930SIngo Molnar 334*86470930SIngo Molnar static int group_fd; 335*86470930SIngo Molnar 336*86470930SIngo Molnar static void create_counter(int counter, int cpu, pid_t pid) 337*86470930SIngo Molnar { 338*86470930SIngo Molnar struct perf_counter_attr *attr = attrs + counter; 339*86470930SIngo Molnar int track = 1; 340*86470930SIngo Molnar 341*86470930SIngo Molnar attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_PERIOD; 342*86470930SIngo Molnar if (freq) { 343*86470930SIngo Molnar attr->freq = 1; 344*86470930SIngo Molnar attr->sample_freq = freq; 345*86470930SIngo Molnar } 346*86470930SIngo Molnar attr->mmap = track; 347*86470930SIngo Molnar attr->comm = track; 348*86470930SIngo Molnar attr->inherit = (cpu < 0) && inherit; 349*86470930SIngo Molnar 350*86470930SIngo Molnar track = 0; /* only the first counter needs these */ 351*86470930SIngo Molnar 352*86470930SIngo Molnar fd[nr_cpu][counter] = sys_perf_counter_open(attr, pid, cpu, group_fd, 0); 353*86470930SIngo Molnar 354*86470930SIngo Molnar if (fd[nr_cpu][counter] < 0) { 355*86470930SIngo Molnar int err = errno; 356*86470930SIngo Molnar 357*86470930SIngo Molnar error("syscall returned with %d (%s)\n", 358*86470930SIngo Molnar fd[nr_cpu][counter], strerror(err)); 359*86470930SIngo Molnar if (err == EPERM) 360*86470930SIngo Molnar printf("Are you root?\n"); 361*86470930SIngo Molnar exit(-1); 362*86470930SIngo Molnar } 363*86470930SIngo Molnar assert(fd[nr_cpu][counter] >= 0); 364*86470930SIngo Molnar fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK); 365*86470930SIngo Molnar 366*86470930SIngo Molnar /* 367*86470930SIngo Molnar * First counter acts as the group leader: 368*86470930SIngo Molnar */ 369*86470930SIngo Molnar if (group && group_fd == -1) 370*86470930SIngo Molnar group_fd = fd[nr_cpu][counter]; 371*86470930SIngo Molnar 372*86470930SIngo Molnar event_array[nr_poll].fd = fd[nr_cpu][counter]; 373*86470930SIngo Molnar event_array[nr_poll].events = POLLIN; 374*86470930SIngo Molnar nr_poll++; 375*86470930SIngo Molnar 376*86470930SIngo Molnar mmap_array[nr_cpu][counter].counter = counter; 377*86470930SIngo Molnar mmap_array[nr_cpu][counter].prev = 0; 378*86470930SIngo Molnar mmap_array[nr_cpu][counter].mask = mmap_pages*page_size - 1; 379*86470930SIngo Molnar mmap_array[nr_cpu][counter].base = mmap(NULL, (mmap_pages+1)*page_size, 380*86470930SIngo Molnar PROT_READ, MAP_SHARED, fd[nr_cpu][counter], 0); 381*86470930SIngo Molnar if (mmap_array[nr_cpu][counter].base == MAP_FAILED) { 382*86470930SIngo Molnar error("failed to mmap with %d (%s)\n", errno, strerror(errno)); 383*86470930SIngo Molnar exit(-1); 384*86470930SIngo Molnar } 385*86470930SIngo Molnar } 386*86470930SIngo Molnar 387*86470930SIngo Molnar static void open_counters(int cpu, pid_t pid) 388*86470930SIngo Molnar { 389*86470930SIngo Molnar int counter; 390*86470930SIngo Molnar 391*86470930SIngo Molnar if (pid > 0) { 392*86470930SIngo Molnar pid_synthesize_comm_event(pid, 0); 393*86470930SIngo Molnar pid_synthesize_mmap_samples(pid); 394*86470930SIngo Molnar } 395*86470930SIngo Molnar 396*86470930SIngo Molnar group_fd = -1; 397*86470930SIngo Molnar for (counter = 0; counter < nr_counters; counter++) 398*86470930SIngo Molnar create_counter(counter, cpu, pid); 399*86470930SIngo Molnar 400*86470930SIngo Molnar nr_cpu++; 401*86470930SIngo Molnar } 402*86470930SIngo Molnar 403*86470930SIngo Molnar static int __cmd_record(int argc, const char **argv) 404*86470930SIngo Molnar { 405*86470930SIngo Molnar int i, counter; 406*86470930SIngo Molnar struct stat st; 407*86470930SIngo Molnar pid_t pid; 408*86470930SIngo Molnar int flags; 409*86470930SIngo Molnar int ret; 410*86470930SIngo Molnar 411*86470930SIngo Molnar page_size = sysconf(_SC_PAGE_SIZE); 412*86470930SIngo Molnar nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); 413*86470930SIngo Molnar assert(nr_cpus <= MAX_NR_CPUS); 414*86470930SIngo Molnar assert(nr_cpus >= 0); 415*86470930SIngo Molnar 416*86470930SIngo Molnar if (!stat(output_name, &st) && !force && !append_file) { 417*86470930SIngo Molnar fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite.\n", 418*86470930SIngo Molnar output_name); 419*86470930SIngo Molnar exit(-1); 420*86470930SIngo Molnar } 421*86470930SIngo Molnar 422*86470930SIngo Molnar flags = O_CREAT|O_RDWR; 423*86470930SIngo Molnar if (append_file) 424*86470930SIngo Molnar flags |= O_APPEND; 425*86470930SIngo Molnar else 426*86470930SIngo Molnar flags |= O_TRUNC; 427*86470930SIngo Molnar 428*86470930SIngo Molnar output = open(output_name, flags, S_IRUSR|S_IWUSR); 429*86470930SIngo Molnar if (output < 0) { 430*86470930SIngo Molnar perror("failed to create output file"); 431*86470930SIngo Molnar exit(-1); 432*86470930SIngo Molnar } 433*86470930SIngo Molnar 434*86470930SIngo Molnar if (!system_wide) { 435*86470930SIngo Molnar open_counters(-1, target_pid != -1 ? target_pid : getpid()); 436*86470930SIngo Molnar } else for (i = 0; i < nr_cpus; i++) 437*86470930SIngo Molnar open_counters(i, target_pid); 438*86470930SIngo Molnar 439*86470930SIngo Molnar signal(SIGCHLD, sig_handler); 440*86470930SIngo Molnar signal(SIGINT, sig_handler); 441*86470930SIngo Molnar 442*86470930SIngo Molnar if (target_pid == -1 && argc) { 443*86470930SIngo Molnar pid = fork(); 444*86470930SIngo Molnar if (pid < 0) 445*86470930SIngo Molnar perror("failed to fork"); 446*86470930SIngo Molnar 447*86470930SIngo Molnar if (!pid) { 448*86470930SIngo Molnar if (execvp(argv[0], (char **)argv)) { 449*86470930SIngo Molnar perror(argv[0]); 450*86470930SIngo Molnar exit(-1); 451*86470930SIngo Molnar } 452*86470930SIngo Molnar } 453*86470930SIngo Molnar } 454*86470930SIngo Molnar 455*86470930SIngo Molnar if (realtime_prio) { 456*86470930SIngo Molnar struct sched_param param; 457*86470930SIngo Molnar 458*86470930SIngo Molnar param.sched_priority = realtime_prio; 459*86470930SIngo Molnar if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { 460*86470930SIngo Molnar printf("Could not set realtime priority.\n"); 461*86470930SIngo Molnar exit(-1); 462*86470930SIngo Molnar } 463*86470930SIngo Molnar } 464*86470930SIngo Molnar 465*86470930SIngo Molnar if (system_wide) 466*86470930SIngo Molnar synthesize_samples(); 467*86470930SIngo Molnar 468*86470930SIngo Molnar while (!done) { 469*86470930SIngo Molnar int hits = samples; 470*86470930SIngo Molnar 471*86470930SIngo Molnar for (i = 0; i < nr_cpu; i++) { 472*86470930SIngo Molnar for (counter = 0; counter < nr_counters; counter++) 473*86470930SIngo Molnar mmap_read(&mmap_array[i][counter]); 474*86470930SIngo Molnar } 475*86470930SIngo Molnar 476*86470930SIngo Molnar if (hits == samples) 477*86470930SIngo Molnar ret = poll(event_array, nr_poll, 100); 478*86470930SIngo Molnar } 479*86470930SIngo Molnar 480*86470930SIngo Molnar /* 481*86470930SIngo Molnar * Approximate RIP event size: 24 bytes. 482*86470930SIngo Molnar */ 483*86470930SIngo Molnar fprintf(stderr, 484*86470930SIngo Molnar "[ perf record: Captured and wrote %.3f MB %s (~%lld samples) ]\n", 485*86470930SIngo Molnar (double)bytes_written / 1024.0 / 1024.0, 486*86470930SIngo Molnar output_name, 487*86470930SIngo Molnar bytes_written / 24); 488*86470930SIngo Molnar 489*86470930SIngo Molnar return 0; 490*86470930SIngo Molnar } 491*86470930SIngo Molnar 492*86470930SIngo Molnar static const char * const record_usage[] = { 493*86470930SIngo Molnar "perf record [<options>] [<command>]", 494*86470930SIngo Molnar "perf record [<options>] -- <command> [<options>]", 495*86470930SIngo Molnar NULL 496*86470930SIngo Molnar }; 497*86470930SIngo Molnar 498*86470930SIngo Molnar static const struct option options[] = { 499*86470930SIngo Molnar OPT_CALLBACK('e', "event", NULL, "event", 500*86470930SIngo Molnar "event selector. use 'perf list' to list available events", 501*86470930SIngo Molnar parse_events), 502*86470930SIngo Molnar OPT_INTEGER('p', "pid", &target_pid, 503*86470930SIngo Molnar "record events on existing pid"), 504*86470930SIngo Molnar OPT_INTEGER('r', "realtime", &realtime_prio, 505*86470930SIngo Molnar "collect data with this RT SCHED_FIFO priority"), 506*86470930SIngo Molnar OPT_BOOLEAN('a', "all-cpus", &system_wide, 507*86470930SIngo Molnar "system-wide collection from all CPUs"), 508*86470930SIngo Molnar OPT_BOOLEAN('A', "append", &append_file, 509*86470930SIngo Molnar "append to the output file to do incremental profiling"), 510*86470930SIngo Molnar OPT_BOOLEAN('f', "force", &force, 511*86470930SIngo Molnar "overwrite existing data file"), 512*86470930SIngo Molnar OPT_LONG('c', "count", &default_interval, 513*86470930SIngo Molnar "event period to sample"), 514*86470930SIngo Molnar OPT_STRING('o', "output", &output_name, "file", 515*86470930SIngo Molnar "output file name"), 516*86470930SIngo Molnar OPT_BOOLEAN('i', "inherit", &inherit, 517*86470930SIngo Molnar "child tasks inherit counters"), 518*86470930SIngo Molnar OPT_INTEGER('F', "freq", &freq, 519*86470930SIngo Molnar "profile at this frequency"), 520*86470930SIngo Molnar OPT_INTEGER('m', "mmap-pages", &mmap_pages, 521*86470930SIngo Molnar "number of mmap data pages"), 522*86470930SIngo Molnar OPT_END() 523*86470930SIngo Molnar }; 524*86470930SIngo Molnar 525*86470930SIngo Molnar int cmd_record(int argc, const char **argv, const char *prefix) 526*86470930SIngo Molnar { 527*86470930SIngo Molnar int counter; 528*86470930SIngo Molnar 529*86470930SIngo Molnar argc = parse_options(argc, argv, options, record_usage, 0); 530*86470930SIngo Molnar if (!argc && target_pid == -1 && !system_wide) 531*86470930SIngo Molnar usage_with_options(record_usage, options); 532*86470930SIngo Molnar 533*86470930SIngo Molnar if (!nr_counters) 534*86470930SIngo Molnar nr_counters = 1; 535*86470930SIngo Molnar 536*86470930SIngo Molnar for (counter = 0; counter < nr_counters; counter++) { 537*86470930SIngo Molnar if (attrs[counter].sample_period) 538*86470930SIngo Molnar continue; 539*86470930SIngo Molnar 540*86470930SIngo Molnar attrs[counter].sample_period = default_interval; 541*86470930SIngo Molnar } 542*86470930SIngo Molnar 543*86470930SIngo Molnar return __cmd_record(argc, argv); 544*86470930SIngo Molnar } 545