diff options
author | Adrian Hunter <adrian.hunter@intel.com> | 2015-04-30 10:37:31 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2015-05-05 17:13:00 -0400 |
commit | d20031bb63dd6dde35feb7845eaf17c620eef120 (patch) | |
tree | b36fd419c0ef1459ef4cfe1b000e1b4a3c65e6f2 | |
parent | 0ad21f6869222fd7fd7c63f02febea082e801fc2 (diff) |
perf tools: Add AUX area tracing Snapshot Mode
Add support for making snapshots of AUX area tracing data.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1430404667-10593-9-git-send-email-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r-- | tools/perf/perf.h | 3 | ||||
-rw-r--r-- | tools/perf/util/auxtrace.c | 85 | ||||
-rw-r--r-- | tools/perf/util/auxtrace.h | 41 |
3 files changed, 119 insertions, 10 deletions
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 5042093d5213..aa79fb8a16d4 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -55,6 +55,7 @@ struct record_opts { | |||
55 | bool sample_intr_regs; | 55 | bool sample_intr_regs; |
56 | bool running_time; | 56 | bool running_time; |
57 | bool full_auxtrace; | 57 | bool full_auxtrace; |
58 | bool auxtrace_snapshot_mode; | ||
58 | unsigned int freq; | 59 | unsigned int freq; |
59 | unsigned int mmap_pages; | 60 | unsigned int mmap_pages; |
60 | unsigned int auxtrace_mmap_pages; | 61 | unsigned int auxtrace_mmap_pages; |
@@ -62,6 +63,8 @@ struct record_opts { | |||
62 | u64 branch_stack; | 63 | u64 branch_stack; |
63 | u64 default_interval; | 64 | u64 default_interval; |
64 | u64 user_interval; | 65 | u64 user_interval; |
66 | size_t auxtrace_snapshot_size; | ||
67 | const char *auxtrace_snapshot_opts; | ||
65 | bool sample_transaction; | 68 | bool sample_transaction; |
66 | unsigned initial_delay; | 69 | unsigned initial_delay; |
67 | bool use_clockid; | 70 | bool use_clockid; |
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index 129371048fc1..df66966cfde7 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c | |||
@@ -504,6 +504,29 @@ void auxtrace_record__free(struct auxtrace_record *itr) | |||
504 | itr->free(itr); | 504 | itr->free(itr); |
505 | } | 505 | } |
506 | 506 | ||
507 | int auxtrace_record__snapshot_start(struct auxtrace_record *itr) | ||
508 | { | ||
509 | if (itr && itr->snapshot_start) | ||
510 | return itr->snapshot_start(itr); | ||
511 | return 0; | ||
512 | } | ||
513 | |||
514 | int auxtrace_record__snapshot_finish(struct auxtrace_record *itr) | ||
515 | { | ||
516 | if (itr && itr->snapshot_finish) | ||
517 | return itr->snapshot_finish(itr); | ||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | int auxtrace_record__find_snapshot(struct auxtrace_record *itr, int idx, | ||
522 | struct auxtrace_mmap *mm, | ||
523 | unsigned char *data, u64 *head, u64 *old) | ||
524 | { | ||
525 | if (itr && itr->find_snapshot) | ||
526 | return itr->find_snapshot(itr, idx, mm, data, head, old); | ||
527 | return 0; | ||
528 | } | ||
529 | |||
507 | int auxtrace_record__options(struct auxtrace_record *itr, | 530 | int auxtrace_record__options(struct auxtrace_record *itr, |
508 | struct perf_evlist *evlist, | 531 | struct perf_evlist *evlist, |
509 | struct record_opts *opts) | 532 | struct record_opts *opts) |
@@ -520,6 +543,19 @@ u64 auxtrace_record__reference(struct auxtrace_record *itr) | |||
520 | return 0; | 543 | return 0; |
521 | } | 544 | } |
522 | 545 | ||
546 | int auxtrace_parse_snapshot_options(struct auxtrace_record *itr, | ||
547 | struct record_opts *opts, const char *str) | ||
548 | { | ||
549 | if (!str) | ||
550 | return 0; | ||
551 | |||
552 | if (itr) | ||
553 | return itr->parse_snapshot_options(itr, opts, str); | ||
554 | |||
555 | pr_err("No AUX area tracing to snapshot\n"); | ||
556 | return -EINVAL; | ||
557 | } | ||
558 | |||
523 | struct auxtrace_record *__weak | 559 | struct auxtrace_record *__weak |
524 | auxtrace_record__init(struct perf_evlist *evlist __maybe_unused, int *err) | 560 | auxtrace_record__init(struct perf_evlist *evlist __maybe_unused, int *err) |
525 | { | 561 | { |
@@ -1077,16 +1113,26 @@ int perf_event__process_auxtrace_error(struct perf_tool *tool __maybe_unused, | |||
1077 | return 0; | 1113 | return 0; |
1078 | } | 1114 | } |
1079 | 1115 | ||
1080 | int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr, | 1116 | static int __auxtrace_mmap__read(struct auxtrace_mmap *mm, |
1081 | struct perf_tool *tool, process_auxtrace_t fn) | 1117 | struct auxtrace_record *itr, |
1118 | struct perf_tool *tool, process_auxtrace_t fn, | ||
1119 | bool snapshot, size_t snapshot_size) | ||
1082 | { | 1120 | { |
1083 | u64 head = auxtrace_mmap__read_head(mm); | 1121 | u64 head, old = mm->prev, offset, ref; |
1084 | u64 old = mm->prev, offset, ref; | ||
1085 | unsigned char *data = mm->base; | 1122 | unsigned char *data = mm->base; |
1086 | size_t size, head_off, old_off, len1, len2, padding; | 1123 | size_t size, head_off, old_off, len1, len2, padding; |
1087 | union perf_event ev; | 1124 | union perf_event ev; |
1088 | void *data1, *data2; | 1125 | void *data1, *data2; |
1089 | 1126 | ||
1127 | if (snapshot) { | ||
1128 | head = auxtrace_mmap__read_snapshot_head(mm); | ||
1129 | if (auxtrace_record__find_snapshot(itr, mm->idx, mm, data, | ||
1130 | &head, &old)) | ||
1131 | return -1; | ||
1132 | } else { | ||
1133 | head = auxtrace_mmap__read_head(mm); | ||
1134 | } | ||
1135 | |||
1090 | if (old == head) | 1136 | if (old == head) |
1091 | return 0; | 1137 | return 0; |
1092 | 1138 | ||
@@ -1106,6 +1152,9 @@ int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr, | |||
1106 | else | 1152 | else |
1107 | size = mm->len - (old_off - head_off); | 1153 | size = mm->len - (old_off - head_off); |
1108 | 1154 | ||
1155 | if (snapshot && size > snapshot_size) | ||
1156 | size = snapshot_size; | ||
1157 | |||
1109 | ref = auxtrace_record__reference(itr); | 1158 | ref = auxtrace_record__reference(itr); |
1110 | 1159 | ||
1111 | if (head > old || size <= head || mm->mask) { | 1160 | if (head > old || size <= head || mm->mask) { |
@@ -1153,18 +1202,34 @@ int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr, | |||
1153 | 1202 | ||
1154 | mm->prev = head; | 1203 | mm->prev = head; |
1155 | 1204 | ||
1156 | auxtrace_mmap__write_tail(mm, head); | 1205 | if (!snapshot) { |
1157 | if (itr->read_finish) { | 1206 | auxtrace_mmap__write_tail(mm, head); |
1158 | int err; | 1207 | if (itr->read_finish) { |
1208 | int err; | ||
1159 | 1209 | ||
1160 | err = itr->read_finish(itr, mm->idx); | 1210 | err = itr->read_finish(itr, mm->idx); |
1161 | if (err < 0) | 1211 | if (err < 0) |
1162 | return err; | 1212 | return err; |
1213 | } | ||
1163 | } | 1214 | } |
1164 | 1215 | ||
1165 | return 1; | 1216 | return 1; |
1166 | } | 1217 | } |
1167 | 1218 | ||
1219 | int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr, | ||
1220 | struct perf_tool *tool, process_auxtrace_t fn) | ||
1221 | { | ||
1222 | return __auxtrace_mmap__read(mm, itr, tool, fn, false, 0); | ||
1223 | } | ||
1224 | |||
1225 | int auxtrace_mmap__read_snapshot(struct auxtrace_mmap *mm, | ||
1226 | struct auxtrace_record *itr, | ||
1227 | struct perf_tool *tool, process_auxtrace_t fn, | ||
1228 | size_t snapshot_size) | ||
1229 | { | ||
1230 | return __auxtrace_mmap__read(mm, itr, tool, fn, true, snapshot_size); | ||
1231 | } | ||
1232 | |||
1168 | /** | 1233 | /** |
1169 | * struct auxtrace_cache - hash table to implement a cache | 1234 | * struct auxtrace_cache - hash table to implement a cache |
1170 | * @hashtable: the hashtable | 1235 | * @hashtable: the hashtable |
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index 8c6cbb123fe5..c2c677e62733 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h | |||
@@ -276,6 +276,10 @@ struct auxtrace_mmap_params { | |||
276 | * @info_priv_size: return the size of the private data in auxtrace_info_event | 276 | * @info_priv_size: return the size of the private data in auxtrace_info_event |
277 | * @info_fill: fill-in the private data in auxtrace_info_event | 277 | * @info_fill: fill-in the private data in auxtrace_info_event |
278 | * @free: free this auxtrace record structure | 278 | * @free: free this auxtrace record structure |
279 | * @snapshot_start: starting a snapshot | ||
280 | * @snapshot_finish: finishing a snapshot | ||
281 | * @find_snapshot: find data to snapshot within auxtrace mmap | ||
282 | * @parse_snapshot_options: parse snapshot options | ||
279 | * @reference: provide a 64-bit reference number for auxtrace_event | 283 | * @reference: provide a 64-bit reference number for auxtrace_event |
280 | * @read_finish: called after reading from an auxtrace mmap | 284 | * @read_finish: called after reading from an auxtrace mmap |
281 | */ | 285 | */ |
@@ -289,12 +293,36 @@ struct auxtrace_record { | |||
289 | struct auxtrace_info_event *auxtrace_info, | 293 | struct auxtrace_info_event *auxtrace_info, |
290 | size_t priv_size); | 294 | size_t priv_size); |
291 | void (*free)(struct auxtrace_record *itr); | 295 | void (*free)(struct auxtrace_record *itr); |
296 | int (*snapshot_start)(struct auxtrace_record *itr); | ||
297 | int (*snapshot_finish)(struct auxtrace_record *itr); | ||
298 | int (*find_snapshot)(struct auxtrace_record *itr, int idx, | ||
299 | struct auxtrace_mmap *mm, unsigned char *data, | ||
300 | u64 *head, u64 *old); | ||
301 | int (*parse_snapshot_options)(struct auxtrace_record *itr, | ||
302 | struct record_opts *opts, | ||
303 | const char *str); | ||
292 | u64 (*reference)(struct auxtrace_record *itr); | 304 | u64 (*reference)(struct auxtrace_record *itr); |
293 | int (*read_finish)(struct auxtrace_record *itr, int idx); | 305 | int (*read_finish)(struct auxtrace_record *itr, int idx); |
294 | }; | 306 | }; |
295 | 307 | ||
296 | #ifdef HAVE_AUXTRACE_SUPPORT | 308 | #ifdef HAVE_AUXTRACE_SUPPORT |
297 | 309 | ||
310 | /* | ||
311 | * In snapshot mode the mmapped page is read-only which makes using | ||
312 | * __sync_val_compare_and_swap() problematic. However, snapshot mode expects | ||
313 | * the buffer is not updated while the snapshot is made (e.g. Intel PT disables | ||
314 | * the event) so there is not a race anyway. | ||
315 | */ | ||
316 | static inline u64 auxtrace_mmap__read_snapshot_head(struct auxtrace_mmap *mm) | ||
317 | { | ||
318 | struct perf_event_mmap_page *pc = mm->userpg; | ||
319 | u64 head = ACCESS_ONCE(pc->aux_head); | ||
320 | |||
321 | /* Ensure all reads are done after we read the head */ | ||
322 | rmb(); | ||
323 | return head; | ||
324 | } | ||
325 | |||
298 | static inline u64 auxtrace_mmap__read_head(struct auxtrace_mmap *mm) | 326 | static inline u64 auxtrace_mmap__read_head(struct auxtrace_mmap *mm) |
299 | { | 327 | { |
300 | struct perf_event_mmap_page *pc = mm->userpg; | 328 | struct perf_event_mmap_page *pc = mm->userpg; |
@@ -346,6 +374,11 @@ typedef int (*process_auxtrace_t)(struct perf_tool *tool, | |||
346 | int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr, | 374 | int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr, |
347 | struct perf_tool *tool, process_auxtrace_t fn); | 375 | struct perf_tool *tool, process_auxtrace_t fn); |
348 | 376 | ||
377 | int auxtrace_mmap__read_snapshot(struct auxtrace_mmap *mm, | ||
378 | struct auxtrace_record *itr, | ||
379 | struct perf_tool *tool, process_auxtrace_t fn, | ||
380 | size_t snapshot_size); | ||
381 | |||
349 | int auxtrace_queues__init(struct auxtrace_queues *queues); | 382 | int auxtrace_queues__init(struct auxtrace_queues *queues); |
350 | int auxtrace_queues__add_event(struct auxtrace_queues *queues, | 383 | int auxtrace_queues__add_event(struct auxtrace_queues *queues, |
351 | struct perf_session *session, | 384 | struct perf_session *session, |
@@ -383,6 +416,9 @@ void *auxtrace_cache__lookup(struct auxtrace_cache *c, u32 key); | |||
383 | struct auxtrace_record *auxtrace_record__init(struct perf_evlist *evlist, | 416 | struct auxtrace_record *auxtrace_record__init(struct perf_evlist *evlist, |
384 | int *err); | 417 | int *err); |
385 | 418 | ||
419 | int auxtrace_parse_snapshot_options(struct auxtrace_record *itr, | ||
420 | struct record_opts *opts, | ||
421 | const char *str); | ||
386 | int auxtrace_record__options(struct auxtrace_record *itr, | 422 | int auxtrace_record__options(struct auxtrace_record *itr, |
387 | struct perf_evlist *evlist, | 423 | struct perf_evlist *evlist, |
388 | struct record_opts *opts); | 424 | struct record_opts *opts); |
@@ -392,6 +428,11 @@ int auxtrace_record__info_fill(struct auxtrace_record *itr, | |||
392 | struct auxtrace_info_event *auxtrace_info, | 428 | struct auxtrace_info_event *auxtrace_info, |
393 | size_t priv_size); | 429 | size_t priv_size); |
394 | void auxtrace_record__free(struct auxtrace_record *itr); | 430 | void auxtrace_record__free(struct auxtrace_record *itr); |
431 | int auxtrace_record__snapshot_start(struct auxtrace_record *itr); | ||
432 | int auxtrace_record__snapshot_finish(struct auxtrace_record *itr); | ||
433 | int auxtrace_record__find_snapshot(struct auxtrace_record *itr, int idx, | ||
434 | struct auxtrace_mmap *mm, | ||
435 | unsigned char *data, u64 *head, u64 *old); | ||
395 | u64 auxtrace_record__reference(struct auxtrace_record *itr); | 436 | u64 auxtrace_record__reference(struct auxtrace_record *itr); |
396 | 437 | ||
397 | int auxtrace_index__auxtrace_event(struct list_head *head, union perf_event *event, | 438 | int auxtrace_index__auxtrace_event(struct list_head *head, union perf_event *event, |