aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2010-12-02 07:25:28 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2010-12-04 20:08:40 -0500
commit9c90a61c7e4286aa5a38b314a2d8f5a1e70b5135 (patch)
treed05c5d84db78b2c98c27c3cc83f5da651a6f5707 /tools
parent640c03ce837fe8d4b56342aba376ea0da3960459 (diff)
perf tools: Ask for ID PERF_SAMPLE_ info on all PERF_RECORD_ events
So that we can use -T == --timestamp, asking for PERF_SAMPLE_TIME: $ perf record -aT $ perf report -D | grep PERF_RECORD_ <SNIP> 3 5951915425 0x47530 [0x58]: PERF_RECORD_SAMPLE(IP, 1): 16811/16811: 0xffffffff8138c1a2 period: 215979 cpu:3 3 5952026879 0x47588 [0x90]: PERF_RECORD_SAMPLE(IP, 1): 16811/16811: 0xffffffff810cb480 period: 215979 cpu:3 3 5952059959 0x47618 [0x38]: PERF_RECORD_FORK(6853:6853):(16811:16811) 3 5952138878 0x47650 [0x78]: PERF_RECORD_SAMPLE(IP, 1): 16811/16811: 0xffffffff811bac35 period: 431478 cpu:3 3 5952375068 0x476c8 [0x30]: PERF_RECORD_COMM: find:6853 3 5952395923 0x476f8 [0x50]: PERF_RECORD_MMAP 6853/6853: [0x400000(0x25000) @ 0]: /usr/bin/find 3 5952413756 0x47748 [0xa0]: PERF_RECORD_SAMPLE(IP, 1): 6853/6853: 0xffffffff810d080f period: 859332 cpu:3 3 5952419837 0x477e8 [0x58]: PERF_RECORD_MMAP 6853/6853: [0x3f44600000(0x21d000) @ 0]: /lib64/ld-2.5.so 3 5952437929 0x47840 [0x48]: PERF_RECORD_MMAP 6853/6853: [0x7fff7e1c9000(0x1000) @ 0x7fff7e1c9000]: [vdso] 3 5952570127 0x47888 [0x58]: PERF_RECORD_MMAP 6853/6853: [0x3f46200000(0x218000) @ 0]: /lib64/libselinux.so.1 3 5952623637 0x478e0 [0x58]: PERF_RECORD_MMAP 6853/6853: [0x3f44a00000(0x356000) @ 0]: /lib64/libc-2.5.so 3 5952675720 0x47938 [0x58]: PERF_RECORD_MMAP 6853/6853: [0x3f44e00000(0x204000) @ 0]: /lib64/libdl-2.5.so 3 5952710080 0x47990 [0x58]: PERF_RECORD_MMAP 6853/6853: [0x3f45a00000(0x246000) @ 0]: /lib64/libsepol.so.1 3 5952847802 0x479e8 [0x58]: PERF_RECORD_SAMPLE(IP, 1): 6853/6853: 0xffffffff813897f0 period: 1142536 cpu:3 <SNIP> First column is the cpu and the second the timestamp. That way we can investigate problems in the event stream. If the new perf binary is run on an older kernel, it will disable this feature automatically. Tested-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Acked-by: Ian Munsie <imunsie@au1.ibm.com> Acked-by: Thomas Gleixner <tglx@linutronix.de> Cc: Frédéric Weisbecker <fweisbec@gmail.com> Cc: Ian Munsie <imunsie@au1.ibm.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> Cc: Stephane Eranian <eranian@google.com> LKML-Reference: <1291318772-30880-5-git-send-email-acme@infradead.org> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Documentation/perf-record.txt5
-rw-r--r--tools/perf/builtin-record.c16
-rw-r--r--tools/perf/builtin-top.c14
-rw-r--r--tools/perf/util/event.c285
-rw-r--r--tools/perf/util/event.h7
-rw-r--r--tools/perf/util/header.c18
-rw-r--r--tools/perf/util/header.h1
-rw-r--r--tools/perf/util/session.c66
-rw-r--r--tools/perf/util/session.h3
9 files changed, 315 insertions, 100 deletions
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 0ad1bc75ab49..52462ae26455 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -108,6 +108,11 @@ OPTIONS
108--data:: 108--data::
109 Sample addresses. 109 Sample addresses.
110 110
111-T::
112--timestamp::
113 Sample timestamps. Use it with 'perf report -D' to see the timestamps,
114 for instance.
115
111-n:: 116-n::
112--no-samples:: 117--no-samples::
113 Don't sample. 118 Don't sample.
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index b34de9291c27..699dd2149c4b 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -49,6 +49,7 @@ static const char *output_name = "perf.data";
49static int group = 0; 49static int group = 0;
50static int realtime_prio = 0; 50static int realtime_prio = 0;
51static bool raw_samples = false; 51static bool raw_samples = false;
52static bool sample_id_all_avail = true;
52static bool system_wide = false; 53static bool system_wide = false;
53static pid_t target_pid = -1; 54static pid_t target_pid = -1;
54static pid_t target_tid = -1; 55static pid_t target_tid = -1;
@@ -61,6 +62,7 @@ static bool call_graph = false;
61static bool inherit_stat = false; 62static bool inherit_stat = false;
62static bool no_samples = false; 63static bool no_samples = false;
63static bool sample_address = false; 64static bool sample_address = false;
65static bool sample_time = false;
64static bool no_buildid = false; 66static bool no_buildid = false;
65static bool no_buildid_cache = false; 67static bool no_buildid_cache = false;
66 68
@@ -283,6 +285,9 @@ static void create_counter(int counter, int cpu)
283 if (system_wide) 285 if (system_wide)
284 attr->sample_type |= PERF_SAMPLE_CPU; 286 attr->sample_type |= PERF_SAMPLE_CPU;
285 287
288 if (sample_time)
289 attr->sample_type |= PERF_SAMPLE_TIME;
290
286 if (raw_samples) { 291 if (raw_samples) {
287 attr->sample_type |= PERF_SAMPLE_TIME; 292 attr->sample_type |= PERF_SAMPLE_TIME;
288 attr->sample_type |= PERF_SAMPLE_RAW; 293 attr->sample_type |= PERF_SAMPLE_RAW;
@@ -299,6 +304,8 @@ static void create_counter(int counter, int cpu)
299 attr->disabled = 1; 304 attr->disabled = 1;
300 attr->enable_on_exec = 1; 305 attr->enable_on_exec = 1;
301 } 306 }
307retry_sample_id:
308 attr->sample_id_all = sample_id_all_avail ? 1 : 0;
302 309
303 for (thread_index = 0; thread_index < thread_num; thread_index++) { 310 for (thread_index = 0; thread_index < thread_num; thread_index++) {
304try_again: 311try_again:
@@ -315,6 +322,12 @@ try_again:
315 else if (err == ENODEV && cpu_list) { 322 else if (err == ENODEV && cpu_list) {
316 die("No such device - did you specify" 323 die("No such device - did you specify"
317 " an out-of-range profile CPU?\n"); 324 " an out-of-range profile CPU?\n");
325 } else if (err == EINVAL && sample_id_all_avail) {
326 /*
327 * Old kernel, no attr->sample_id_type_all field
328 */
329 sample_id_all_avail = false;
330 goto retry_sample_id;
318 } 331 }
319 332
320 /* 333 /*
@@ -661,6 +674,8 @@ static int __cmd_record(int argc, const char **argv)
661 674
662 post_processing_offset = lseek(output, 0, SEEK_CUR); 675 post_processing_offset = lseek(output, 0, SEEK_CUR);
663 676
677 perf_session__set_sample_id_all(session, sample_id_all_avail);
678
664 if (pipe_output) { 679 if (pipe_output) {
665 err = event__synthesize_attrs(&session->header, 680 err = event__synthesize_attrs(&session->header,
666 process_synthesized_event, 681 process_synthesized_event,
@@ -841,6 +856,7 @@ const struct option record_options[] = {
841 "per thread counts"), 856 "per thread counts"),
842 OPT_BOOLEAN('d', "data", &sample_address, 857 OPT_BOOLEAN('d', "data", &sample_address,
843 "Sample addresses"), 858 "Sample addresses"),
859 OPT_BOOLEAN('T', "timestamp", &sample_time, "Sample timestamps"),
844 OPT_BOOLEAN('n', "no-samples", &no_samples, 860 OPT_BOOLEAN('n', "no-samples", &no_samples,
845 "don't sample"), 861 "don't sample"),
846 OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache, 862 OPT_BOOLEAN('N', "no-buildid-cache", &no_buildid_cache,
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 5aa29e1e855a..0515ce9d3d3e 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -977,12 +977,12 @@ static int symbol_filter(struct map *map, struct symbol *sym)
977} 977}
978 978
979static void event__process_sample(const event_t *self, 979static void event__process_sample(const event_t *self,
980 struct perf_session *session, int counter) 980 struct sample_data *sample,
981 struct perf_session *session, int counter)
981{ 982{
982 u64 ip = self->ip.ip; 983 u64 ip = self->ip.ip;
983 struct sym_entry *syme; 984 struct sym_entry *syme;
984 struct addr_location al; 985 struct addr_location al;
985 struct sample_data data;
986 struct machine *machine; 986 struct machine *machine;
987 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 987 u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
988 988
@@ -1025,9 +1025,7 @@ static void event__process_sample(const event_t *self,
1025 if (self->header.misc & PERF_RECORD_MISC_EXACT_IP) 1025 if (self->header.misc & PERF_RECORD_MISC_EXACT_IP)
1026 exact_samples++; 1026 exact_samples++;
1027 1027
1028 event__parse_sample(self, session->sample_type, &data); 1028 if (event__preprocess_sample(self, session, &al, sample,
1029
1030 if (event__preprocess_sample(self, session, &al, &data,
1031 symbol_filter) < 0 || 1029 symbol_filter) < 0 ||
1032 al.filtered) 1030 al.filtered)
1033 return; 1031 return;
@@ -1107,6 +1105,7 @@ static void perf_session__mmap_read_counter(struct perf_session *self,
1107 unsigned int head = mmap_read_head(md); 1105 unsigned int head = mmap_read_head(md);
1108 unsigned int old = md->prev; 1106 unsigned int old = md->prev;
1109 unsigned char *data = md->base + page_size; 1107 unsigned char *data = md->base + page_size;
1108 struct sample_data sample;
1110 int diff; 1109 int diff;
1111 1110
1112 /* 1111 /*
@@ -1154,10 +1153,11 @@ static void perf_session__mmap_read_counter(struct perf_session *self,
1154 event = &event_copy; 1153 event = &event_copy;
1155 } 1154 }
1156 1155
1156 event__parse_sample(event, self, &sample);
1157 if (event->header.type == PERF_RECORD_SAMPLE) 1157 if (event->header.type == PERF_RECORD_SAMPLE)
1158 event__process_sample(event, self, md->counter); 1158 event__process_sample(event, &sample, self, md->counter);
1159 else 1159 else
1160 event__process(event, NULL, self); 1160 event__process(event, &sample, self);
1161 old += size; 1161 old += size;
1162 } 1162 }
1163 1163
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 34510f441975..e4cdc1ebe0fb 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -33,11 +33,10 @@ static struct sample_data synth_sample = {
33 .period = 1, 33 .period = 1,
34}; 34};
35 35
36static pid_t event__synthesize_comm(pid_t pid, int full, 36static pid_t event__synthesize_comm(event_t *event, pid_t pid, int full,
37 event__handler_t process, 37 event__handler_t process,
38 struct perf_session *session) 38 struct perf_session *session)
39{ 39{
40 event_t ev;
41 char filename[PATH_MAX]; 40 char filename[PATH_MAX];
42 char bf[BUFSIZ]; 41 char bf[BUFSIZ];
43 FILE *fp; 42 FILE *fp;
@@ -58,34 +57,39 @@ out_race:
58 return 0; 57 return 0;
59 } 58 }
60 59
61 memset(&ev.comm, 0, sizeof(ev.comm)); 60 memset(&event->comm, 0, sizeof(event->comm));
62 while (!ev.comm.comm[0] || !ev.comm.pid) { 61
63 if (fgets(bf, sizeof(bf), fp) == NULL) 62 while (!event->comm.comm[0] || !event->comm.pid) {
64 goto out_failure; 63 if (fgets(bf, sizeof(bf), fp) == NULL) {
64 pr_warning("couldn't get COMM and pgid, malformed %s\n", filename);
65 goto out;
66 }
65 67
66 if (memcmp(bf, "Name:", 5) == 0) { 68 if (memcmp(bf, "Name:", 5) == 0) {
67 char *name = bf + 5; 69 char *name = bf + 5;
68 while (*name && isspace(*name)) 70 while (*name && isspace(*name))
69 ++name; 71 ++name;
70 size = strlen(name) - 1; 72 size = strlen(name) - 1;
71 memcpy(ev.comm.comm, name, size++); 73 memcpy(event->comm.comm, name, size++);
72 } else if (memcmp(bf, "Tgid:", 5) == 0) { 74 } else if (memcmp(bf, "Tgid:", 5) == 0) {
73 char *tgids = bf + 5; 75 char *tgids = bf + 5;
74 while (*tgids && isspace(*tgids)) 76 while (*tgids && isspace(*tgids))
75 ++tgids; 77 ++tgids;
76 tgid = ev.comm.pid = atoi(tgids); 78 tgid = event->comm.pid = atoi(tgids);
77 } 79 }
78 } 80 }
79 81
80 ev.comm.header.type = PERF_RECORD_COMM; 82 event->comm.header.type = PERF_RECORD_COMM;
81 size = ALIGN(size, sizeof(u64)); 83 size = ALIGN(size, sizeof(u64));
82 ev.comm.header.size = sizeof(ev.comm) - (sizeof(ev.comm.comm) - size); 84 memset(event->comm.comm + size, 0, session->id_hdr_size);
83 85 event->comm.header.size = (sizeof(event->comm) -
86 (sizeof(event->comm.comm) - size) +
87 session->id_hdr_size);
84 if (!full) { 88 if (!full) {
85 ev.comm.tid = pid; 89 event->comm.tid = pid;
86 90
87 process(&ev, &synth_sample, session); 91 process(event, &synth_sample, session);
88 goto out_fclose; 92 goto out;
89 } 93 }
90 94
91 snprintf(filename, sizeof(filename), "/proc/%d/task", pid); 95 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
@@ -100,22 +104,19 @@ out_race:
100 if (*end) 104 if (*end)
101 continue; 105 continue;
102 106
103 ev.comm.tid = pid; 107 event->comm.tid = pid;
104 108
105 process(&ev, &synth_sample, session); 109 process(event, &synth_sample, session);
106 } 110 }
107 closedir(tasks);
108 111
109out_fclose: 112 closedir(tasks);
113out:
110 fclose(fp); 114 fclose(fp);
111 return tgid;
112 115
113out_failure: 116 return tgid;
114 pr_warning("couldn't get COMM and pgid, malformed %s\n", filename);
115 return -1;
116} 117}
117 118
118static int event__synthesize_mmap_events(pid_t pid, pid_t tgid, 119static int event__synthesize_mmap_events(event_t *event, pid_t pid, pid_t tgid,
119 event__handler_t process, 120 event__handler_t process,
120 struct perf_session *session) 121 struct perf_session *session)
121{ 122{
@@ -133,29 +134,25 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
133 return -1; 134 return -1;
134 } 135 }
135 136
137 event->header.type = PERF_RECORD_MMAP;
138 /*
139 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
140 */
141 event->header.misc = PERF_RECORD_MISC_USER;
142
136 while (1) { 143 while (1) {
137 char bf[BUFSIZ], *pbf = bf; 144 char bf[BUFSIZ], *pbf = bf;
138 event_t ev = {
139 .header = {
140 .type = PERF_RECORD_MMAP,
141 /*
142 * Just like the kernel, see __perf_event_mmap
143 * in kernel/perf_event.c
144 */
145 .misc = PERF_RECORD_MISC_USER,
146 },
147 };
148 int n; 145 int n;
149 size_t size; 146 size_t size;
150 if (fgets(bf, sizeof(bf), fp) == NULL) 147 if (fgets(bf, sizeof(bf), fp) == NULL)
151 break; 148 break;
152 149
153 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 150 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
154 n = hex2u64(pbf, &ev.mmap.start); 151 n = hex2u64(pbf, &event->mmap.start);
155 if (n < 0) 152 if (n < 0)
156 continue; 153 continue;
157 pbf += n + 1; 154 pbf += n + 1;
158 n = hex2u64(pbf, &ev.mmap.len); 155 n = hex2u64(pbf, &event->mmap.len);
159 if (n < 0) 156 if (n < 0)
160 continue; 157 continue;
161 pbf += n + 3; 158 pbf += n + 3;
@@ -170,19 +167,21 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
170 continue; 167 continue;
171 168
172 pbf += 3; 169 pbf += 3;
173 n = hex2u64(pbf, &ev.mmap.pgoff); 170 n = hex2u64(pbf, &event->mmap.pgoff);
174 171
175 size = strlen(execname); 172 size = strlen(execname);
176 execname[size - 1] = '\0'; /* Remove \n */ 173 execname[size - 1] = '\0'; /* Remove \n */
177 memcpy(ev.mmap.filename, execname, size); 174 memcpy(event->mmap.filename, execname, size);
178 size = ALIGN(size, sizeof(u64)); 175 size = ALIGN(size, sizeof(u64));
179 ev.mmap.len -= ev.mmap.start; 176 event->mmap.len -= event->mmap.start;
180 ev.mmap.header.size = (sizeof(ev.mmap) - 177 event->mmap.header.size = (sizeof(event->mmap) -
181 (sizeof(ev.mmap.filename) - size)); 178 (sizeof(event->mmap.filename) - size));
182 ev.mmap.pid = tgid; 179 memset(event->mmap.filename + size, 0, session->id_hdr_size);
183 ev.mmap.tid = pid; 180 event->mmap.header.size += session->id_hdr_size;
184 181 event->mmap.pid = tgid;
185 process(&ev, &synth_sample, session); 182 event->mmap.tid = pid;
183
184 process(event, &synth_sample, session);
186 } 185 }
187 } 186 }
188 187
@@ -196,20 +195,27 @@ int event__synthesize_modules(event__handler_t process,
196{ 195{
197 struct rb_node *nd; 196 struct rb_node *nd;
198 struct map_groups *kmaps = &machine->kmaps; 197 struct map_groups *kmaps = &machine->kmaps;
199 u16 misc; 198 event_t *event = zalloc(sizeof(event->mmap) + session->id_hdr_size);
199
200 if (event == NULL) {
201 pr_debug("Not enough memory synthesizing mmap event "
202 "for kernel modules\n");
203 return -1;
204 }
205
206 event->header.type = PERF_RECORD_MMAP;
200 207
201 /* 208 /*
202 * kernel uses 0 for user space maps, see kernel/perf_event.c 209 * kernel uses 0 for user space maps, see kernel/perf_event.c
203 * __perf_event_mmap 210 * __perf_event_mmap
204 */ 211 */
205 if (machine__is_host(machine)) 212 if (machine__is_host(machine))
206 misc = PERF_RECORD_MISC_KERNEL; 213 event->header.misc = PERF_RECORD_MISC_KERNEL;
207 else 214 else
208 misc = PERF_RECORD_MISC_GUEST_KERNEL; 215 event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
209 216
210 for (nd = rb_first(&kmaps->maps[MAP__FUNCTION]); 217 for (nd = rb_first(&kmaps->maps[MAP__FUNCTION]);
211 nd; nd = rb_next(nd)) { 218 nd; nd = rb_next(nd)) {
212 event_t ev;
213 size_t size; 219 size_t size;
214 struct map *pos = rb_entry(nd, struct map, rb_node); 220 struct map *pos = rb_entry(nd, struct map, rb_node);
215 221
@@ -217,39 +223,78 @@ int event__synthesize_modules(event__handler_t process,
217 continue; 223 continue;
218 224
219 size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); 225 size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
220 memset(&ev, 0, sizeof(ev)); 226 event->mmap.header.type = PERF_RECORD_MMAP;
221 ev.mmap.header.misc = misc; 227 event->mmap.header.size = (sizeof(event->mmap) -
222 ev.mmap.header.type = PERF_RECORD_MMAP; 228 (sizeof(event->mmap.filename) - size));
223 ev.mmap.header.size = (sizeof(ev.mmap) - 229 memset(event->mmap.filename + size, 0, session->id_hdr_size);
224 (sizeof(ev.mmap.filename) - size)); 230 event->mmap.header.size += session->id_hdr_size;
225 ev.mmap.start = pos->start; 231 event->mmap.start = pos->start;
226 ev.mmap.len = pos->end - pos->start; 232 event->mmap.len = pos->end - pos->start;
227 ev.mmap.pid = machine->pid; 233 event->mmap.pid = machine->pid;
228 234
229 memcpy(ev.mmap.filename, pos->dso->long_name, 235 memcpy(event->mmap.filename, pos->dso->long_name,
230 pos->dso->long_name_len + 1); 236 pos->dso->long_name_len + 1);
231 process(&ev, &synth_sample, session); 237 process(event, &synth_sample, session);
232 } 238 }
233 239
240 free(event);
234 return 0; 241 return 0;
235} 242}
236 243
237int event__synthesize_thread(pid_t pid, event__handler_t process, 244static int __event__synthesize_thread(event_t *comm_event, event_t *mmap_event,
238 struct perf_session *session) 245 pid_t pid, event__handler_t process,
246 struct perf_session *session)
239{ 247{
240 pid_t tgid = event__synthesize_comm(pid, 1, process, session); 248 pid_t tgid = event__synthesize_comm(comm_event, pid, 1, process,
249 session);
241 if (tgid == -1) 250 if (tgid == -1)
242 return -1; 251 return -1;
243 return event__synthesize_mmap_events(pid, tgid, process, session); 252 return event__synthesize_mmap_events(mmap_event, pid, tgid,
253 process, session);
244} 254}
245 255
246void event__synthesize_threads(event__handler_t process, 256int event__synthesize_thread(pid_t pid, event__handler_t process,
247 struct perf_session *session) 257 struct perf_session *session)
258{
259 event_t *comm_event, *mmap_event;
260 int err = -1;
261
262 comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size);
263 if (comm_event == NULL)
264 goto out;
265
266 mmap_event = malloc(sizeof(mmap_event->mmap) + session->id_hdr_size);
267 if (mmap_event == NULL)
268 goto out_free_comm;
269
270 err = __event__synthesize_thread(comm_event, mmap_event, pid,
271 process, session);
272 free(mmap_event);
273out_free_comm:
274 free(comm_event);
275out:
276 return err;
277}
278
279int event__synthesize_threads(event__handler_t process,
280 struct perf_session *session)
248{ 281{
249 DIR *proc; 282 DIR *proc;
250 struct dirent dirent, *next; 283 struct dirent dirent, *next;
284 event_t *comm_event, *mmap_event;
285 int err = -1;
286
287 comm_event = malloc(sizeof(comm_event->comm) + session->id_hdr_size);
288 if (comm_event == NULL)
289 goto out;
290
291 mmap_event = malloc(sizeof(mmap_event->mmap) + session->id_hdr_size);
292 if (mmap_event == NULL)
293 goto out_free_comm;
251 294
252 proc = opendir("/proc"); 295 proc = opendir("/proc");
296 if (proc == NULL)
297 goto out_free_mmap;
253 298
254 while (!readdir_r(proc, &dirent, &next) && next) { 299 while (!readdir_r(proc, &dirent, &next) && next) {
255 char *end; 300 char *end;
@@ -258,10 +303,18 @@ void event__synthesize_threads(event__handler_t process,
258 if (*end) /* only interested in proper numerical dirents */ 303 if (*end) /* only interested in proper numerical dirents */
259 continue; 304 continue;
260 305
261 event__synthesize_thread(pid, process, session); 306 __event__synthesize_thread(comm_event, mmap_event, pid,
307 process, session);
262 } 308 }
263 309
264 closedir(proc); 310 closedir(proc);
311 err = 0;
312out_free_mmap:
313 free(mmap_event);
314out_free_comm:
315 free(comm_event);
316out:
317 return err;
265} 318}
266 319
267struct process_symbol_args { 320struct process_symbol_args {
@@ -295,18 +348,20 @@ int event__synthesize_kernel_mmap(event__handler_t process,
295 char path[PATH_MAX]; 348 char path[PATH_MAX];
296 char name_buff[PATH_MAX]; 349 char name_buff[PATH_MAX];
297 struct map *map; 350 struct map *map;
298 351 int err;
299 event_t ev = {
300 .header = {
301 .type = PERF_RECORD_MMAP,
302 },
303 };
304 /* 352 /*
305 * We should get this from /sys/kernel/sections/.text, but till that is 353 * We should get this from /sys/kernel/sections/.text, but till that is
306 * available use this, and after it is use this as a fallback for older 354 * available use this, and after it is use this as a fallback for older
307 * kernels. 355 * kernels.
308 */ 356 */
309 struct process_symbol_args args = { .name = symbol_name, }; 357 struct process_symbol_args args = { .name = symbol_name, };
358 event_t *event = zalloc(sizeof(event->mmap) + session->id_hdr_size);
359
360 if (event == NULL) {
361 pr_debug("Not enough memory synthesizing mmap event "
362 "for kernel modules\n");
363 return -1;
364 }
310 365
311 mmap_name = machine__mmap_name(machine, name_buff, sizeof(name_buff)); 366 mmap_name = machine__mmap_name(machine, name_buff, sizeof(name_buff));
312 if (machine__is_host(machine)) { 367 if (machine__is_host(machine)) {
@@ -314,10 +369,10 @@ int event__synthesize_kernel_mmap(event__handler_t process,
314 * kernel uses PERF_RECORD_MISC_USER for user space maps, 369 * kernel uses PERF_RECORD_MISC_USER for user space maps,
315 * see kernel/perf_event.c __perf_event_mmap 370 * see kernel/perf_event.c __perf_event_mmap
316 */ 371 */
317 ev.header.misc = PERF_RECORD_MISC_KERNEL; 372 event->header.misc = PERF_RECORD_MISC_KERNEL;
318 filename = "/proc/kallsyms"; 373 filename = "/proc/kallsyms";
319 } else { 374 } else {
320 ev.header.misc = PERF_RECORD_MISC_GUEST_KERNEL; 375 event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
321 if (machine__is_default_guest(machine)) 376 if (machine__is_default_guest(machine))
322 filename = (char *) symbol_conf.default_guest_kallsyms; 377 filename = (char *) symbol_conf.default_guest_kallsyms;
323 else { 378 else {
@@ -330,17 +385,21 @@ int event__synthesize_kernel_mmap(event__handler_t process,
330 return -ENOENT; 385 return -ENOENT;
331 386
332 map = machine->vmlinux_maps[MAP__FUNCTION]; 387 map = machine->vmlinux_maps[MAP__FUNCTION];
333 size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename), 388 size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
334 "%s%s", mmap_name, symbol_name) + 1; 389 "%s%s", mmap_name, symbol_name) + 1;
335 size = ALIGN(size, sizeof(u64)); 390 size = ALIGN(size, sizeof(u64));
336 ev.mmap.header.size = (sizeof(ev.mmap) - 391 event->mmap.header.type = PERF_RECORD_MMAP;
337 (sizeof(ev.mmap.filename) - size)); 392 event->mmap.header.size = (sizeof(event->mmap) -
338 ev.mmap.pgoff = args.start; 393 (sizeof(event->mmap.filename) - size) + session->id_hdr_size);
339 ev.mmap.start = map->start; 394 event->mmap.pgoff = args.start;
340 ev.mmap.len = map->end - ev.mmap.start; 395 event->mmap.start = map->start;
341 ev.mmap.pid = machine->pid; 396 event->mmap.len = map->end - event->mmap.start;
342 397 event->mmap.pid = machine->pid;
343 return process(&ev, &synth_sample, session); 398
399 err = process(event, &synth_sample, session);
400 free(event);
401
402 return err;
344} 403}
345 404
346static void thread__comm_adjust(struct thread *self, struct hists *hists) 405static void thread__comm_adjust(struct thread *self, struct hists *hists)
@@ -756,9 +815,65 @@ out_filtered:
756 return 0; 815 return 0;
757} 816}
758 817
759int event__parse_sample(const event_t *event, u64 type, struct sample_data *data) 818static int event__parse_id_sample(const event_t *event,
819 struct perf_session *session,
820 struct sample_data *sample)
760{ 821{
761 const u64 *array = event->sample.array; 822 const u64 *array;
823 u64 type;
824
825 sample->cpu = sample->pid = sample->tid = -1;
826 sample->stream_id = sample->id = sample->time = -1ULL;
827
828 if (!session->sample_id_all)
829 return 0;
830
831 array = event->sample.array;
832 array += ((event->header.size -
833 sizeof(event->header)) / sizeof(u64)) - 1;
834 type = session->sample_type;
835
836 if (type & PERF_SAMPLE_CPU) {
837 u32 *p = (u32 *)array;
838 sample->cpu = *p;
839 array--;
840 }
841
842 if (type & PERF_SAMPLE_STREAM_ID) {
843 sample->stream_id = *array;
844 array--;
845 }
846
847 if (type & PERF_SAMPLE_ID) {
848 sample->id = *array;
849 array--;
850 }
851
852 if (type & PERF_SAMPLE_TIME) {
853 sample->time = *array;
854 array--;
855 }
856
857 if (type & PERF_SAMPLE_TID) {
858 u32 *p = (u32 *)array;
859 sample->pid = p[0];
860 sample->tid = p[1];
861 }
862
863 return 0;
864}
865
866int event__parse_sample(const event_t *event, struct perf_session *session,
867 struct sample_data *data)
868{
869 const u64 *array;
870 u64 type;
871
872 if (event->header.type != PERF_RECORD_SAMPLE)
873 return event__parse_id_sample(event, session, data);
874
875 array = event->sample.array;
876 type = session->sample_type;
762 877
763 if (type & PERF_SAMPLE_IP) { 878 if (type & PERF_SAMPLE_IP) {
764 data->ip = event->ip.ip; 879 data->ip = event->ip.ip;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 08c400b83d57..a95ab18575ce 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -142,8 +142,8 @@ typedef int (*event__handler_t)(event_t *event, struct sample_data *sample,
142 142
143int event__synthesize_thread(pid_t pid, event__handler_t process, 143int event__synthesize_thread(pid_t pid, event__handler_t process,
144 struct perf_session *session); 144 struct perf_session *session);
145void event__synthesize_threads(event__handler_t process, 145int event__synthesize_threads(event__handler_t process,
146 struct perf_session *session); 146 struct perf_session *session);
147int event__synthesize_kernel_mmap(event__handler_t process, 147int event__synthesize_kernel_mmap(event__handler_t process,
148 struct perf_session *session, 148 struct perf_session *session,
149 struct machine *machine, 149 struct machine *machine,
@@ -168,7 +168,8 @@ struct addr_location;
168int event__preprocess_sample(const event_t *self, struct perf_session *session, 168int event__preprocess_sample(const event_t *self, struct perf_session *session,
169 struct addr_location *al, struct sample_data *data, 169 struct addr_location *al, struct sample_data *data,
170 symbol_filter_t filter); 170 symbol_filter_t filter);
171int event__parse_sample(const event_t *event, u64 type, struct sample_data *data); 171int event__parse_sample(const event_t *event, struct perf_session *session,
172 struct sample_data *sample);
172 173
173extern const char *event__name[]; 174extern const char *event__name[];
174 175
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index fe652f3b0aa7..073f0e1c7123 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -946,6 +946,24 @@ u64 perf_header__sample_type(struct perf_header *header)
946 return type; 946 return type;
947} 947}
948 948
949bool perf_header__sample_id_all(const struct perf_header *header)
950{
951 bool value = false, first = true;
952 int i;
953
954 for (i = 0; i < header->attrs; i++) {
955 struct perf_header_attr *attr = header->attr[i];
956
957 if (first) {
958 value = attr->attr.sample_id_all;
959 first = false;
960 } else if (value != attr->attr.sample_id_all)
961 die("non matching sample_id_all");
962 }
963
964 return value;
965}
966
949struct perf_event_attr * 967struct perf_event_attr *
950perf_header__find_attr(u64 id, struct perf_header *header) 968perf_header__find_attr(u64 id, struct perf_header *header)
951{ 969{
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index ed550bffd655..6335965e1f93 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -81,6 +81,7 @@ void perf_header_attr__delete(struct perf_header_attr *self);
81int perf_header_attr__add_id(struct perf_header_attr *self, u64 id); 81int perf_header_attr__add_id(struct perf_header_attr *self, u64 id);
82 82
83u64 perf_header__sample_type(struct perf_header *header); 83u64 perf_header__sample_type(struct perf_header *header);
84bool perf_header__sample_id_all(const struct perf_header *header);
84struct perf_event_attr * 85struct perf_event_attr *
85perf_header__find_attr(u64 id, struct perf_header *header); 86perf_header__find_attr(u64 id, struct perf_header *header);
86void perf_header__set_feat(struct perf_header *self, int feat); 87void perf_header__set_feat(struct perf_header *self, int feat);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 08ec018966a8..5c756609104e 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -65,9 +65,37 @@ out_close:
65 return -1; 65 return -1;
66} 66}
67 67
68void perf_session__update_sample_type(struct perf_session *self) 68static void perf_session__id_header_size(struct perf_session *session)
69{ 69{
70 self->sample_type = perf_header__sample_type(&self->header); 70 struct sample_data *data;
71 u64 sample_type = session->sample_type;
72 u16 size = 0;
73
74 if (!session->sample_id_all)
75 goto out;
76
77 if (sample_type & PERF_SAMPLE_TID)
78 size += sizeof(data->tid) * 2;
79
80 if (sample_type & PERF_SAMPLE_TIME)
81 size += sizeof(data->time);
82
83 if (sample_type & PERF_SAMPLE_ID)
84 size += sizeof(data->id);
85
86 if (sample_type & PERF_SAMPLE_STREAM_ID)
87 size += sizeof(data->stream_id);
88
89 if (sample_type & PERF_SAMPLE_CPU)
90 size += sizeof(data->cpu) * 2;
91out:
92 session->id_hdr_size = size;
93}
94
95void perf_session__set_sample_id_all(struct perf_session *session, bool value)
96{
97 session->sample_id_all = value;
98 perf_session__id_header_size(session);
71} 99}
72 100
73void perf_session__set_sample_type(struct perf_session *session, u64 type) 101void perf_session__set_sample_type(struct perf_session *session, u64 type)
@@ -75,6 +103,13 @@ void perf_session__set_sample_type(struct perf_session *session, u64 type)
75 session->sample_type = type; 103 session->sample_type = type;
76} 104}
77 105
106void perf_session__update_sample_type(struct perf_session *self)
107{
108 self->sample_type = perf_header__sample_type(&self->header);
109 self->sample_id_all = perf_header__sample_id_all(&self->header);
110 perf_session__id_header_size(self);
111}
112
78int perf_session__create_kernel_maps(struct perf_session *self) 113int perf_session__create_kernel_maps(struct perf_session *self)
79{ 114{
80 int ret = machine__create_kernel_maps(&self->host_machine); 115 int ret = machine__create_kernel_maps(&self->host_machine);
@@ -443,7 +478,7 @@ static void flush_sample_queue(struct perf_session *s,
443 if (iter->timestamp > limit) 478 if (iter->timestamp > limit)
444 break; 479 break;
445 480
446 event__parse_sample(iter->event, s->sample_type, &sample); 481 event__parse_sample(iter->event, s, &sample);
447 ops->sample(iter->event, &sample, s); 482 ops->sample(iter->event, &sample, s);
448 483
449 os->last_flush = iter->timestamp; 484 os->last_flush = iter->timestamp;
@@ -618,6 +653,23 @@ static void callchain__dump(struct sample_data *sample)
618 printf("..... %2d: %016Lx\n", i, sample->callchain->ips[i]); 653 printf("..... %2d: %016Lx\n", i, sample->callchain->ips[i]);
619} 654}
620 655
656static void perf_session__print_tstamp(struct perf_session *session,
657 event_t *event,
658 struct sample_data *sample)
659{
660 if (event->header.type != PERF_RECORD_SAMPLE &&
661 !session->sample_id_all) {
662 fputs("-1 -1 ", stdout);
663 return;
664 }
665
666 if ((session->sample_type & PERF_SAMPLE_CPU))
667 printf("%u ", sample->cpu);
668
669 if (session->sample_type & PERF_SAMPLE_TIME)
670 printf("%Lu ", sample->time);
671}
672
621static int perf_session__process_event(struct perf_session *self, 673static int perf_session__process_event(struct perf_session *self,
622 event_t *event, 674 event_t *event,
623 struct perf_event_ops *ops, 675 struct perf_event_ops *ops,
@@ -630,8 +682,12 @@ static int perf_session__process_event(struct perf_session *self,
630 if (self->header.needs_swap && event__swap_ops[event->header.type]) 682 if (self->header.needs_swap && event__swap_ops[event->header.type])
631 event__swap_ops[event->header.type](event); 683 event__swap_ops[event->header.type](event);
632 684
633 if (event->header.type == PERF_RECORD_SAMPLE) 685 if (event->header.type >= PERF_RECORD_MMAP &&
634 event__parse_sample(event, self->sample_type, &sample); 686 event->header.type <= PERF_RECORD_SAMPLE) {
687 event__parse_sample(event, self, &sample);
688 if (dump_trace)
689 perf_session__print_tstamp(self, event, &sample);
690 }
635 691
636 if (event->header.type < PERF_RECORD_HEADER_MAX) { 692 if (event->header.type < PERF_RECORD_HEADER_MAX) {
637 dump_printf("%#Lx [%#x]: PERF_RECORD_%s", 693 dump_printf("%#Lx [%#x]: PERF_RECORD_%s",
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 4578f86a6209..ac36f99f14af 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -46,6 +46,8 @@ struct perf_session {
46 int fd; 46 int fd;
47 bool fd_pipe; 47 bool fd_pipe;
48 bool repipe; 48 bool repipe;
49 bool sample_id_all;
50 u16 id_hdr_size;
49 int cwdlen; 51 int cwdlen;
50 char *cwd; 52 char *cwd;
51 struct ordered_samples ordered_samples; 53 struct ordered_samples ordered_samples;
@@ -106,6 +108,7 @@ int perf_session__create_kernel_maps(struct perf_session *self);
106 108
107int do_read(int fd, void *buf, size_t size); 109int do_read(int fd, void *buf, size_t size);
108void perf_session__update_sample_type(struct perf_session *self); 110void perf_session__update_sample_type(struct perf_session *self);
111void perf_session__set_sample_id_all(struct perf_session *session, bool value);
109void perf_session__set_sample_type(struct perf_session *session, u64 type); 112void perf_session__set_sample_type(struct perf_session *session, u64 type);
110void perf_session__remove_thread(struct perf_session *self, struct thread *th); 113void perf_session__remove_thread(struct perf_session *self, struct thread *th);
111 114