operf_counter.cpp

Go to the documentation of this file.
00001 
00018 #include <unistd.h>
00019 #include <fcntl.h>
00020 #include <sys/ioctl.h>
00021 #include <signal.h>
00022 #include <errno.h>
00023 #include <string.h>
00024 #include <iostream>
00025 #include <stdlib.h>
00026 #include "op_events.h"
00027 #include "operf_counter.h"
00028 #include "op_abi.h"
00029 #include "cverb.h"
00030 #include "operf_process_info.h"
00031 #include "op_libiberty.h"
00032 #include "operf_stats.h"
00033 
00034 
00035 using namespace std;
00036 using namespace OP_perf_utils;
00037 
00038 
00039 volatile bool quit;
00040 volatile bool read_quit;
00041 int sample_reads;
00042 int num_mmap_pages;
00043 unsigned int pagesize;
00044 verbose vrecord("record");
00045 verbose vconvert("convert");
00046 
00047 extern bool first_time_processing;
00048 extern bool throttled;
00049 extern size_t mmap_size;
00050 extern size_t pg_sz;
00051 
00052 namespace {
00053 
00054 vector<string> event_names;
00055 
00056 static const char *__op_magic = "OPFILE";
00057 
00058 #define OP_MAGIC    (*(u64 *)__op_magic)
00059 
00060 
00061 int _get_perf_event_from_pipe(event_t * event, int sample_data_fd)
00062 {
00063     static size_t pe_header_size = sizeof(perf_event_header);
00064     char * evt = (char *)event;
00065     ssize_t num_read;
00066     perf_event_header * header = (perf_event_header *)event;
00067 
00068     /* A signal handler was setup for the operf_read process to handle interrupts
00069      * (i.e., from ctrl-C), so the read syscalls below may get interrupted.  But the
00070      * operf_read process should ignore the interrupt and continue processing
00071      * until there's no more data to read or until the parent operf process
00072      * forces us to stop.  So we must try the read operation again if it was
00073      * interrupted.
00074      */
00075 again:
00076     errno = 0;
00077     if ((num_read = read(sample_data_fd, header, pe_header_size)) < 0) {
00078         cverb << vdebug << "Read 1 of sample data pipe returned with " << strerror(errno) << endl;
00079         if (errno == EINTR)
00080             goto again;
00081         else
00082             return -1;
00083     } else if (num_read == 0) {
00084         return -1;
00085     }
00086     evt += pe_header_size;
00087     if (!header->size)
00088         return -1;
00089 
00090 again2:
00091     if ((num_read = read(sample_data_fd, evt, header->size - pe_header_size)) < 0) {
00092         cverb << vdebug << "Read 2 of sample data pipe returned with " << strerror(errno) << endl;
00093         if (errno == EINTR)
00094             goto again2;
00095         else
00096             return -1;
00097     } else if (num_read == 0) {
00098         return -1;
00099     }
00100     return 0;
00101 }
00102 
00103 event_t * _get_perf_event_from_file(struct mmap_info & info)
00104 {
00105     uint32_t size;
00106     event_t * event;
00107 
00108     if (info.offset + info.head >= info.file_data_offset + info.file_data_size)
00109         return NULL;
00110 
00111     if (!pg_sz)
00112         pg_sz = sysconf(_SC_PAGESIZE);
00113 
00114 try_again:
00115     event = (event_t *)(info.buf + info.head);
00116 
00117     if ((mmap_size != info.file_data_size) &&
00118             (((info.head + sizeof(event->header)) > mmap_size) ||
00119                     (info.head + event->header.size > mmap_size))) {
00120         int ret;
00121         u64 shift = pg_sz * (info.head / pg_sz);
00122         cverb << vconvert << "Remapping perf data file" << endl;
00123         ret = munmap(info.buf, mmap_size);
00124         if (ret) {
00125             string errmsg = "Internal error:  munmap of perf data file failed with errno: ";
00126             errmsg += strerror(errno);
00127             throw runtime_error(errmsg);
00128         }
00129 
00130         info.offset += shift;
00131         info.head -= shift;
00132         ret = op_mmap_trace_file(info, false);
00133         if (ret) {
00134             string errmsg = "Internal error:  mmap of perf data file failed with errno: ";
00135             errmsg += strerror(errno);
00136             throw runtime_error(errmsg);
00137         }
00138         goto try_again;
00139     }
00140 
00141     size = event->header.size;
00142 
00143     // The tail end of the operf data file may be zero'ed out, so we assume if we
00144     // find size==0, we're now in that area of the file, so we're done.
00145     if (size == 0)
00146         return NULL;
00147 
00148     info.head += size;
00149     if (info.offset + info.head >= info.file_data_offset + info.file_data_size)
00150         return NULL;
00151 
00152     return event;
00153 }
00154 
00155 }  // end anonymous namespace
00156 
00157 operf_counter::operf_counter(operf_event_t & evt,  bool enable_on_exec, bool do_cg,
00158                              bool separate_cpu)
00159 {
00160     memset(&attr, 0, sizeof(attr));
00161     attr.size = sizeof(attr);
00162     attr.sample_type = OP_BASIC_SAMPLE_FORMAT;
00163     if (do_cg)
00164         attr.sample_type |= PERF_SAMPLE_CALLCHAIN;
00165     if (separate_cpu)
00166         attr.sample_type |= PERF_SAMPLE_CPU;
00167     attr.type = PERF_TYPE_RAW;
00168     attr.config = evt.evt_code;
00169     attr.sample_period = evt.count;
00170     attr.inherit = 1;
00171     attr.enable_on_exec = enable_on_exec ? 1 : 0;
00172     attr.disabled  = 1;
00173     attr.exclude_idle = 0;
00174     attr.exclude_kernel = evt.no_kernel;
00175     attr.exclude_hv = evt.no_hv;
00176     attr.read_format = PERF_FORMAT_ID;
00177     event_name = evt.name;
00178     fd = id = -1;
00179 }
00180 
00181 operf_counter::~operf_counter() {
00182 }
00183 
00184 
00185 int operf_counter::perf_event_open(pid_t ppid, int cpu, unsigned event, operf_record * rec)
00186 {
00187     struct {
00188         u64 count;
00189         u64 id;
00190     } read_data;
00191 
00192     if (event == 0) {
00193         attr.mmap = 1;
00194         attr.comm = 1;
00195     }
00196     fd = op_perf_event_open(&attr, ppid, cpu, -1, 0);
00197     if (fd < 0) {
00198         int ret = -1;
00199         cverb << vrecord << "perf_event_open failed: " << strerror(errno) << endl;
00200         if (errno == EBUSY) {
00201             cerr << "The performance monitoring hardware reports EBUSY. Is another profiling tool in use?" << endl
00202                  << "On some architectures, tools such as oprofile and perf being used in system-wide "
00203                  << "mode can cause this problem." << endl;
00204             ret = OP_PERF_HANDLED_ERROR;
00205         } else if (errno == ESRCH) {
00206             cerr << "!!!! No samples collected !!!" << endl;
00207             cerr << "The target program/command ended before profiling was started." << endl;
00208             ret = OP_PERF_HANDLED_ERROR;
00209         } else {
00210             cerr << "perf_event_open failed with " << strerror(errno) << endl;
00211         }
00212         return ret;
00213     }
00214     if (read(fd, &read_data, sizeof(read_data)) == -1) {
00215         perror("Error reading perf_event fd");
00216         return -1;
00217     }
00218     rec->register_perf_event_id(event, read_data.id, attr);
00219 
00220     cverb << vrecord << "perf_event_open returning fd " << fd << endl;
00221     return fd;
00222 }
00223 
00224 operf_record::~operf_record()
00225 {
00226     cverb << vrecord << "operf_record::~operf_record()" << endl;
00227     opHeader.data_size = total_bytes_recorded;
00228     if (total_bytes_recorded)
00229         write_op_header_info();
00230 
00231     if (poll_data)
00232         delete[] poll_data;
00233     close(output_fd);
00234     for (int i = 0; i < samples_array.size(); i++) {
00235         struct mmap_data *md = &samples_array[i];
00236         munmap(md->base, (num_mmap_pages + 1) * pagesize);
00237     }
00238     samples_array.clear();
00239     evts.clear();
00240     perfCounters.clear();
00241 }
00242 
00243 operf_record::operf_record(int out_fd, bool sys_wide, pid_t the_pid, bool pid_running,
00244                            vector<operf_event_t> & events, vmlinux_info_t vi, bool do_cg,
00245 bool separate_by_cpu, bool out_fd_is_file)
00246 {
00247     int flags = O_CREAT|O_RDWR|O_TRUNC;
00248     struct sigaction sa;
00249     sigset_t ss;
00250     vmlinux_file = vi.image_name;
00251     kernel_start = vi.start;
00252     kernel_end = vi.end;
00253     pid = the_pid;
00254     pid_started = pid_running;
00255     system_wide = sys_wide;
00256     callgraph = do_cg;
00257     separate_cpu = separate_by_cpu;
00258     total_bytes_recorded = 0;
00259     poll_count = 0;
00260     evts = events;
00261     valid = false;
00262     poll_data = NULL;
00263     output_fd = out_fd;
00264     write_to_file = out_fd_is_file;
00265     opHeader.data_size = 0;
00266     num_cpus = -1;
00267 
00268     if (system_wide && (pid != -1 || pid_started))
00269         return;  // object is not valid
00270 
00271     cverb << vrecord << "operf_record ctor using output fd " << output_fd << endl;
00272 
00273     memset(&sa, 0, sizeof(struct sigaction));
00274     sa.sa_sigaction = op_perfrecord_sigusr1_handler;
00275     sigemptyset(&sa.sa_mask);
00276     sigemptyset(&ss);
00277     sigaddset(&ss, SIGUSR1);
00278     sigprocmask(SIG_UNBLOCK, &ss, NULL);
00279     sa.sa_mask = ss;
00280     sa.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
00281     cverb << vrecord << "calling sigaction" << endl;
00282     if (sigaction(SIGUSR1, &sa, NULL) == -1) {
00283         cverb << vrecord << "operf_record ctor: sigaction failed; errno is: "
00284               << strerror(errno) << endl;
00285         _exit(EXIT_FAILURE);
00286     }
00287     cverb << vrecord << "calling setup" << endl;
00288     setup();
00289 }
00290 
00291 int operf_record::_write_header_to_file(void)
00292 {
00293     struct OP_file_header f_header;
00294     struct op_file_attr f_attr;
00295     int total = 0;
00296 
00297     lseek(output_fd, sizeof(f_header), SEEK_SET);
00298 
00299     for (unsigned i = 0; i < evts.size(); i++) {
00300         opHeader.h_attrs[i].id_offset = lseek(output_fd, 0, SEEK_CUR);
00301         total += op_write_output(output_fd, &opHeader.h_attrs[i].ids[0],
00302                                  opHeader.h_attrs[i].ids.size() * sizeof(u64));
00303     }
00304 
00305     opHeader.attr_offset = lseek(output_fd, 0, SEEK_CUR);
00306 
00307     for (unsigned i = 0; i < evts.size(); i++) {
00308         struct op_header_evt_info attr = opHeader.h_attrs[i];
00309         f_attr.attr = attr.attr;
00310         f_attr.ids.offset = attr.id_offset;
00311         f_attr.ids.size = attr.ids.size() * sizeof(u64);
00312         total += op_write_output(output_fd, &f_attr, sizeof(f_attr));
00313     }
00314 
00315     opHeader.data_offset = lseek(output_fd, 0, SEEK_CUR);
00316 
00317     f_header.magic = OP_MAGIC;
00318     f_header.size = sizeof(f_header);
00319     f_header.attr_size = sizeof(f_attr);
00320     f_header.attrs.offset = opHeader.attr_offset;
00321     f_header.attrs.size = evts.size() * sizeof(f_attr);
00322     f_header.data.offset = opHeader.data_offset;
00323     f_header.data.size = opHeader.data_size;
00324 
00325     lseek(output_fd, 0, SEEK_SET);
00326     total += op_write_output(output_fd, &f_header, sizeof(f_header));
00327     lseek(output_fd, opHeader.data_offset + opHeader.data_size, SEEK_SET);
00328     return total;
00329 }
00330 
00331 int operf_record::_write_header_to_pipe(void)
00332 {
00333     struct OP_file_header f_header;
00334     struct op_file_attr f_attr;
00335     int total;
00336 
00337     f_header.magic = OP_MAGIC;
00338     f_header.size = sizeof(f_header);
00339     f_header.attr_size = sizeof(f_attr);
00340     f_header.attrs.size = evts.size() * sizeof(f_attr);
00341     f_header.data.size = 0;
00342 
00343     total = op_write_output(output_fd, &f_header, sizeof(f_header));
00344 
00345     for (unsigned i = 0; i < evts.size(); i++) {
00346         struct op_header_evt_info attr = opHeader.h_attrs[i];
00347         f_attr.attr = attr.attr;
00348         f_attr.ids.size = attr.ids.size() * sizeof(u64);
00349         total += op_write_output(output_fd, &f_attr, sizeof(f_attr));
00350     }
00351 
00352     for (unsigned i = 0; i < evts.size(); i++) {
00353         total += op_write_output(output_fd, &opHeader.h_attrs[i].ids[0],
00354                                  opHeader.h_attrs[i].ids.size() * sizeof(u64));
00355     }
00356     return total;
00357 }
00358 
00359 void operf_record::register_perf_event_id(unsigned event, u64 id, perf_event_attr attr)
00360 {
00361     // It's overkill to blindly do this assignment below every time, since this function
00362     // is invoked once for each event for each cpu; but it's not worth the bother of trying
00363     // to avoid it.
00364     opHeader.h_attrs[event].attr = attr;
00365     cverb << vrecord << "Perf header: id = " << hex << (unsigned long long)id << " for event num "
00366             << event << ", code " << attr.config <<  endl;
00367     opHeader.h_attrs[event].ids.push_back(id);
00368 }
00369 
00370 void operf_record::write_op_header_info()
00371 {
00372     if (write_to_file)
00373         add_to_total(_write_header_to_file());
00374     else
00375         add_to_total(_write_header_to_pipe());
00376 }
00377 
00378 int operf_record::prepareToRecord(int cpu, int fd)
00379 {
00380     struct mmap_data md;;
00381     md.prev = 0;
00382     md.mask = num_mmap_pages * pagesize - 1;
00383 
00384     fcntl(fd, F_SETFL, O_NONBLOCK);
00385 
00386     poll_data[cpu].fd = fd;
00387     poll_data[cpu].events = POLLIN;
00388     poll_count++;
00389 
00390     md.base = mmap(NULL, (num_mmap_pages + 1) * pagesize,
00391             PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
00392     if (md.base == MAP_FAILED) {
00393         if (errno == EPERM) {
00394             cerr << "Failed to mmap kernel profile data." << endl;
00395             cerr << "This issue may be caused by a non-root user running multiple operf" << endl;
00396             cerr << "sessions simultaneously. Try running as root or increasing the value of" << endl;
00397             cerr << "/proc/sys/kernel/perf_event_mlock_kb to resolve the problem." << endl << endl;
00398             return OP_PERF_HANDLED_ERROR;
00399         } else {
00400             perror("failed to mmap");
00401         }
00402         return -1;
00403     }
00404     samples_array.push_back(md);
00405 
00406     return 0;
00407 }
00408 
00409 
00410 void operf_record::setup()
00411 {
00412     bool all_cpus_avail = true;
00413     int rc = 0;
00414     struct dirent *entry = NULL;
00415     DIR *dir = NULL;
00416     string err_msg;
00417     char cpus_online[129];
00418     bool need_IOC_enable = (system_wide || pid_started);
00419 
00420 
00421     if (system_wide)
00422         cverb << vrecord << "operf_record::setup() for system-wide profiling" << endl;
00423     else
00424         cverb << vrecord << "operf_record::setup() with pid_started = " << pid_started << endl;
00425 
00426     if (!system_wide && pid_started) {
00427         /* We need to verify the existence of the passed PID before trying
00428          * perf_event_open or all hell will break loose.
00429          */
00430         char fname[PATH_MAX];
00431         FILE *fp;
00432         snprintf(fname, sizeof(fname), "/proc/%d/status", pid);
00433         fp = fopen(fname, "r");
00434         if (fp == NULL) {
00435             // Process must have finished or invalid PID passed into us.
00436             // We'll bail out now.
00437             cerr << "Unable to find process information for PID " << pid << "." << endl;
00438             cverb << vrecord << "couldn't open " << fname << endl;
00439             return;
00440         }
00441         fclose(fp);
00442     }
00443     pagesize = sysconf(_SC_PAGE_SIZE);
00444     num_mmap_pages = (512 * 1024)/pagesize;
00445     num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
00446     if (!num_cpus)
00447         throw runtime_error("Number of online CPUs is zero; cannot continue");;
00448 
00449     poll_data = new struct pollfd [num_cpus];
00450 
00451     cverb << vrecord << "calling perf_event_open for pid " << pid << " on "
00452           << num_cpus << " cpus" << endl;
00453     FILE * online_cpus = fopen("/sys/devices/system/cpu/online", "r");
00454     if (!online_cpus) {
00455         err_msg = "Internal Error: Number of online cpus cannot be determined.";
00456         rc = -1;
00457         goto error;
00458     }
00459     memset(cpus_online, 0, sizeof(cpus_online));
00460     fgets(cpus_online, sizeof(cpus_online), online_cpus);
00461     if (!cpus_online[0]) {
00462         fclose(online_cpus);
00463         err_msg = "Internal Error: Number of online cpus cannot be determined.";
00464         rc = -1;
00465         goto error;
00466 
00467     }
00468     if (index(cpus_online, ',')) {
00469         all_cpus_avail = false;
00470         if ((dir = opendir("/sys/devices/system/cpu")) == NULL) {
00471             fclose(online_cpus);
00472             err_msg = "Internal Error: Number of online cpus cannot be determined.";
00473             rc = -1;
00474             goto error;
00475         }
00476     }
00477     fclose(online_cpus);
00478 
00479     for (int cpu = 0; cpu < num_cpus; cpu++) {
00480         int real_cpu;
00481         int mmap_fd;
00482         bool mmap_done_for_cpu = false;
00483         if (all_cpus_avail) {
00484             real_cpu = cpu;
00485         } else {
00486             real_cpu = op_get_next_online_cpu(dir, entry);
00487             if (real_cpu < 0) {
00488                 err_msg = "Internal Error: Number of online cpus cannot be determined.";
00489                 rc = -1;
00490                 goto error;
00491             }
00492         }
00493 
00494         // Create new row to hold operf_counter objects since we need one
00495         // row for each cpu. Do the same for samples_array.
00496         vector<operf_counter> tmp_pcvec;
00497 
00498         perfCounters.push_back(tmp_pcvec);
00499         for (unsigned event = 0; event < evts.size(); event++) {
00500             evts[event].counter = event;
00501             perfCounters[cpu].push_back(operf_counter(evts[event],
00502                                                       (!pid_started && !system_wide),
00503                                                       callgraph, separate_cpu));
00504             if ((rc = perfCounters[cpu][event].perf_event_open(pid, real_cpu, event, this)) < 0) {
00505                 err_msg = "Internal Error.  Perf event setup failed.";
00506                 goto error;
00507             }
00508             if (!mmap_done_for_cpu) {
00509                 if (((rc = prepareToRecord(cpu, perfCounters[cpu][event].get_fd()))) < 0) {
00510                     err_msg = "Internal Error.  Perf event setup failed.";
00511                     goto error;
00512                 }
00513                 mmap_fd = perfCounters[cpu][event].get_fd();
00514                 mmap_done_for_cpu = true;
00515             } else {
00516                 if (ioctl(perfCounters[cpu][event].get_fd(),
00517                           PERF_EVENT_IOC_SET_OUTPUT, mmap_fd) < 0)
00518                     goto error;
00519             }
00520             if (need_IOC_enable)
00521                 if (ioctl(perfCounters[cpu][event].get_fd(), PERF_EVENT_IOC_ENABLE) < 0)
00522                     goto error;
00523         }
00524     }
00525     if (dir)
00526         closedir(dir);
00527     write_op_header_info();
00528 
00529     // Set bit to indicate we're set to go.
00530     valid = true;
00531     return;
00532 
00533 error:
00534     delete[] poll_data;
00535     poll_data = NULL;
00536     for (int i = 0; i < samples_array.size(); i++) {
00537         struct mmap_data *md = &samples_array[i];
00538         munmap(md->base, (num_mmap_pages + 1) * pagesize);
00539     }
00540     samples_array.clear();
00541     if (dir)
00542         closedir(dir);
00543     close(output_fd);
00544     if (rc != OP_PERF_HANDLED_ERROR)
00545         throw runtime_error(err_msg);
00546 }
00547 
00548 void operf_record::recordPerfData(void)
00549 {
00550     bool disabled = false;
00551     if (pid_started || system_wide) {
00552         if (op_record_process_info(system_wide, pid, this, output_fd) < 0) {
00553             for (int i = 0; i < num_cpus; i++) {
00554                 for (unsigned int evt = 0; evt < evts.size(); evt++)
00555                     ioctl(perfCounters[i][evt].get_fd(), PERF_EVENT_IOC_DISABLE);
00556             }
00557             throw runtime_error("operf_record: error recording process info");
00558         }
00559     }
00560     op_record_kernel_info(vmlinux_file, kernel_start, kernel_end, output_fd, this);
00561 
00562     while (1) {
00563         int prev = sample_reads;
00564 
00565 
00566         for (int i = 0; i < samples_array.size(); i++) {
00567             if (samples_array[i].base)
00568                 op_get_kernel_event_data(&samples_array[i], this);
00569         }
00570         if (quit && disabled)
00571             break;
00572 
00573         if (prev == sample_reads) {
00574             poll(poll_data, poll_count, -1);
00575         }
00576 
00577         if (quit) {
00578             for (int i = 0; i < num_cpus; i++) {
00579                 for (unsigned int evt = 0; evt < evts.size(); evt++)
00580                     ioctl(perfCounters[i][evt].get_fd(), PERF_EVENT_IOC_DISABLE);
00581             }
00582             disabled = true;
00583             cverb << vrecord << "operf_record::recordPerfData received signal to quit." << endl;
00584         }
00585     }
00586     cverb << vdebug << "operf recording finished." << endl;
00587 }
00588 
00589 void operf_read::init(int sample_data_pipe_fd, string input_filename, string samples_loc, op_cpu cputype,
00590                       vector<operf_event_t> & events, bool systemwide)
00591 {
00592     struct sigaction sa;
00593     sigset_t ss;
00594     sample_data_fd = sample_data_pipe_fd;
00595     inputFname = input_filename;
00596     sampledir = samples_loc;
00597     evts = events;
00598     cpu_type = cputype;
00599     syswide = systemwide;
00600     memset(&sa, 0, sizeof(struct sigaction));
00601     sa.sa_sigaction = op_perfread_sigusr1_handler;
00602     sigemptyset(&sa.sa_mask);
00603     sigemptyset(&ss);
00604     sigaddset(&ss, SIGUSR1);
00605     sigprocmask(SIG_UNBLOCK, &ss, NULL);
00606     sa.sa_mask = ss;
00607     sa.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
00608     cverb << vconvert << "operf-read calling sigaction" << endl;
00609     if (sigaction(SIGUSR1, &sa, NULL) == -1) {
00610         cverb << vconvert << "operf-read init: sigaction failed; errno is: "
00611               << strerror(errno) << endl;
00612         _exit(EXIT_FAILURE);
00613     }
00614 
00615 }
00616 
00617 operf_read::~operf_read()
00618 {
00619     evts.clear();
00620 }
00621 
00622 
00623 int operf_read::_read_header_info_with_ifstream(void)
00624 {
00625     struct OP_file_header fheader;
00626     int num_fattrs, ret = 0;
00627     size_t fattr_size;
00628     istrm.seekg(0, ios_base::beg);
00629 
00630     if (op_read_from_stream(istrm, (char *)&fheader, sizeof(fheader)) != sizeof(fheader)) {
00631         cerr << "Error: input file " << inputFname << " does not have enough data for header" << endl;
00632         ret = OP_PERF_HANDLED_ERROR;
00633         goto out;
00634     }
00635 
00636     if (memcmp(&fheader.magic, __op_magic, sizeof(fheader.magic))) {
00637         cerr << "Error: input file " << inputFname << " does not have expected header data" << endl;
00638         ret = OP_PERF_HANDLED_ERROR;
00639         goto out;
00640     }
00641 
00642     cverb << vconvert << "operf magic number " << (char *)&fheader.magic << " matches expected __op_magic " << __op_magic << endl;
00643     opHeader.attr_offset = fheader.attrs.offset;
00644     opHeader.data_offset = fheader.data.offset;
00645     opHeader.data_size = fheader.data.size;
00646     fattr_size = sizeof(struct op_file_attr);
00647     if (fattr_size != fheader.attr_size) {
00648         cerr << "Error: perf_events binary incompatibility. Event data collection was apparently "
00649              << endl << "performed under a different kernel version than current." << endl;
00650         ret = OP_PERF_HANDLED_ERROR;
00651         goto out;
00652     }
00653     num_fattrs = fheader.attrs.size/fheader.attr_size;
00654     cverb << vconvert << "num_fattrs  is " << num_fattrs << endl;
00655     istrm.seekg(opHeader.attr_offset, ios_base::beg);
00656     for (int i = 0; i < num_fattrs; i++) {
00657         struct op_file_attr f_attr;
00658         streamsize fattr_size = sizeof(f_attr);
00659         if (op_read_from_stream(istrm, (char *)&f_attr, fattr_size) != fattr_size) {
00660             cerr << "Error: Unexpected end of input file " << inputFname << "." << endl;
00661             ret = OP_PERF_HANDLED_ERROR;
00662             goto out;
00663         }
00664         opHeader.h_attrs[i].attr = f_attr.attr;
00665         streampos next_f_attr = istrm.tellg();
00666         int num_ids = f_attr.ids.size/sizeof(u64);
00667         istrm.seekg(f_attr.ids.offset, ios_base::beg);
00668         for (int id = 0; id < num_ids; id++) {
00669             u64 perf_id;
00670             streamsize perfid_size = sizeof(perf_id);
00671             if (op_read_from_stream(istrm, (char *)& perf_id, perfid_size) != perfid_size) {
00672                 cerr << "Error: Unexpected end of input file " << inputFname << "." << endl;
00673                 ret = OP_PERF_HANDLED_ERROR;
00674                 goto out;
00675             }
00676             cverb << vconvert << "Perf header: id = " << hex << (unsigned long long)perf_id << endl;
00677             opHeader.h_attrs[i].ids.push_back(perf_id);
00678         }
00679         istrm.seekg(next_f_attr, ios_base::beg);
00680     }
00681 out:
00682     istrm.close();
00683     return ret;
00684 }
00685 
00686 int operf_read::_read_perf_header_from_file(void)
00687 {
00688     int ret = 0;
00689 
00690     opHeader.data_size = 0;
00691     istrm.open(inputFname.c_str(), ios_base::in);
00692     if (!istrm.good()) {
00693         valid = false;
00694         cerr << "Input stream bad for " << inputFname << endl;
00695         ret = OP_PERF_HANDLED_ERROR;
00696         goto out;
00697     }
00698     istrm.peek();
00699     if (istrm.eof()) {
00700         cverb << vconvert << "operf_read::readPerfHeader:  Empty profile data file." << endl;
00701         valid = false;
00702         ret = OP_PERF_HANDLED_ERROR;
00703         goto out;
00704     }
00705     cverb << vconvert << "operf_read: successfully opened input file " << inputFname << endl;
00706     if ((ret = _read_header_info_with_ifstream()) == 0) {
00707         valid = true;
00708         cverb << vconvert << "Successfully read perf header" << endl;
00709     } else {
00710         valid = false;
00711     }
00712 out:
00713     return ret;
00714 }
00715 
00716 int operf_read::_read_perf_header_from_pipe(void)
00717 {
00718     struct OP_file_header fheader;
00719     string errmsg;
00720     int num_fattrs;
00721     size_t fattr_size;
00722     vector<struct op_file_attr> f_attr_cache;
00723 
00724     errno = 0;
00725     if (read(sample_data_fd, &fheader, sizeof(fheader)) != sizeof(fheader)) {
00726         errmsg = "Error reading header on sample data pipe: " + string(strerror(errno));
00727         goto fail;
00728     }
00729 
00730     if (memcmp(&fheader.magic, __op_magic, sizeof(fheader.magic))) {
00731         errmsg = "Error: operf sample data does not have expected header data";
00732         goto fail;
00733     }
00734 
00735     cverb << vconvert << "operf magic number " << (char *)&fheader.magic << " matches expected __op_magic " << __op_magic << endl;
00736     fattr_size = sizeof(struct op_file_attr);
00737     if (fattr_size != fheader.attr_size) {
00738         errmsg = "Error: perf_events binary incompatibility. Event data collection was apparently "
00739                 "performed under a different kernel version than current.";
00740         goto fail;
00741     }
00742     num_fattrs = fheader.attrs.size/fheader.attr_size;
00743     cverb << vconvert << "num_fattrs  is " << num_fattrs << endl;
00744     for (int i = 0; i < num_fattrs; i++) {
00745         struct op_file_attr f_attr;
00746         streamsize fattr_size = sizeof(f_attr);
00747         if (read(sample_data_fd, (char *)&f_attr, fattr_size) != fattr_size) {
00748             errmsg = "Error reading file attr on sample data pipe: " + string(strerror(errno));
00749             goto fail;
00750         }
00751         opHeader.h_attrs[i].attr = f_attr.attr;
00752         f_attr_cache.push_back(f_attr);
00753     }
00754     for (int i = 0; i < num_fattrs; i++) {
00755         vector<struct op_file_attr>::iterator it = f_attr_cache.begin();
00756         struct op_file_attr f_attr = *(it);
00757         int num_ids = f_attr.ids.size/sizeof(u64);
00758 
00759         for (int id = 0; id < num_ids; id++) {
00760             u64 perf_id;
00761             streamsize perfid_size = sizeof(perf_id);
00762             if (read(sample_data_fd, (char *)& perf_id, perfid_size) != perfid_size) {
00763                 errmsg = "Error reading perf ID on sample data pipe: " + string(strerror(errno));
00764                 goto fail;
00765             }
00766             cverb << vconvert << "Perf header: id = " << hex << (unsigned long long)perf_id << endl;
00767             opHeader.h_attrs[i].ids.push_back(perf_id);
00768         }
00769 
00770     }
00771     valid = true;
00772     cverb << vconvert << "Successfully read perf header" << endl;
00773     return 0;
00774 
00775 fail:
00776     cerr << errmsg;
00777     return OP_PERF_HANDLED_ERROR;
00778 }
00779 
00780 int operf_read::readPerfHeader(void)
00781 {
00782     if (!inputFname.empty())
00783         return _read_perf_header_from_file();
00784     else
00785         return _read_perf_header_from_pipe();
00786 }
00787 
00788 int operf_read::get_eventnum_by_perf_event_id(u64 id) const
00789 {
00790     for (unsigned i = 0; i < evts.size(); i++) {
00791         struct op_header_evt_info attr = opHeader.h_attrs[i];
00792         for (unsigned j = 0; j < attr.ids.size(); j++) {
00793             if (attr.ids[j] == id)
00794                 return i;
00795         }
00796     }
00797     return -1;
00798 }
00799 
00800 int operf_read::convertPerfData(void)
00801 {
00802     int num_bytes = 0;
00803     struct mmap_info info;
00804     event_t * event;
00805 
00806     if (!inputFname.empty()) {
00807         info.file_data_offset = opHeader.data_offset;
00808         info.file_data_size = opHeader.data_size;
00809         info.traceFD = open(inputFname.c_str(), O_RDONLY);
00810         if (info.traceFD == -1) {
00811             cerr << "Error: open failed with errno:\n\t" << strerror(errno) << endl;
00812             throw runtime_error("Error: Unable to open operf data file");
00813         }
00814         cverb << vdebug << "operf_read opened " << inputFname << endl;
00815         if (op_mmap_trace_file(info, true) < 0) {
00816             close(info.traceFD);
00817             throw runtime_error("Error: Unable to mmap operf data file");
00818         }
00819     } else {
00820         // Allocate way more than enough space for a really big event with a long callchain
00821         event = (event_t *)xmalloc(65536);
00822         memset(event, '\0', 65536);
00823     }
00824 
00825     for (int i = 0; i < OPERF_MAX_STATS; i++)
00826         operf_stats[i] = 0;
00827 
00828     cverb << vdebug << "Converting operf data to oprofile sample data format" << endl;
00829     cverb << vdebug << "sample type is " << hex <<  opHeader.h_attrs[0].attr.sample_type << endl;
00830     first_time_processing = true;
00831     int num_recs = 0;
00832     bool print_progress = !inputFname.empty() && syswide;
00833     if (print_progress)
00834         cerr << "Converting profile data to OProfile format" << endl;
00835     while (1) {
00836         streamsize rec_size = 0;
00837         if (!inputFname.empty()) {
00838             event = _get_perf_event_from_file(info);
00839             if (event == NULL)
00840                 break;
00841         } else {
00842             if (_get_perf_event_from_pipe(event, sample_data_fd) < 0)
00843                 break;
00844         }
00845         rec_size = event->header.size;
00846         op_write_event(event, opHeader.h_attrs[0].attr.sample_type);
00847         num_bytes += rec_size;
00848         num_recs++;
00849         if ((num_recs % 1000000 == 0) && print_progress)
00850             cerr << ".";
00851     }
00852     if (print_progress)
00853         cerr << endl;
00854 
00855     first_time_processing = false;
00856     op_reprocess_unresolved_events(opHeader.h_attrs[0].attr.sample_type);
00857 
00858     op_release_resources();
00859     operf_print_stats(operf_options::session_dir, start_time_human_readable, throttled);
00860 
00861     char * cbuf;
00862     cbuf = (char *)xmalloc(operf_options::session_dir.length() + 5);
00863     strcpy(cbuf, operf_options::session_dir.c_str());
00864     strcat(cbuf, "/abi");
00865     op_write_abi_to_file(cbuf);
00866     free(cbuf);
00867     if (inputFname.empty())
00868         close(info.traceFD);
00869     else
00870         free(event);
00871     return num_bytes;
00872 }

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1