1 #include <linux/types.h>
10 static pid_t
event__synthesize_comm(pid_t pid
, int full
,
11 int (*process
)(event_t
*event
,
12 struct perf_session
*session
),
13 struct perf_session
*session
)
16 char filename
[PATH_MAX
];
21 struct dirent dirent
, *next
;
24 snprintf(filename
, sizeof(filename
), "/proc/%d/status", pid
);
26 fp
= fopen(filename
, "r");
30 * We raced with a task exiting - just return:
32 pr_debug("couldn't open %s\n", filename
);
36 memset(&ev
.comm
, 0, sizeof(ev
.comm
));
37 while (!ev
.comm
.comm
[0] || !ev
.comm
.pid
) {
38 if (fgets(bf
, sizeof(bf
), fp
) == NULL
)
41 if (memcmp(bf
, "Name:", 5) == 0) {
43 while (*name
&& isspace(*name
))
45 size
= strlen(name
) - 1;
46 memcpy(ev
.comm
.comm
, name
, size
++);
47 } else if (memcmp(bf
, "Tgid:", 5) == 0) {
49 while (*tgids
&& isspace(*tgids
))
51 tgid
= ev
.comm
.pid
= atoi(tgids
);
55 ev
.comm
.header
.type
= PERF_RECORD_COMM
;
56 size
= ALIGN(size
, sizeof(u64
));
57 ev
.comm
.header
.size
= sizeof(ev
.comm
) - (sizeof(ev
.comm
.comm
) - size
);
62 process(&ev
, session
);
66 snprintf(filename
, sizeof(filename
), "/proc/%d/task", pid
);
68 tasks
= opendir(filename
);
72 while (!readdir_r(tasks
, &dirent
, &next
) && next
) {
74 pid
= strtol(dirent
.d_name
, &end
, 10);
80 process(&ev
, session
);
89 pr_warning("couldn't get COMM and pgid, malformed %s\n", filename
);
93 static int event__synthesize_mmap_events(pid_t pid
, pid_t tgid
,
94 int (*process
)(event_t
*event
,
95 struct perf_session
*session
),
96 struct perf_session
*session
)
98 char filename
[PATH_MAX
];
101 snprintf(filename
, sizeof(filename
), "/proc/%d/maps", pid
);
103 fp
= fopen(filename
, "r");
106 * We raced with a task exiting - just return:
108 pr_debug("couldn't open %s\n", filename
);
113 char bf
[BUFSIZ
], *pbf
= bf
;
115 .header
= { .type
= PERF_RECORD_MMAP
},
119 if (fgets(bf
, sizeof(bf
), fp
) == NULL
)
122 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
123 n
= hex2u64(pbf
, &ev
.mmap
.start
);
127 n
= hex2u64(pbf
, &ev
.mmap
.len
);
131 if (*pbf
== 'x') { /* vm_exec */
132 char *execname
= strchr(bf
, '/');
135 if (execname
== NULL
)
136 execname
= strstr(bf
, "[vdso]");
138 if (execname
== NULL
)
141 size
= strlen(execname
);
142 execname
[size
- 1] = '\0'; /* Remove \n */
143 memcpy(ev
.mmap
.filename
, execname
, size
);
144 size
= ALIGN(size
, sizeof(u64
));
145 ev
.mmap
.len
-= ev
.mmap
.start
;
146 ev
.mmap
.header
.size
= (sizeof(ev
.mmap
) -
147 (sizeof(ev
.mmap
.filename
) - size
));
151 process(&ev
, session
);
159 int event__synthesize_thread(pid_t pid
,
160 int (*process
)(event_t
*event
,
161 struct perf_session
*session
),
162 struct perf_session
*session
)
164 pid_t tgid
= event__synthesize_comm(pid
, 1, process
, session
);
167 return event__synthesize_mmap_events(pid
, tgid
, process
, session
);
170 void event__synthesize_threads(int (*process
)(event_t
*event
,
171 struct perf_session
*session
),
172 struct perf_session
*session
)
175 struct dirent dirent
, *next
;
177 proc
= opendir("/proc");
179 while (!readdir_r(proc
, &dirent
, &next
) && next
) {
181 pid_t pid
= strtol(dirent
.d_name
, &end
, 10);
183 if (*end
) /* only interested in proper numerical dirents */
186 event__synthesize_thread(pid
, process
, session
);
192 static void thread__comm_adjust(struct thread
*self
)
194 char *comm
= self
->comm
;
196 if (!symbol_conf
.col_width_list_str
&& !symbol_conf
.field_sep
&&
197 (!symbol_conf
.comm_list
||
198 strlist__has_entry(symbol_conf
.comm_list
, comm
))) {
199 unsigned int slen
= strlen(comm
);
201 if (slen
> comms__col_width
) {
202 comms__col_width
= slen
;
203 threads__col_width
= slen
+ 6;
208 static int thread__set_comm_adjust(struct thread
*self
, const char *comm
)
210 int ret
= thread__set_comm(self
, comm
);
215 thread__comm_adjust(self
);
220 int event__process_comm(event_t
*self
, struct perf_session
*session
)
222 struct thread
*thread
= perf_session__findnew(session
, self
->comm
.pid
);
224 dump_printf(": %s:%d\n", self
->comm
.comm
, self
->comm
.pid
);
226 if (thread
== NULL
|| thread__set_comm_adjust(thread
, self
->comm
.comm
)) {
227 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
234 int event__process_lost(event_t
*self
, struct perf_session
*session
)
236 dump_printf(": id:%Ld: lost:%Ld\n", self
->lost
.id
, self
->lost
.lost
);
237 session
->events_stats
.lost
+= self
->lost
.lost
;
241 int event__process_mmap(event_t
*self
, struct perf_session
*session
)
243 struct thread
*thread
= perf_session__findnew(session
, self
->mmap
.pid
);
244 struct map
*map
= map__new(&self
->mmap
, MAP__FUNCTION
,
245 session
->cwd
, session
->cwdlen
);
247 dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n",
248 self
->mmap
.pid
, self
->mmap
.tid
,
249 (void *)(long)self
->mmap
.start
,
250 (void *)(long)self
->mmap
.len
,
251 (void *)(long)self
->mmap
.pgoff
,
252 self
->mmap
.filename
);
254 if (thread
== NULL
|| map
== NULL
)
255 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
257 thread__insert_map(thread
, map
);
262 int event__process_task(event_t
*self
, struct perf_session
*session
)
264 struct thread
*thread
= perf_session__findnew(session
, self
->fork
.pid
);
265 struct thread
*parent
= perf_session__findnew(session
, self
->fork
.ppid
);
267 dump_printf("(%d:%d):(%d:%d)\n", self
->fork
.pid
, self
->fork
.tid
,
268 self
->fork
.ppid
, self
->fork
.ptid
);
270 * A thread clone will have the same PID for both parent and child.
272 if (thread
== parent
)
275 if (self
->header
.type
== PERF_RECORD_EXIT
)
278 if (thread
== NULL
|| parent
== NULL
||
279 thread__fork(thread
, parent
) < 0) {
280 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
287 void thread__find_addr_location(struct thread
*self
,
288 struct perf_session
*session
, u8 cpumode
,
289 enum map_type type
, u64 addr
,
290 struct addr_location
*al
,
291 symbol_filter_t filter
)
293 struct map_groups
*mg
= &self
->mg
;
298 if (cpumode
== PERF_RECORD_MISC_KERNEL
) {
300 mg
= &session
->kmaps
;
301 } else if (cpumode
== PERF_RECORD_MISC_USER
)
310 al
->map
= map_groups__find(mg
, type
, al
->addr
);
311 if (al
->map
== NULL
) {
313 * If this is outside of all known maps, and is a negative
314 * address, try to look it up in the kernel dso, as it might be
315 * a vsyscall or vdso (which executes in user-mode).
317 * XXX This is nasty, we should have a symbol list in the
318 * "[vdso]" dso, but for now lets use the old trick of looking
319 * in the whole kernel symbol list.
321 if ((long long)al
->addr
< 0 && mg
!= &session
->kmaps
) {
322 mg
= &session
->kmaps
;
327 al
->addr
= al
->map
->map_ip(al
->map
, al
->addr
);
328 al
->sym
= map__find_symbol(al
->map
, session
, al
->addr
, filter
);
332 static void dso__calc_col_width(struct dso
*self
)
334 if (!symbol_conf
.col_width_list_str
&& !symbol_conf
.field_sep
&&
335 (!symbol_conf
.dso_list
||
336 strlist__has_entry(symbol_conf
.dso_list
, self
->name
))) {
337 unsigned int slen
= strlen(self
->name
);
338 if (slen
> dsos__col_width
)
339 dsos__col_width
= slen
;
342 self
->slen_calculated
= 1;
345 int event__preprocess_sample(const event_t
*self
, struct perf_session
*session
,
346 struct addr_location
*al
, symbol_filter_t filter
)
348 u8 cpumode
= self
->header
.misc
& PERF_RECORD_MISC_CPUMODE_MASK
;
349 struct thread
*thread
= perf_session__findnew(session
, self
->ip
.pid
);
354 if (symbol_conf
.comm_list
&&
355 !strlist__has_entry(symbol_conf
.comm_list
, thread
->comm
))
358 dump_printf(" ... thread: %s:%d\n", thread
->comm
, thread
->pid
);
360 thread__find_addr_location(thread
, session
, cpumode
, MAP__FUNCTION
,
361 self
->ip
.ip
, al
, filter
);
362 dump_printf(" ...... dso: %s\n",
363 al
->map
? al
->map
->dso
->long_name
:
364 al
->level
== 'H' ? "[hypervisor]" : "<not found>");
366 * We have to do this here as we may have a dso with no symbol hit that
367 * has a name longer than the ones with symbols sampled.
369 if (al
->map
&& !sort_dso
.elide
&& !al
->map
->dso
->slen_calculated
)
370 dso__calc_col_width(al
->map
->dso
);
372 if (symbol_conf
.dso_list
&&
373 (!al
->map
|| !al
->map
->dso
||
374 !(strlist__has_entry(symbol_conf
.dso_list
, al
->map
->dso
->short_name
) ||
375 (al
->map
->dso
->short_name
!= al
->map
->dso
->long_name
&&
376 strlist__has_entry(symbol_conf
.dso_list
, al
->map
->dso
->long_name
)))))
379 if (symbol_conf
.sym_list
&& al
->sym
&&
380 !strlist__has_entry(symbol_conf
.sym_list
, al
->sym
->name
))
383 al
->filtered
= false;
391 int event__parse_sample(event_t
*event
, u64 type
, struct sample_data
*data
)
393 u64
*array
= event
->sample
.array
;
395 if (type
& PERF_SAMPLE_IP
) {
396 data
->ip
= event
->ip
.ip
;
400 if (type
& PERF_SAMPLE_TID
) {
401 u32
*p
= (u32
*)array
;
407 if (type
& PERF_SAMPLE_TIME
) {
412 if (type
& PERF_SAMPLE_ADDR
) {
417 if (type
& PERF_SAMPLE_ID
) {
422 if (type
& PERF_SAMPLE_STREAM_ID
) {
423 data
->stream_id
= *array
;
427 if (type
& PERF_SAMPLE_CPU
) {
428 u32
*p
= (u32
*)array
;
433 if (type
& PERF_SAMPLE_PERIOD
) {
434 data
->period
= *array
;
438 if (type
& PERF_SAMPLE_READ
) {
439 pr_debug("PERF_SAMPLE_READ is unsuported for now\n");
443 if (type
& PERF_SAMPLE_CALLCHAIN
) {
444 data
->callchain
= (struct ip_callchain
*)array
;
445 array
+= 1 + data
->callchain
->nr
;
448 if (type
& PERF_SAMPLE_RAW
) {
449 u32
*p
= (u32
*)array
;