Skip to content

Commit cf03668

Browse files
committed
Consider timestamps in comm and fork events
To prevent clearing mmap data when it is not useful, we consider timestamps of comm and fork events
1 parent 63a54d9 commit cf03668

File tree

6 files changed

+54
-16
lines changed

6 files changed

+54
-16
lines changed

include/dso_hdr.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ class DsoHdr {
118118
bool maybe_insert_erase_overlap(Dso &&dso, PerfClock::time_point timestamp);
119119

120120
// Clear all dsos and regions associated with this pid
121+
bool pid_free(int pid, PerfClock::time_point timestamp);
121122
void pid_free(int pid);
122123

123124
// Duplicate mapping info from parent_pid into pid

include/unwind.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#pragma once
77

88
#include "ddres_def.hpp"
9+
#include "perf_clock.hpp"
910

1011
#include <sys/types.h>
1112

@@ -27,6 +28,7 @@ DDRes unwindstate_unwind(UnwindState *us);
2728
void unwind_cycle(UnwindState *us);
2829

2930
// Clear unwinding structures of this pid
30-
void unwind_pid_free(UnwindState *us, pid_t pid);
31+
void unwind_pid_free(UnwindState *us, pid_t pid,
32+
PerfClock::time_point timestamp);
3133

3234
} // namespace ddprof

src/ddprof_worker.cc

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ const DDPROF_STATS s_cycled_stats[] = {
4747
const long k_clock_ticks_per_sec = sysconf(_SC_CLK_TCK);
4848

4949
/// Remove all structures related to
50-
DDRes worker_pid_free(DDProfContext &ctx, pid_t el);
50+
DDRes worker_pid_free(DDProfContext &ctx, pid_t el,
51+
PerfClock::time_point timestamp);
5152

5253
DDRes clear_unvisited_pids(DDProfContext &ctx);
5354

@@ -231,7 +232,7 @@ DDRes ddprof_unwind_sample(DDProfContext &ctx, perf_event_sample *sample,
231232
if (us->_dwfl_wrapper && us->_dwfl_wrapper->_inconsistent) {
232233
// Loaded modules were inconsistent, assume we should flush everything.
233234
LG_WRN("(Inconsistent DWFL/DSOs)%d - Free associated objects", us->pid);
234-
DDRES_CHECK_FWD(worker_pid_free(ctx, us->pid));
235+
DDRES_CHECK_FWD(worker_pid_free(ctx, us->pid, PerfClock::now()));
235236
}
236237
return res;
237238
}
@@ -303,19 +304,21 @@ DDRes aggregate_live_allocations(DDProfContext &ctx) {
303304
return {};
304305
}
305306

306-
DDRes worker_pid_free(DDProfContext &ctx, pid_t el) {
307+
DDRes worker_pid_free(DDProfContext &ctx, pid_t el,
308+
PerfClock::time_point timestamp) {
307309
DDRES_CHECK_FWD(aggregate_live_allocations_for_pid(ctx, el));
308310
UnwindState *us = ctx.worker_ctx.us;
309-
unwind_pid_free(us, el);
311+
unwind_pid_free(us, el, timestamp);
310312
ctx.worker_ctx.live_allocation.clear_pid(el);
311313
return {};
312314
}
313315

314316
DDRes clear_unvisited_pids(DDProfContext &ctx) {
315317
UnwindState *us = ctx.worker_ctx.us;
316318
const std::vector<pid_t> pids_remove = us->dwfl_hdr.get_unvisited();
319+
const PerfClock::time_point now = PerfClock::now();
317320
for (pid_t const el : pids_remove) {
318-
DDRES_CHECK_FWD(worker_pid_free(ctx, el));
321+
DDRES_CHECK_FWD(worker_pid_free(ctx, el, now));
319322
}
320323
us->dwfl_hdr.reset_unvisited();
321324
return {};
@@ -584,21 +587,21 @@ void ddprof_pr_lost(DDProfContext &ctx, const perf_event_lost *lost,
584587
}
585588

586589
DDRes ddprof_pr_comm(DDProfContext &ctx, const perf_event_comm *comm,
587-
int watcher_pos) {
590+
int watcher_pos, PerfClock::time_point timestamp) {
588591
// Change in process name (assuming exec) : clear all associated dso
589592
if (comm->header.misc & PERF_RECORD_MISC_COMM_EXEC) {
590593
LG_DBG("<%d>(COMM)%d -> %s", watcher_pos, comm->pid, comm->comm);
591-
DDRES_CHECK_FWD(worker_pid_free(ctx, comm->pid));
594+
DDRES_CHECK_FWD(worker_pid_free(ctx, comm->pid, timestamp));
592595
}
593596
return {};
594597
}
595598

596599
DDRes ddprof_pr_fork(DDProfContext &ctx, const perf_event_fork *frk,
597-
int watcher_pos) {
600+
int watcher_pos, PerfClock::time_point timestamp) {
598601
LG_DBG("<%d>(FORK)%d -> %d/%d", watcher_pos, frk->ppid, frk->pid, frk->tid);
599602
if (frk->ppid != frk->pid) {
600603
// Clear everything and populate at next error or with coming samples
601-
DDRES_CHECK_FWD(worker_pid_free(ctx, frk->pid));
604+
DDRES_CHECK_FWD(worker_pid_free(ctx, frk->pid, timestamp));
602605
ctx.worker_ctx.us->dso_hdr.pid_fork(frk->pid, frk->ppid);
603606
}
604607
return {};
@@ -745,8 +748,11 @@ DDRes ddprof_worker_process_event(const perf_event_header *hdr, int watcher_pos,
745748
break;
746749
case PERF_RECORD_COMM:
747750
if (wpid->pid) {
748-
DDRES_CHECK_FWD(ddprof_pr_comm(
749-
ctx, reinterpret_cast<const perf_event_comm *>(hdr), watcher_pos));
751+
auto timestamp = perf_clock_time_point_from_timestamp(
752+
hdr_time(hdr, watcher->sample_type));
753+
DDRES_CHECK_FWD(
754+
ddprof_pr_comm(ctx, reinterpret_cast<const perf_event_comm *>(hdr),
755+
watcher_pos, timestamp));
750756
}
751757
break;
752758
case PERF_RECORD_EXIT:
@@ -757,8 +763,11 @@ DDRes ddprof_worker_process_event(const perf_event_header *hdr, int watcher_pos,
757763
break;
758764
case PERF_RECORD_FORK:
759765
if (wpid->pid) {
760-
DDRES_CHECK_FWD(ddprof_pr_fork(
761-
ctx, reinterpret_cast<const perf_event_fork *>(hdr), watcher_pos));
766+
auto timestamp = perf_clock_time_point_from_timestamp(
767+
hdr_time(hdr, watcher->sample_type));
768+
DDRES_CHECK_FWD(
769+
ddprof_pr_fork(ctx, reinterpret_cast<const perf_event_fork *>(hdr),
770+
watcher_pos, timestamp));
762771
}
763772

764773
break;

src/dso_hdr.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,15 @@ DsoHdr::DsoFindRes DsoHdr::dso_find_or_backpopulate(pid_t pid,
404404
return dso_find_or_backpopulate(pid_mapping, pid, addr);
405405
}
406406

407+
bool DsoHdr::pid_free(int pid, PerfClock::time_point timestamp) {
408+
const auto &pid_mapping = _pid_map[pid];
409+
if (timestamp < pid_mapping._backpopulate_state.last_backpopulate_time) {
410+
return false;
411+
}
412+
pid_free(pid);
413+
return true;
414+
}
415+
407416
void DsoHdr::pid_free(int pid) { _pid_map.erase(pid); }
408417

409418
bool DsoHdr::pid_backpopulate(pid_t pid, int &nb_elts_added) {

src/unwind.cc

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,12 @@ DDRes unwindstate_unwind(UnwindState *us) {
123123
return res;
124124
}
125125

126-
void unwind_pid_free(UnwindState *us, pid_t pid) {
127-
us->dso_hdr.pid_free(pid);
126+
void unwind_pid_free(UnwindState *us, pid_t pid,
127+
PerfClock::time_point timestamp) {
128+
if (!(us->dso_hdr.pid_free(pid, timestamp))) {
129+
LG_DBG("(PID Free)%d -> avoid free of mappings (%ld)", pid,
130+
timestamp.time_since_epoch().count());
131+
}
128132
us->dwfl_hdr.clear_pid(pid);
129133
us->symbol_hdr.clear(pid);
130134
us->process_hdr.clear(pid);

test/dso-ut.cc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,19 @@ TEST(DSOTest, erase) {
160160
}
161161
}
162162

163+
TEST(DSOTest, avoid_erase) {
164+
PerfClock::init(); // init otherwise it returns 0
165+
DsoHdr dso_hdr;
166+
PerfClock::time_point old_now = PerfClock::now();
167+
pid_t my_pid = getpid();
168+
usleep(100);
169+
int nb_elts = 0;
170+
dso_hdr.pid_backpopulate(my_pid, nb_elts);
171+
EXPECT_GT(nb_elts, 0);
172+
EXPECT_FALSE(dso_hdr.pid_free(my_pid, old_now));
173+
EXPECT_GE(dso_hdr.get_nb_dso(), nb_elts);
174+
}
175+
163176
TEST(DSOTest, find_same) {
164177
DsoHdr dso_hdr;
165178
fill_mock_hdr(dso_hdr);

0 commit comments

Comments
 (0)