Fwd: Potential deadlock in operf when using --pid
大平怜 <[email protected]>
| Newsgroups | gmane.linux.oprofile |
|---|---|
| Message-ID | <CAERM-Ph5E7_U9K=wuRt5+9gZhmDfGukiTnxejPOfpQk4JsKWfA@mail.gmail.com> |
I forgot to include oprofile-list. Regards, Rei Odaira ---------- Forwarded message ---------- From: 大平怜 <[email protected]> Date: 2016-06-24 19:04 GMT-05:00 Subject: Re: Potential deadlock in operf when using --pid To: William Cohen <[email protected]> Hi, Now I come back to this problem. I am attaching two patches to solve it. They apply to the latest master in the git repository. Please apply oprofile_avoid_deadlock_1.patch first and then oprofile_avoid_deadlock_2.patch. The first patch is just for refactoring the code to make the second patch possible, and the second patch is for the actual problem solving. So, the problem is that the operf-record process is blocked on a write to the sample output pipe when the pipe is full, while the operf-read process, which is the consumer of the pipe, cannot read from the pipe because it is blocked on a read from the comm pipe, to which the operf-record process is supposed to write. Please refer to the previous emails for the detailed problem description. |<--sample output pipe--| operf-read |-------comm pipe------>| operf-record |<------comm pipe-------| My solution is to make the sample output pipe non-blocking on the operf-record side. When the sample output pipe is full, instead of waiting on it, the operf-record process polls both the sample output pipe and the (read-end of) comm pipe. If there is a message in the comm pipe from the operf-read process, the operf-record process handles it and writes a response to the comm pipe, so that the operf-read process can finish being blocked on the read from the comm pipe and eventually can consume the sample output pipe. There are some other ways to solve this problem, so any comments are welcome. With my patches, you can finish profiling oprofile_multithread_test by a single ctrl-c. They passed all the tests in oprofile-tests. Regards, Rei Odaira 2015-10-02 14:19 GMT-05:00 William Cohen <[email protected]>: > On 10/02/2015 11:10 AM, 大平怜 wrote: > > Sorry, I sent wrong source code. I am attaching the right one. > > > > > > Regards, > > Rei Odaira > > > > 2015-10-01 18:32 GMT-05:00 大平怜 <[email protected] <mailto: > [email protected]>>: > > > > Hi Will, > > > > How about the attached test program? This almost always causes the > problem in my environment. > > > > > gcc -o oprofile_multithread_test oprofile_multithread_test.c > -lpthread > > > ./oprofile_multithread_test > > Usage: oprofile_multithread_test <number of spawns> <number of > threads> <number of operations per thread> > > > ./oprofile_multithread_test -1 16 100000 > > > > In this example, oprofile_multithread_test spawns threads infinitely > but runs maximum 16 threads simultaneously. Each thread performs addition > 100000 times and then completes. Please use ^C to end this program if you > specify -1 to the number of spawns. > > > > If you profile this program with operf --pid, I expect you will not > be able to finish operf by a single ^C. > > > > > > Regards, > > Rei Odaira > > Hi, > > I was able to get the failure mentioned with the example code on a rhel7 > machine. > > $ /usr/local/bin/operf --events=CPU_CLK_UNHALTED:100000000:0:1:1 --pid > `pgrep oprofile_multi` > operf: Press Ctl-c or 'kill -SIGINT 8976' to stop profiling > operf: Profiler started > Unable to collect samples for forked process 9569. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9570. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9571. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9572. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9573. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9574. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9576. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9577. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9578. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9579. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9580. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9581. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9582. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9583. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9584. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9585. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9586. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9587. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9588. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9589. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9590. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9591. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9592. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9593. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9594. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9595. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9596. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9597. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9598. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9599. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9600. Process may have ended > before recording could be started. > Unable to collect samples for forked process 9601. Process may have ended > before recording could be started. > ^C^Cwaitpid for operf-record process failed: Interrupted system call > ^Cwaitpid for operf-read process failed: Interrupted system call > Error running profiler > > Threads are being created and destroyed very often in the example code. It > took multiple times to get operf to connect up to all the threads. Many > times I get messages like the following: > > $ /usr/local/bin/operf --events=CPU_CLK_UNHALTED:100000000:0:1:1 --pid > `pgrep oprofile_multi` > !!!! No samples collected !!! > The target program/command ended before profiling was started. > operf record init failed > usage: operf [ options ] [ --system-wide | --pid <pid> | [ command [ args > ] ] ] > Error running profiler > > However, it operf gets started, it seems to reliably fail with the ctl-c. > > -Will > > > > > 2015-10-01 15:42 GMT-05:00 William Cohen <[email protected] <mailto: > [email protected]>>: > > > > On 09/30/2015 06:07 PM, 大平怜 wrote: > > > Hello again, > > > > > > When using --pid, I have occasionally seen operf does not end > by hitting ^C once. By hitting ^C multiple times, operf ends with error > messages: > > > > Hi, > > > > I tried to replicate this on my local machine, but haven't seen > it occur yet. How often does it happen? Also does it make a difference > when the event sampling rate is changed? There is just one monitored > process and it isn't spawning new processes? > > > > > > > > ----- > > > operf --events=CPU_CLK_UNHALTED:100000000:0:1:1 --pid `pgrep > -f CassandraDaemon` > > > Kernel profiling is not possible with current system config. > > > Set /proc/sys/kernel/kptr_restrict to 0 to collect kernel > samples. > > > operf: Press Ctl-c or 'kill -SIGINT 18042' to stop profiling > > > operf: Profiler started > > > ^C^Cwaitpid for operf-record process failed: Interrupted > system call > > > ^Cwaitpid for operf-read process failed: Interrupted system > call > > > Error running profiler > > > ----- > > > > > > I am using the master branch in the git repository. > > > > > > Here is what I found: > > > The operf-read process was waiting for a read of a sample ID > from the operf-record process to return: > > > (gdb) bt > > > #0 0x00007fd90e0fa480 in __read_nocancel () > > > at ../sysdeps/unix/syscall-template.S:81 > > > #1 0x0000000000412999 in read (__nbytes=8, > __buf=0x7ffddc82b620, > > > __fd=<optimized out>) at > /usr/include/x86_64-linux-gnu/bits/unistd.h:44 > > > #2 __handle_fork_event (event=0x98e860) at operf_utils.cpp:125 > > > #3 OP_perf_utils::op_write_event (event=event@entry=0x98e860, > > > sample_type=<optimized out>) at operf_utils.cpp:834 > > > #4 0x0000000000417250 in operf_read::convertPerfData ( > > > this=this@entry=0x648000 <operfRead>) at > operf_counter.cpp:1147 > > > #5 0x000000000040a4cb in convert_sample_data () at > operf.cpp:947 > > > #6 0x0000000000407482 in _run () at operf.cpp:625 > > > #7 main (argc=4, argv=0x7ffddc82be48) at operf.cpp:1539 > > > > > > The operf-record process was waiting for a write of sample > data to the operf-read process to complete. Why did the write of the > sample data block? My guess is that the sample_data_pipe was full: > > > (gdb) bt > > > #0 0x00007fbe0dc9f4e0 in __write_nocancel () > > > at ../sysdeps/unix/syscall-template.S:81 > > > #1 0x000000000040cd0e in OP_perf_utils::op_write_output > (output=6, > > > buf=0x7fbe0e4e5140, size=32) at operf_utils.cpp:989 > > > #2 0x000000000040d605 in > OP_perf_utils::op_get_kernel_event_data ( > > > md=0xd3c7f0, pr=pr@entry=0xd07900) at operf_utils.cpp:1443 > > > #3 0x000000000041bc12 in operf_record::recordPerfData > (this=0xd07900) > > > at operf_counter.cpp:846 > > > #4 0x00000000004098b8 in start_profiling () at operf.cpp:402 > > > #5 0x0000000000406305 in _run () at operf.cpp:596 > > > #6 main (argc=4, argv=0x7ffdc6fcde58) at operf.cpp:1539 > > > > > > As a result, when I hit ^C, the operf main process sent > SIGUSR1 to the operf-record process, in which the write returned with EINTR > and simply got retried. Since the operf-record process did not end, the > operf main process waited at waitpid(2) forever. > > > > > > Do you think my guess makes sense? What would be a > fundamental solution? Simply extending the pipe size would not be > appropriate.... > > > > I am wondering if there are any other nuggets of information > that can be gathered by using "--verbose debug,misc" and other "--verbose" > variations on the operf command line. It would be worthwhile to take a > close look at the code in operf.cpp and see how ctl-c is being handled. > There could be a problem with the order that things are shutdown, causing > the problem. I noticed around line 406 and of operf.cpp there is the > following code: > > > > catch (const runtime_error & re) { > > /* If the user does ctl-c, the > operf-record process may get interrupted > > * in a system call, causing problems > with writes to the sample data pipe. > > * So we'll ignore such errors unless > the user requests debug info. > > */ > > if (!ctl_c || (cverb << vmisc)) { > > cerr << "Caught runtime_error: " > << re.what() << endl; > > exit_code = EXIT_FAILURE; > > } > > goto fail_out; > > } > > > > -Will > > > > > > > > > > > > > > > > > ------------------------------------------------------------------------------ > > > > > > > > _______________________________________________ > > oprofile-list mailing list > > [email protected] > > https://lists.sourceforge.net/lists/listinfo/oprofile-list > > > > ------------------------------------------------------------------------------ Attend Shape: An AT&T Tech Expo July 15-16. Meet us at AT&T Park in San Francisco, CA to explore cutting-edge tech and listen to tech luminaries present their vision of the future. This family event has something for everyone, including kids. Get more information and register today. http://sdm.link/attshape _______________________________________________ oprofile-list mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/oprofile-list
oprofile_avoid_deadlock_1.patch
(application/octet-stream, 5 KB)
From 2b67533e7cacec028fe4e7429ae4ccbdf7d1f567 Mon Sep 17 00:00:00 2001 From: Rei Odaira <[email protected]> Date: Fri, 24 Jun 2016 12:06:39 -0500 Subject: [PATCH] Refactor operf_record::_start_recoding_new_thread to include read from a pipe and checks --- libperf_events/operf_counter.cpp | 50 ++++++++++++++++++++++------------------ libperf_events/operf_counter.h | 2 +- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/libperf_events/operf_counter.cpp b/libperf_events/operf_counter.cpp index 023f210..e51d108 100644 --- a/libperf_events/operf_counter.cpp +++ b/libperf_events/operf_counter.cpp @@ -759,14 +759,26 @@ void operf_record::record_process_info(void) } } -int operf_record::_start_recoding_new_thread(pid_t id) +void operf_record::_check_new_thread(void) { + pid_t pi; + ssize_t len; string err_msg; int rc, fd_for_set_output = -1; struct comm_event ce; u64 sample_id; struct pollfd * old_polldata = poll_data; + len = read(read_comm_pipe, &pi, sizeof(pi)); + + if (len < 0 && errno != EAGAIN) { + cverb << vrecord << "Non-fatal error: read_comm_pipe returned too few bytes" << endl; + } else if (len != sizeof(pi) || (procs.find(pi) != procs.end())) { + return; + } + // Start profiling this new thread + cverb << vrecord << "Start recording for new thread " << pi << endl; + num_mmaps++; poll_data = new struct pollfd [num_mmaps]; // Copy only the existing pollfd objects from the array. The new pollfd will @@ -777,7 +789,7 @@ int operf_record::_start_recoding_new_thread(pid_t id) // Make a pseudo comm_event object. At this point, the // only field we need to set is tid. memset(&ce, 0, sizeof(ce)); - ce.tid = id; + ce.tid = pi; add_process(ce); for (unsigned event = 0; event < evts.size(); event++) { @@ -785,13 +797,13 @@ int operf_record::_start_recoding_new_thread(pid_t id) (!pid_started && !system_wide), callgraph, separate_cpu, false, event)); - if (op_ctr.perf_event_open(id, -1, this, false) < 0) { + if (op_ctr.perf_event_open(pi, -1, this, false) < 0) { sample_id = OP_PERF_NO_SAMPLE_ID; // Send special value to convert process to indicate failure ssize_t len = write(write_comm_pipe, &sample_id, sizeof(sample_id)); if (len < 0) perror("Internal error on convert write_comm_pipe"); - return -1; + goto fail; } perfCounters.push_back(op_ctr); int fd = op_ctr.get_fd(); @@ -801,15 +813,15 @@ int operf_record::_start_recoding_new_thread(pid_t id) } else { if ((rc = ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, fd_for_set_output)) < 0) - perror("_start_recoding_new_thread: ioctl #1 failed"); + perror("_check_new_thread: ioctl #1 failed"); } if (rc < 0) - return rc; + goto fail; if ((rc = ioctl(fd, PERF_EVENT_IOC_ENABLE)) < 0) { - perror("_start_recoding_new_thread: ioctl #2 failed"); - return rc; + perror("_check_new_thread: ioctl #2 failed"); + goto fail; } sample_id = opHeader.h_attrs[event].ids.back(); @@ -822,7 +834,12 @@ int operf_record::_start_recoding_new_thread(pid_t id) cverb << vrecord << "Sent sample_id " << sample_id << " to convert process" << endl; } - return 0; + return; + + fail: + cerr << "Unable to collect samples for forked process " << pi + << ". Process may have ended before recording could be started." << endl; + return; } @@ -838,8 +855,6 @@ void operf_record::recordPerfData(void) cerr << "operf: Profiler started" << endl; while (1) { int prev = sample_reads; - pid_t pi; - ssize_t len; for (size_t i = 0; i < samples_array.size(); i++) { if (samples_array[i].base) @@ -852,18 +867,7 @@ void operf_record::recordPerfData(void) (void)poll(poll_data, poll_count, -1); } if (!quit && track_new_forks && procs.size() > 1) { - len = read(read_comm_pipe, &pi, sizeof(pi)); - - if (len < 0 && errno != EAGAIN) { - cverb << vrecord << "Non-fatal error: read_comm_pipe returned too few bytes" << endl; - } else if (len == sizeof(pi) && (procs.find(pi) == procs.end())) { - // Start profiling this new thread - cverb << vrecord << "Start recording for new thread " << pi << endl; - // Don't treat as fatal error if it doesn't work - if (_start_recoding_new_thread(pi) < 0) - cerr << "Unable to collect samples for forked process " << pi - << ". Process may have ended before recording could be started." << endl; - } + _check_new_thread(); } if (quit) { diff --git a/libperf_events/operf_counter.h b/libperf_events/operf_counter.h index 6e19da9..99d23ae 100644 --- a/libperf_events/operf_counter.h +++ b/libperf_events/operf_counter.h @@ -99,7 +99,7 @@ private: void setup(void); int prepareToRecord(void); int _prepare_to_record_one_fd(int idx, int fd); - int _start_recoding_new_thread(pid_t id); + void _check_new_thread(void); void record_process_info(void); void write_op_header_info(void); int _write_header_to_file(void); -- 2.5.4 (Apple Git-61)
oprofile_avoid_deadlock_2.patch
(application/octet-stream, 10.3 KB)
From f47e184e328549b31c32c80a1b749204cc30b0b7 Mon Sep 17 00:00:00 2001 From: Rei Odaira <[email protected]> Date: Fri, 24 Jun 2016 18:13:11 -0500 Subject: [PATCH] Avoid deadlock between operf-record and operf-read by making the sample output pipe of operf-read non-blocking and polling both the output pipe and the read comm pipe when the pipe is full --- libperf_events/operf_counter.cpp | 50 ++++++++++++++++++++++++++++++++++------ libperf_events/operf_counter.h | 1 + libperf_events/operf_utils.cpp | 31 +++++++++++++++++++------ libperf_events/operf_utils.h | 2 +- 4 files changed, 69 insertions(+), 15 deletions(-) diff --git a/libperf_events/operf_counter.cpp b/libperf_events/operf_counter.cpp index e51d108..ca2e421 100644 --- a/libperf_events/operf_counter.cpp +++ b/libperf_events/operf_counter.cpp @@ -361,6 +361,18 @@ operf_record::operf_record(int out_fd, bool sys_wide, pid_t the_pid, bool pid_ru << strerror(errno) << endl; _exit(EXIT_FAILURE); } + if (track_new_forks && !write_to_file) { + /* The pipe of out_fd can become full when the operf-read process + cannot consume it because the operf-read process waits on another pipe. + To avoid this deadlock, make out_fd non-blocking. + See the comments in OP_perf_utils::op_write_output(). + */ + if (fcntl(out_fd, F_SETFL, O_NONBLOCK) < 0) { + cverb << vrecord << "operf_record ctor: failed to make out_fd non_blocking; errno is: " + << strerror(errno) << endl; + cverb << vrecord << " continue execution but the operf-record and operf-read processes can deadlock on each other" << endl; + } + } cverb << vrecord << "calling setup" << endl; setup(); } @@ -380,7 +392,7 @@ int operf_record::_write_header_to_file(void) if (opHeader.h_attrs[i].id_offset == (off_t)-1) goto err_out; total += op_write_output(output_fd, &opHeader.h_attrs[i].ids[0], - opHeader.h_attrs[i].ids.size() * sizeof(u64)); + opHeader.h_attrs[i].ids.size() * sizeof(u64), this); } opHeader.attr_offset = lseek(output_fd, 0, SEEK_CUR); @@ -392,7 +404,7 @@ int operf_record::_write_header_to_file(void) f_attr.attr = attr.attr; f_attr.ids.offset = attr.id_offset; f_attr.ids.size = attr.ids.size() * sizeof(u64); - total += op_write_output(output_fd, &f_attr, sizeof(f_attr)); + total += op_write_output(output_fd, &f_attr, sizeof(f_attr), this); } opHeader.data_offset = lseek(output_fd, 0, SEEK_CUR); @@ -410,7 +422,7 @@ int operf_record::_write_header_to_file(void) if (lseek(output_fd, 0, SEEK_SET) == (off_t)-1) goto err_out; - total += op_write_output(output_fd, &f_header, sizeof(f_header)); + total += op_write_output(output_fd, &f_header, sizeof(f_header), this); if (lseek(output_fd, opHeader.data_offset + opHeader.data_size, SEEK_SET) == (off_t)-1) goto err_out; return total; @@ -433,18 +445,18 @@ int operf_record::_write_header_to_pipe(void) f_header.attrs.size = evts.size() * sizeof(f_attr); f_header.data.size = 0; - total = op_write_output(output_fd, &f_header, sizeof(f_header)); + total = op_write_output(output_fd, &f_header, sizeof(f_header), this); for (unsigned i = 0; i < evts.size(); i++) { struct op_header_evt_info attr = opHeader.h_attrs[i]; f_attr.attr = attr.attr; f_attr.ids.size = attr.ids.size() * sizeof(u64); - total += op_write_output(output_fd, &f_attr, sizeof(f_attr)); + total += op_write_output(output_fd, &f_attr, sizeof(f_attr), this); } for (unsigned i = 0; i < evts.size(); i++) { total += op_write_output(output_fd, &opHeader.h_attrs[i].ids[0], - opHeader.h_attrs[i].ids.size() * sizeof(u64)); + opHeader.h_attrs[i].ids.size() * sizeof(u64), this); } return total; } @@ -744,7 +756,7 @@ void operf_record::record_process_info(void) for (unsigned int proc_idx = 0; proc_idx < procs.size(); proc_idx++, proc_it++) { struct comm_event ce = proc_it->second; - int num = OP_perf_utils::op_write_output(output_fd, &ce, ce.header.size); + int num = OP_perf_utils::op_write_output(output_fd, &ce, ce.header.size, this); add_to_total(num); if (cverb << vrecord) cout << "Created COMM event for " << ce.comm << endl; @@ -842,6 +854,30 @@ void operf_record::_check_new_thread(void) return; } +void operf_record::handle_output_full(int output) +{ + struct pollfd poll_output_and_comm[2]; + poll_output_and_comm[0].fd = output; + poll_output_and_comm[0].events = POLLOUT; + poll_output_and_comm[1].fd = read_comm_pipe; + poll_output_and_comm[1].events = POLLIN; + + for ( ; ; ) { + if (poll(poll_output_and_comm, 2, -1) < 0) { + if (errno == EINTR) + continue; + string errmsg = "Internal error: Failed to poll output fd and communication pipe. errno is "; + errmsg += strerror(errno); + throw runtime_error(errmsg); + } + if ((poll_output_and_comm[1].revents | POLLIN) && procs.size() > 1) { + _check_new_thread(); + } + if (poll_output_and_comm[0].revents | POLLOUT) + break; + } +} + void operf_record::recordPerfData(void) { diff --git a/libperf_events/operf_counter.h b/libperf_events/operf_counter.h index 99d23ae..e9aa03d 100644 --- a/libperf_events/operf_counter.h +++ b/libperf_events/operf_counter.h @@ -93,6 +93,7 @@ public: unsigned int get_total_bytes_recorded(void) const { return total_bytes_recorded; } void register_perf_event_id(unsigned counter, u64 id, perf_event_attr evt_attr); bool get_valid(void) { return valid; } + void handle_output_full(int output); private: void create(std::string outfile, std::vector<operf_event_t> & evts); diff --git a/libperf_events/operf_utils.cpp b/libperf_events/operf_utils.cpp index ff972d4..39b5b00 100644 --- a/libperf_events/operf_utils.cpp +++ b/libperf_events/operf_utils.cpp @@ -982,7 +982,7 @@ int OP_perf_utils::op_mmap_trace_file(struct mmap_info & info, bool init) } -int OP_perf_utils::op_write_output(int output, void *buf, size_t size) +int OP_perf_utils::op_write_output(int output, void *buf, size_t size, operf_record * pr) { int sum = 0; while (size) { @@ -991,6 +991,23 @@ int OP_perf_utils::op_write_output(int output, void *buf, size_t size) if (ret < 0) { if (errno == EINTR) continue; + else if (errno == EAGAIN) { + /* The output pipe is full. It is typically because + the consumer of the pipe, the operf-read process, is + being blocked on a read from the comm pipe. + handle_output_full() will poll both the sample output pipe + and the read end of the comm pipe. + If there is a message in the comm pipe from the operf-read + process, handle_output_full() will call _check_new_thread() + to handle the message and then will write a response + to the comm pipe. As a result, the operf-read process will + finish being blocked on the read from the comm pipe and + consume the output file, and eventually this operf-record + process can write to the output pipe. + */ + pr->handle_output_full(output); + continue; + } string errmsg = "Internal error: Failed to write sample data to output fd. errno is "; errmsg += strerror(errno); @@ -1059,7 +1076,7 @@ void OP_perf_utils::op_get_vsyscall_mapping(pid_t tgid, int output_fd, operf_rec mmap.tid = tgid; mmap.header.size = (sizeof(mmap) - (sizeof(mmap.filename) - size)); - int num = OP_perf_utils::op_write_output(output_fd, &mmap, mmap.header.size); + int num = OP_perf_utils::op_write_output(output_fd, &mmap, mmap.header.size, pr); if (cverb << vrecord) cout << "Created MMAP event for " << imagename << endl; pr->add_to_total(num); @@ -1130,7 +1147,7 @@ void OP_perf_utils::op_record_process_exec_mmaps(pid_t pid, pid_t tgid, int outp mmap.tid = pid; mmap.header.size = (sizeof(mmap) - (sizeof(mmap.filename) - size)); - int num = OP_perf_utils::op_write_output(output_fd, &mmap, mmap.header.size); + int num = OP_perf_utils::op_write_output(output_fd, &mmap, mmap.header.size, pr); if (cverb << vrecord) cout << "Created MMAP event for " << imagename << endl; pr->add_to_total(num); @@ -1341,7 +1358,7 @@ static void _record_module_info(int output_fd, operf_record * pr) mmap.tid = 0; mmap.header.size = (sizeof(mmap) - (sizeof(mmap.filename) - size)); - int num = OP_perf_utils::op_write_output(output_fd, &mmap, mmap.header.size); + int num = OP_perf_utils::op_write_output(output_fd, &mmap, mmap.header.size, pr); if (cverb << vrecord) cout << "Created MMAP event for " << module_name << ". Size: " << module_size << "; start addr: " << start_address << endl; @@ -1388,7 +1405,7 @@ void OP_perf_utils::op_record_kernel_info(string vmlinux_file, u64 start_addr, u mmap.tid = 0; mmap.header.size = (sizeof(mmap) - (sizeof(mmap.filename) - size)); - int num = op_write_output(output_fd, &mmap, mmap.header.size); + int num = op_write_output(output_fd, &mmap, mmap.header.size, pr); if (cverb << vrecord) { ostringstream message; message << "Created MMAP event of size " << mmap.header.size << " for " <<mmap.filename << ". length: " @@ -1434,13 +1451,13 @@ void OP_perf_utils::op_get_kernel_event_data(struct mmap_data *md, operf_record buf = &data[old & md->mask]; size = md->mask + 1 - (old & md->mask); old += size; - pr->add_to_total(op_write_output(out_fd, buf, size)); + pr->add_to_total(op_write_output(out_fd, buf, size, pr)); } buf = &data[old & md->mask]; size = head - old; old += size; - pr->add_to_total(op_write_output(out_fd, buf, size)); + pr->add_to_total(op_write_output(out_fd, buf, size, pr)); md->prev = old; pc->data_tail = old; } diff --git a/libperf_events/operf_utils.h b/libperf_events/operf_utils.h index 32954cc..e0a3326 100644 --- a/libperf_events/operf_utils.h +++ b/libperf_events/operf_utils.h @@ -84,7 +84,7 @@ void op_perfrecord_sigusr1_handler(int sig __attribute__((unused)), int op_get_process_info(bool system_wide, pid_t pid, operf_record * pr); void op_record_process_exec_mmaps(pid_t pid, pid_t tgid, int output_fd, operf_record * pr); void op_get_vsyscall_mapping(pid_t tgid, int output_fd, operf_record * pr); -int op_write_output(int output, void *buf, size_t size); +int op_write_output(int output, void *buf, size_t size, operf_record * pr); int op_write_event(event_t * event, u64 sample_type); int op_read_from_stream(std::ifstream & is, char * buf, std::streamsize sz); int op_mmap_trace_file(struct mmap_info & info, bool init); -- 2.5.4 (Apple Git-61)