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
00069
00070
00071
00072
00073
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
00144
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 }
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;
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
00362
00363
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
00428
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
00436
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
00495
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
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
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 }