/* Print status when ^\ pressed */ static void sigquit_handler(int signum, siginfo_t *info, void *uc) { int i; for(i=0;i<NUM_EVENTS;i++) { if (event_data[i].active) { perf_pretty_print_event(stdout, event_data[i].fd, getpid(), &event_data[i].attr, event_data[i].pid, event_data[i].cpu, event_data[i].group_fd, event_data[i].flags ); } } }
static void open_event(char *line) { struct perf_event_attr *pe; int fd,orig_fd,remapped_group_fd; pid_t pid; int cpu,group_fd,orig_size; long int flags; unsigned char zeros[4096]; /* urgh, necessary. Took forever to track this down */ /* data from the poll structure was leaking in if not */ /* entirely zero, and also getting E2BIG errors if we */ /* set the size to a "too big" value and there were */ /* non-zero values in that space. */ /* The max size of a struct is the pagesize, so make */ /* all events live in a sea of zeros to avoid problems*/ memset(&zeros,0,4096); pe=(struct perf_event_attr *)&zeros; /* I hate bitfields */ int disabled,inherit,pinned,exclusive; int exclude_user,exclude_kernel,exclude_hv,exclude_idle; int mmap,comm,freq,inherit_stat; int enable_on_exec,task,watermark,precise_ip; int mmap_data,sample_id_all,exclude_host,exclude_guest; int exclude_callchain_user,exclude_callchain_kernel; int mmap2,comm_exec; sscanf(line, "%*c %d %d %d %d %lx " "%x %x " "%llx %llx %llx %llx " "%d %d %d %d " "%d %d %d %d " "%d %d %d %d " "%d %d %d %d " "%d %d %d %d " "%d %d " "%llx %llx %lld " "%d %d %lld %d %d %d", &orig_fd,&pid,&cpu,&group_fd,&flags, &pe->type,&pe->size, &pe->config,&pe->sample_period,&pe->sample_type,&pe->read_format, &disabled,&inherit,&pinned,&exclusive, &exclude_user,&exclude_kernel,&exclude_hv,&exclude_idle, &mmap,&comm,&freq,&inherit_stat, &enable_on_exec,&task,&watermark,&precise_ip, &mmap_data,&sample_id_all,&exclude_host,&exclude_guest, &pe->wakeup_events,&pe->bp_type, &pe->config1,&pe->config2,&pe->branch_sample_type, &exclude_callchain_kernel,&exclude_callchain_user, &pe->sample_regs_user,&pe->sample_stack_user,&mmap2,&comm_exec); errno=0; /* use recorded value for pid not our actual pid */ if (pid==original_pid) { pid=getpid(); } /* re-populate bitfields */ /* can't sscanf into them */ pe->disabled=disabled; pe->inherit=inherit; pe->pinned=pinned; pe->exclusive=exclusive; pe->exclude_user=exclude_user; pe->exclude_kernel=exclude_kernel; pe->exclude_hv=exclude_hv; pe->exclude_idle=exclude_idle; pe->mmap=mmap; pe->comm=comm; pe->freq=freq; pe->inherit_stat=inherit_stat; pe->enable_on_exec=enable_on_exec; pe->task=task; pe->watermark=watermark; pe->precise_ip=precise_ip; pe->mmap_data=mmap_data; pe->sample_id_all=sample_id_all; pe->exclude_host=exclude_host; pe->exclude_guest=exclude_guest; pe->exclude_callchain_user=exclude_callchain_user; pe->exclude_callchain_kernel=exclude_callchain_kernel; pe->mmap2=mmap2; pe->comm_exec=comm_exec; /* kernel over-writes this sometimes :( */ orig_size=pe->size; if (group_fd==-1) { remapped_group_fd=-1; } else { remapped_group_fd=fd_remap[group_fd]; } fd=perf_event_open(pe,pid,cpu,remapped_group_fd,flags); if (fd<0) { fprintf(stderr,"Line %lld Error opening %s : %s\n", line_num,line,strerror(errno)); perf_pretty_print_event(stderr,orig_fd,original_pid, pe, pid, cpu, remapped_group_fd,flags); if (errno==E2BIG) { printf("Too big! Kernel returns %d we were %d\n", pe->size,orig_size); } #if 0 { int i; char *blah; blah=(char *)&pe; printf("BEFORE\n"); for(i=0;i<100;i++) { printf("%d:%2x ",i,blah[i]); } printf("AFTER\n"); } #endif error=1; return; } if (orig_fd>FD_REMAP_SIZE) { fprintf(stderr,"fd out of range\n"); error=1; return; } fd_remap[orig_fd]=fd; if (fd>FD_REMAP_SIZE) { fprintf(stderr,"overflow fd out of range\n"); error=1; return; } fd_overflows[fd]=0; fd_throttles[fd]=0; }
static void open_event(char *line) { struct perf_event_attr pe; int orig_fd; pid_t pid; int cpu,group_fd; long int flags; /* I hate bitfields */ int disabled,inherit,pinned,exclusive; int exclude_user,exclude_kernel,exclude_hv,exclude_idle; int mmap,comm,freq,inherit_stat; int enable_on_exec,task,watermark,precise_ip; int mmap_data,sample_id_all,exclude_host,exclude_guest; int exclude_callchain_kernel,exclude_callchain_user; int mmap2; sscanf(line, "%*c %d %d %d %d %lx " "%x %x " "%llx %llx %llx %llx " "%d %d %d %d " "%d %d %d %d " "%d %d %d %d " "%d %d %d %d " "%d %d %d %d " "%d %d " "%llx %llx %lld " "%d %d %lld %d %d ", &orig_fd,&pid,&cpu,&group_fd,&flags, &pe.type,&pe.size, &pe.config,&pe.sample_period,&pe.sample_type,&pe.read_format, &disabled,&inherit,&pinned,&exclusive, &exclude_user,&exclude_kernel,&exclude_hv,&exclude_idle, &mmap,&comm,&freq,&inherit_stat, &enable_on_exec,&task,&watermark,&precise_ip, &mmap_data,&sample_id_all,&exclude_host,&exclude_guest, &pe.wakeup_events,&pe.bp_type, &pe.config1,&pe.config2,&pe.branch_sample_type, &exclude_callchain_kernel,&exclude_callchain_user, &pe.sample_regs_user,&pe.sample_stack_user,&mmap2); /* re-populate bitfields */ /* can't sscanf into them */ pe.disabled=disabled; pe.inherit=inherit; pe.pinned=pinned; pe.exclusive=exclusive; pe.exclude_user=exclude_user; pe.exclude_kernel=exclude_kernel; pe.exclude_hv=exclude_hv; pe.exclude_idle=exclude_idle; pe.mmap=mmap; pe.comm=comm; pe.freq=freq; pe.inherit_stat=inherit_stat; pe.enable_on_exec=enable_on_exec; pe.task=task; pe.watermark=watermark; pe.precise_ip=precise_ip; pe.mmap_data=mmap_data; pe.sample_id_all=sample_id_all; pe.exclude_host=exclude_host; pe.exclude_guest=exclude_guest; pe.exclude_callchain_user=exclude_callchain_user; pe.exclude_callchain_kernel=exclude_callchain_kernel; pe.mmap2=mmap2; perf_pretty_print_event(stdout,orig_fd,original_pid, &pe,pid,cpu,group_fd,flags); printf("\n"); }
int main(int argc, char **argv) { FILE *logfile; char *logfile_name=NULL; char line[BUFSIZ]; char *result; long long total_syscalls=0,replay_syscalls=0; long long skip_lines=0; int i; int replay_which=REPLAY_ALL; if (argc<2) { print_usage(argv[0]); exit(1); } i=1; while(1) { if (i>=argc) break; if (argv[i][0]=='-') { switch(argv[i][1]) { case 'h': print_usage(argv[0]); exit(1); break; default: fprintf(stderr,"Unknown option -%c\n",argv[i][1]); exit(1); break; } } else { logfile_name=strdup(argv[i]); i++; } } if (logfile_name==NULL) { fprintf(stderr,"Must specify logfile name\n"); exit(1); } logfile=fopen(logfile_name,"r"); if (logfile==NULL) { fprintf(stderr,"Error opening %s\n",logfile_name); exit(1); } /* Init structs */ for(i=0;i<MAX_EVENTS;i++) { event_info[i].opened=0; event_info[i].enabled=0; mmap_info[i].valid=0; } /* Main loop */ while(1) { result=fgets(line,BUFSIZ,logfile); if (result==NULL) break; line_num++; if (line_num<skip_lines) continue; switch(line[0]) { case 'C': if (replay_which & REPLAY_CLOSE) { close_event(line); replay_syscalls++; } break; case 'F': if (replay_which & REPLAY_FORK) { fork_event(line); replay_syscalls++; } break; case 'G': sscanf(line,"%*c %d",&original_pid); printf("Original pid was %d\n",original_pid); break; case 'I': if (replay_which & REPLAY_IOCTL) { ioctl_event(line); replay_syscalls++; } break; case 'M': if (replay_which & REPLAY_MMAP) { mmap_event(line); replay_syscalls++; } break; case 'O': if (replay_which & REPLAY_OPEN) { open_event(line); replay_syscalls++; } break; case 'o': if (replay_which & REPLAY_OVERFLOW) { setup_overflow(line); replay_syscalls++; } break; case 'P': if (replay_which & REPLAY_PRCTL) { prctl_event(line); replay_syscalls++; } break; case 'p': if (replay_which & REPLAY_POLL) { poll_event(line); replay_syscalls++; } break; case 'Q': if (replay_which & REPLAY_TRASH_MMAP) { trash_mmap_event(line); replay_syscalls++; } break; case 'q': fprintf(stderr,"Quitting early\n"); exit(1); case 'R': if (replay_which & REPLAY_READ) { read_event(line); replay_syscalls++; } break; case 'S': if (replay_which & REPLAY_SEED) { /* don't need to do anything */ /* as we don't use rand */ } break; case 'U': if (replay_which & REPLAY_MUNMAP) { munmap_event(line); replay_syscalls++; } break; default: fprintf(stderr,"Line %lld Unknown log type \'%c\'\n", line_num,line[0]); break; } //if (error) break; total_syscalls++; if (total_syscalls%1000==0) { printf("%lld\n",total_syscalls); } } printf("ACTIVE EVENT REPORT\n"); printf("~~~~~~~~~~~~~~~~~~~\n"); printf("\tReplayed %lld of %lld syscalls\n", replay_syscalls,total_syscalls); int total_active=0,total_opened=0; for(i=0;i<MAX_EVENTS;i++) { if (event_info[i].opened) total_opened++; if (event_info[i].enabled) total_active++; } printf("\t%d events open, %d events active\n", total_opened,total_active); printf("ENABLED EVENTS\n\n"); for(i=0;i<MAX_EVENTS;i++) { if (event_info[i].enabled) { perf_pretty_print_event(stdout, i,original_pid, &event_info[i].attr, event_info[i].pid, event_info[i].cpu, event_info[i].group_fd, event_info[i].flags); printf("\n\n"); } } printf("SHORT EVENT SUMMARY\n\n"); for(i=0;i<MAX_EVENTS;i++) { if (event_info[i].enabled) { perf_pretty_print_event_short(stdout, i,original_pid, &event_info[i].attr, event_info[i].pid, event_info[i].cpu, event_info[i].group_fd, event_info[i].flags); } } return 0; }