diff options
| author | Igor Nabirushkin <inabirushkin@nvidia.com> | 2018-04-17 09:20:12 -0400 |
|---|---|---|
| committer | mobile promotions <svcmobile_promotions@nvidia.com> | 2018-04-18 11:43:24 -0400 |
| commit | c3c4e00a8ddfcb888f640fc2aec3b69f53eae515 (patch) | |
| tree | 98907deec98a81a43c4fbc1cfc81becca7a992b8 | |
| parent | e224e866f8b4b814b19ec854b49510507f0a06ae (diff) | |
misc: tegra-profiler: sample multiple processes
- Sample multiple processes. Add a few new modes.
- Fix possible crash in d_path() during multiple execs.
Bug 2104957
Bug 2100416
Change-Id: Iab1568de9365e1c719b45c65f490bbd212995b69
Signed-off-by: Igor Nabirushkin <inabirushkin@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1696670
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Dmitry Antipov <dantipov@nvidia.com>
Reviewed-by: Sachin Nikam <snikam@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
| -rw-r--r-- | drivers/misc/tegra-profiler/arm_pmu.h | 2 | ||||
| -rw-r--r-- | drivers/misc/tegra-profiler/comm.c | 10 | ||||
| -rw-r--r-- | drivers/misc/tegra-profiler/comm.h | 6 | ||||
| -rw-r--r-- | drivers/misc/tegra-profiler/hrt.c | 117 | ||||
| -rw-r--r-- | drivers/misc/tegra-profiler/hrt.h | 11 | ||||
| -rw-r--r-- | drivers/misc/tegra-profiler/main.c | 101 | ||||
| -rw-r--r-- | drivers/misc/tegra-profiler/mmap.c | 250 | ||||
| -rw-r--r-- | drivers/misc/tegra-profiler/mmap.h | 10 | ||||
| -rw-r--r-- | drivers/misc/tegra-profiler/quadd.h | 47 | ||||
| -rw-r--r-- | drivers/misc/tegra-profiler/quadd_proc.c | 2 | ||||
| -rw-r--r-- | drivers/misc/tegra-profiler/version.h | 2 | ||||
| -rw-r--r-- | include/linux/tegra_profiler.h | 68 |
12 files changed, 382 insertions, 244 deletions
diff --git a/drivers/misc/tegra-profiler/arm_pmu.h b/drivers/misc/tegra-profiler/arm_pmu.h index 7e6558414..14aa684cb 100644 --- a/drivers/misc/tegra-profiler/arm_pmu.h +++ b/drivers/misc/tegra-profiler/arm_pmu.h | |||
| @@ -34,7 +34,7 @@ struct quadd_pmu_event_info { | |||
| 34 | struct quadd_arch_info { | 34 | struct quadd_arch_info { |
| 35 | int type; | 35 | int type; |
| 36 | 36 | ||
| 37 | int pmuver; | 37 | unsigned int pmuver; |
| 38 | unsigned pmuver_is_set:1; | 38 | unsigned pmuver_is_set:1; |
| 39 | 39 | ||
| 40 | char name[QUADD_ARCH_NAME_MAX]; | 40 | char name[QUADD_ARCH_NAME_MAX]; |
diff --git a/drivers/misc/tegra-profiler/comm.c b/drivers/misc/tegra-profiler/comm.c index 0f9cf2374..fb78e2542 100644 --- a/drivers/misc/tegra-profiler/comm.c +++ b/drivers/misc/tegra-profiler/comm.c | |||
| @@ -46,6 +46,7 @@ struct quadd_ring_buffer { | |||
| 46 | }; | 46 | }; |
| 47 | 47 | ||
| 48 | struct quadd_comm_ctx { | 48 | struct quadd_comm_ctx { |
| 49 | struct quadd_ctx *ctx; | ||
| 49 | struct quadd_comm_control_interface *control; | 50 | struct quadd_comm_control_interface *control; |
| 50 | 51 | ||
| 51 | atomic_t active; | 52 | atomic_t active; |
| @@ -387,7 +388,7 @@ ready_to_profile(void) | |||
| 387 | if (!comm_ctx.params_ok) | 388 | if (!comm_ctx.params_ok) |
| 388 | return 0; | 389 | return 0; |
| 389 | 390 | ||
| 390 | if (quadd_mode_is_sampling()) { | 391 | if (quadd_mode_is_sampling(comm_ctx.ctx)) { |
| 391 | for_each_possible_cpu(cpuid) { | 392 | for_each_possible_cpu(cpuid) { |
| 392 | is_cpu_present = | 393 | is_cpu_present = |
| 393 | comm_ctx.control->is_cpu_present(cpuid); | 394 | comm_ctx.control->is_cpu_present(cpuid); |
| @@ -457,7 +458,7 @@ device_ioctl(struct file *file, | |||
| 457 | } | 458 | } |
| 458 | 459 | ||
| 459 | if (!comm_ctx.params_ok || | 460 | if (!comm_ctx.params_ok || |
| 460 | !quadd_mode_is_sampling()) { | 461 | !quadd_mode_is_sampling(comm_ctx.ctx)) { |
| 461 | pr_err("error: incorrect setup ioctl\n"); | 462 | pr_err("error: incorrect setup ioctl\n"); |
| 462 | err = -EPERM; | 463 | err = -EPERM; |
| 463 | goto error_out; | 464 | goto error_out; |
| @@ -932,10 +933,13 @@ static int comm_init(void) | |||
| 932 | } | 933 | } |
| 933 | 934 | ||
| 934 | struct quadd_comm_data_interface * | 935 | struct quadd_comm_data_interface * |
| 935 | quadd_comm_events_init(struct quadd_comm_control_interface *control) | 936 | quadd_comm_events_init(struct quadd_ctx *ctx, |
| 937 | struct quadd_comm_control_interface *control) | ||
| 936 | { | 938 | { |
| 937 | int err; | 939 | int err; |
| 938 | 940 | ||
| 941 | comm_ctx.ctx = ctx; | ||
| 942 | |||
| 939 | err = comm_init(); | 943 | err = comm_init(); |
| 940 | if (err < 0) | 944 | if (err < 0) |
| 941 | return ERR_PTR(err); | 945 | return ERR_PTR(err); |
diff --git a/drivers/misc/tegra-profiler/comm.h b/drivers/misc/tegra-profiler/comm.h index eca48a9b6..b3755a82d 100644 --- a/drivers/misc/tegra-profiler/comm.h +++ b/drivers/misc/tegra-profiler/comm.h | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * drivers/misc/tegra-profiler/comm.h | 2 | * drivers/misc/tegra-profiler/comm.h |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2013-2017, NVIDIA CORPORATION. All rights reserved. | 4 | * Copyright (c) 2013-2018, NVIDIA CORPORATION. All rights reserved. |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
| 7 | * under the terms and conditions of the GNU General Public License, | 7 | * under the terms and conditions of the GNU General Public License, |
| @@ -19,6 +19,7 @@ | |||
| 19 | 19 | ||
| 20 | #include <linux/types.h> | 20 | #include <linux/types.h> |
| 21 | 21 | ||
| 22 | struct quadd_ctx; | ||
| 22 | struct quadd_record_data; | 23 | struct quadd_record_data; |
| 23 | struct quadd_comm_cap; | 24 | struct quadd_comm_cap; |
| 24 | struct quadd_module_state; | 25 | struct quadd_module_state; |
| @@ -85,7 +86,8 @@ struct quadd_comm_data_interface { | |||
| 85 | }; | 86 | }; |
| 86 | 87 | ||
| 87 | struct quadd_comm_data_interface * | 88 | struct quadd_comm_data_interface * |
| 88 | quadd_comm_events_init(struct quadd_comm_control_interface *control); | 89 | quadd_comm_events_init(struct quadd_ctx *ctx, |
| 90 | struct quadd_comm_control_interface *control); | ||
| 89 | void quadd_comm_events_exit(void); | 91 | void quadd_comm_events_exit(void); |
| 90 | 92 | ||
| 91 | #endif /* __QUADD_COMM_H__ */ | 93 | #endif /* __QUADD_COMM_H__ */ |
diff --git a/drivers/misc/tegra-profiler/hrt.c b/drivers/misc/tegra-profiler/hrt.c index ec45b0f4b..126c7f579 100644 --- a/drivers/misc/tegra-profiler/hrt.c +++ b/drivers/misc/tegra-profiler/hrt.c | |||
| @@ -210,10 +210,18 @@ static void put_header(int cpuid) | |||
| 210 | 210 | ||
| 211 | hdr->reserved |= QUADD_HDR_HAS_CPUID; | 211 | hdr->reserved |= QUADD_HDR_HAS_CPUID; |
| 212 | 212 | ||
| 213 | if (quadd_mode_is_trace_all()) | 213 | if (quadd_mode_is_sampling(ctx)) |
| 214 | hdr->reserved |= QUADD_HDR_MODE_TRACE_ALL; | ||
| 215 | if (quadd_mode_is_sampling()) | ||
| 216 | hdr->reserved |= QUADD_HDR_MODE_SAMPLING; | 214 | hdr->reserved |= QUADD_HDR_MODE_SAMPLING; |
| 215 | if (quadd_mode_is_tracing(ctx)) | ||
| 216 | hdr->reserved |= QUADD_HDR_MODE_TRACING; | ||
| 217 | if (quadd_mode_is_sample_all(ctx)) | ||
| 218 | hdr->reserved |= QUADD_HDR_MODE_SAMPLE_ALL; | ||
| 219 | if (quadd_mode_is_trace_all(ctx)) | ||
| 220 | hdr->reserved |= QUADD_HDR_MODE_TRACE_ALL; | ||
| 221 | if (quadd_mode_is_sample_tree(ctx)) | ||
| 222 | hdr->reserved |= QUADD_HDR_MODE_SAMPLE_TREE; | ||
| 223 | if (quadd_mode_is_trace_tree(ctx)) | ||
| 224 | hdr->reserved |= QUADD_HDR_MODE_TRACE_TREE; | ||
| 217 | 225 | ||
| 218 | if (pmu) | 226 | if (pmu) |
| 219 | nr_events += pmu->get_current_events(cpuid, events + nr_events, | 227 | nr_events += pmu->get_current_events(cpuid, events + nr_events, |
| @@ -373,6 +381,14 @@ get_stack_offset(struct task_struct *task, | |||
| 373 | return vma->vm_end - sp; | 381 | return vma->vm_end - sp; |
| 374 | } | 382 | } |
| 375 | 383 | ||
| 384 | static inline void | ||
| 385 | validate_um_for_task(struct task_struct *task, | ||
| 386 | pid_t param_pid, struct quadd_unw_methods *um) | ||
| 387 | { | ||
| 388 | if (task_tgid_nr(task) != param_pid) | ||
| 389 | um->ut = um->dwarf = 0; | ||
| 390 | } | ||
| 391 | |||
| 376 | static void | 392 | static void |
| 377 | read_all_sources(struct pt_regs *regs, struct task_struct *task, int is_sched) | 393 | read_all_sources(struct pt_regs *regs, struct task_struct *task, int is_sched) |
| 378 | { | 394 | { |
| @@ -436,6 +452,7 @@ read_all_sources(struct pt_regs *regs, struct task_struct *task, int is_sched) | |||
| 436 | 452 | ||
| 437 | if (ctx->param.backtrace) { | 453 | if (ctx->param.backtrace) { |
| 438 | cc->um = hrt.um; | 454 | cc->um = hrt.um; |
| 455 | validate_um_for_task(task, ctx->param.pids[0], &cc->um); | ||
| 439 | 456 | ||
| 440 | bt_size = quadd_get_user_callchain(&event_ctx, cc, ctx); | 457 | bt_size = quadd_get_user_callchain(&event_ctx, cc, ctx); |
| 441 | if (bt_size > 0) { | 458 | if (bt_size > 0) { |
| @@ -538,55 +555,69 @@ read_all_sources(struct pt_regs *regs, struct task_struct *task, int is_sched) | |||
| 538 | } | 555 | } |
| 539 | 556 | ||
| 540 | static inline int | 557 | static inline int |
| 541 | is_profile_process(struct task_struct *task) | 558 | is_profile_process(struct task_struct *task, int is_trace) |
| 542 | { | 559 | { |
| 543 | int i; | 560 | pid_t pid; |
| 544 | pid_t pid, profile_pid; | ||
| 545 | struct quadd_ctx *ctx = hrt.quadd_ctx; | 561 | struct quadd_ctx *ctx = hrt.quadd_ctx; |
| 546 | 562 | ||
| 547 | if (!task) | 563 | pid = ctx->param.pids[0]; |
| 548 | return 0; | 564 | |
| 565 | if (task_tgid_nr(task) == pid) | ||
| 566 | return 1; | ||
| 567 | |||
| 568 | if ((is_trace && quadd_mode_is_trace_tree(ctx)) || | ||
| 569 | (!is_trace && quadd_mode_is_sample_tree(ctx))) { | ||
| 570 | struct task_struct *p; | ||
| 549 | 571 | ||
| 550 | pid = task->tgid; | 572 | read_lock(&tasklist_lock); |
| 573 | for (p = task; p != &init_task;) { | ||
| 574 | if (task_pid_nr(p) == pid) { | ||
| 575 | read_unlock(&tasklist_lock); | ||
| 576 | return 1; | ||
| 577 | } | ||
| 551 | 578 | ||
| 552 | for (i = 0; i < ctx->param.nr_pids; i++) { | 579 | rcu_read_lock(); |
| 553 | profile_pid = ctx->param.pids[i]; | 580 | p = rcu_dereference(p->real_parent); |
| 554 | if (profile_pid == pid) | 581 | rcu_read_unlock(); |
| 555 | return 1; | 582 | } |
| 583 | read_unlock(&tasklist_lock); | ||
| 556 | } | 584 | } |
| 557 | 585 | ||
| 558 | return 0; | 586 | return 0; |
| 559 | } | 587 | } |
| 560 | 588 | ||
| 561 | static inline int | 589 | static inline int |
| 562 | is_sample_process(struct task_struct *task) | 590 | is_swapper_task(struct task_struct *task) |
| 563 | { | 591 | { |
| 564 | return (quadd_mode_is_sampling() && | 592 | return task_pid_nr(task) == 0; |
| 565 | is_profile_process(task)); | ||
| 566 | } | 593 | } |
| 567 | 594 | ||
| 568 | static inline int | 595 | static inline int |
| 569 | is_swapper_task(struct task_struct *task) | 596 | validate_task(struct task_struct *task) |
| 570 | { | 597 | { |
| 571 | if (task->pid == 0) | 598 | return task && task->mm && !is_swapper_task(task); |
| 572 | return 1; | 599 | } |
| 573 | 600 | ||
| 574 | return 0; | 601 | static inline int |
| 602 | is_sample_process(struct task_struct *task) | ||
| 603 | { | ||
| 604 | struct quadd_ctx *ctx = hrt.quadd_ctx; | ||
| 605 | |||
| 606 | if (!validate_task(task) || !quadd_mode_is_sampling(ctx)) | ||
| 607 | return 0; | ||
| 608 | |||
| 609 | return (quadd_mode_is_sample_all(ctx) || is_profile_process(task, 0)); | ||
| 575 | } | 610 | } |
| 576 | 611 | ||
| 577 | static inline int | 612 | static inline int |
| 578 | is_trace_process(struct task_struct *task) | 613 | is_trace_process(struct task_struct *task) |
| 579 | { | 614 | { |
| 580 | if (!task) | 615 | struct quadd_ctx *ctx = hrt.quadd_ctx; |
| 581 | return 0; | ||
| 582 | 616 | ||
| 583 | if (is_swapper_task(task)) | 617 | if (!validate_task(task) || !quadd_mode_is_tracing(ctx)) |
| 584 | return 0; | 618 | return 0; |
| 585 | 619 | ||
| 586 | if (quadd_mode_is_trace_all()) | 620 | return (quadd_mode_is_trace_all(ctx) || is_profile_process(task, 1)); |
| 587 | return 1; | ||
| 588 | |||
| 589 | return is_profile_process(task); | ||
| 590 | } | 621 | } |
| 591 | 622 | ||
| 592 | static int | 623 | static int |
| @@ -702,16 +733,13 @@ void __quadd_task_sched_out(struct task_struct *prev, | |||
| 702 | 733 | ||
| 703 | void __quadd_event_mmap(struct vm_area_struct *vma) | 734 | void __quadd_event_mmap(struct vm_area_struct *vma) |
| 704 | { | 735 | { |
| 705 | struct quadd_parameters *param; | 736 | if (likely(!atomic_read(&hrt.mmap_active))) |
| 706 | |||
| 707 | if (likely(!atomic_read(&hrt.active))) | ||
| 708 | return; | 737 | return; |
| 709 | 738 | ||
| 710 | if (!is_sample_process(current)) | 739 | if (!is_sample_process(current)) |
| 711 | return; | 740 | return; |
| 712 | 741 | ||
| 713 | param = &hrt.quadd_ctx->param; | 742 | quadd_process_mmap(vma, current); |
| 714 | quadd_process_mmap(vma, param->pids[0]); | ||
| 715 | } | 743 | } |
| 716 | 744 | ||
| 717 | static void reset_cpu_ctx(void) | 745 | static void reset_cpu_ctx(void) |
| @@ -733,7 +761,6 @@ static void reset_cpu_ctx(void) | |||
| 733 | 761 | ||
| 734 | int quadd_hrt_start(void) | 762 | int quadd_hrt_start(void) |
| 735 | { | 763 | { |
| 736 | int err; | ||
| 737 | int cpuid; | 764 | int cpuid; |
| 738 | u64 period; | 765 | u64 period; |
| 739 | long freq; | 766 | long freq; |
| @@ -787,14 +814,16 @@ int quadd_hrt_start(void) | |||
| 787 | put_header(cpuid); | 814 | put_header(cpuid); |
| 788 | } | 815 | } |
| 789 | 816 | ||
| 790 | if (quadd_mode_is_sampling()) { | 817 | atomic_set(&hrt.mmap_active, 1); |
| 791 | if (extra & QUADD_PARAM_EXTRA_GET_MMAP) { | 818 | |
| 792 | err = quadd_get_current_mmap(param->pids[0]); | 819 | /* Enable the mmap events processing before quadd_get_mmaps() |
| 793 | if (err) { | 820 | * otherwise we can miss some events. |
| 794 | pr_err("error: quadd_get_current_mmap\n"); | 821 | */ |
| 795 | return err; | 822 | smp_wmb(); |
| 796 | } | 823 | |
| 797 | } | 824 | if (quadd_mode_is_sampling(ctx)) { |
| 825 | if (extra & QUADD_PARAM_EXTRA_GET_MMAP) | ||
| 826 | quadd_get_mmaps(ctx); | ||
| 798 | 827 | ||
| 799 | if (ctx->pl310) | 828 | if (ctx->pl310) |
| 800 | ctx->pl310->start(); | 829 | ctx->pl310->start(); |
| @@ -802,6 +831,9 @@ int quadd_hrt_start(void) | |||
| 802 | 831 | ||
| 803 | quadd_ma_start(&hrt); | 832 | quadd_ma_start(&hrt); |
| 804 | 833 | ||
| 834 | /* Enable the sampling only after quadd_get_mmaps() */ | ||
| 835 | smp_wmb(); | ||
| 836 | |||
| 805 | atomic_set(&hrt.active, 1); | 837 | atomic_set(&hrt.active, 1); |
| 806 | 838 | ||
| 807 | pr_info("Start hrt: freq/period: %ld/%llu\n", freq, period); | 839 | pr_info("Start hrt: freq/period: %ld/%llu\n", freq, period); |
| @@ -822,6 +854,7 @@ void quadd_hrt_stop(void) | |||
| 822 | quadd_ma_stop(&hrt); | 854 | quadd_ma_stop(&hrt); |
| 823 | 855 | ||
| 824 | atomic_set(&hrt.active, 0); | 856 | atomic_set(&hrt.active, 0); |
| 857 | atomic_set(&hrt.mmap_active, 0); | ||
| 825 | 858 | ||
| 826 | atomic64_set(&hrt.counter_samples, 0); | 859 | atomic64_set(&hrt.counter_samples, 0); |
| 827 | atomic64_set(&hrt.skipped_samples, 0); | 860 | atomic64_set(&hrt.skipped_samples, 0); |
| @@ -870,7 +903,9 @@ struct quadd_hrt_ctx *quadd_hrt_init(struct quadd_ctx *ctx) | |||
| 870 | struct quadd_cpu_context *cpu_ctx; | 903 | struct quadd_cpu_context *cpu_ctx; |
| 871 | 904 | ||
| 872 | hrt.quadd_ctx = ctx; | 905 | hrt.quadd_ctx = ctx; |
| 906 | |||
| 873 | atomic_set(&hrt.active, 0); | 907 | atomic_set(&hrt.active, 0); |
| 908 | atomic_set(&hrt.mmap_active, 0); | ||
| 874 | 909 | ||
| 875 | freq = ctx->param.freq; | 910 | freq = ctx->param.freq; |
| 876 | freq = max_t(long, QUADD_HRT_MIN_FREQ, freq); | 911 | freq = max_t(long, QUADD_HRT_MIN_FREQ, freq); |
diff --git a/drivers/misc/tegra-profiler/hrt.h b/drivers/misc/tegra-profiler/hrt.h index 2db0ac8e6..98b591d1e 100644 --- a/drivers/misc/tegra-profiler/hrt.h +++ b/drivers/misc/tegra-profiler/hrt.h | |||
| @@ -50,6 +50,7 @@ struct quadd_hrt_ctx { | |||
| 50 | struct quadd_ctx *quadd_ctx; | 50 | struct quadd_ctx *quadd_ctx; |
| 51 | 51 | ||
| 52 | atomic_t active; | 52 | atomic_t active; |
| 53 | atomic_t mmap_active; | ||
| 53 | atomic_t nr_active_all_core; | 54 | atomic_t nr_active_all_core; |
| 54 | 55 | ||
| 55 | atomic64_t counter_samples; | 56 | atomic64_t counter_samples; |
| @@ -62,11 +63,11 @@ struct quadd_hrt_ctx { | |||
| 62 | unsigned long rss_size_prev; | 63 | unsigned long rss_size_prev; |
| 63 | 64 | ||
| 64 | struct timecounter *tc; | 65 | struct timecounter *tc; |
| 65 | int use_arch_timer; | 66 | unsigned int use_arch_timer:1; |
| 66 | int arch_timer_user_access; | 67 | unsigned int arch_timer_user_access:1; |
| 67 | 68 | ||
| 68 | struct quadd_unw_methods um; | 69 | struct quadd_unw_methods um; |
| 69 | int get_stack_offset; | 70 | unsigned int get_stack_offset:1; |
| 70 | }; | 71 | }; |
| 71 | 72 | ||
| 72 | struct task_struct; | 73 | struct task_struct; |
| @@ -76,8 +77,8 @@ struct quadd_event_context { | |||
| 76 | struct task_struct *task; | 77 | struct task_struct *task; |
| 77 | struct pt_regs *regs; | 78 | struct pt_regs *regs; |
| 78 | 79 | ||
| 79 | int user_mode; | 80 | unsigned int user_mode:1; |
| 80 | int is_sched; | 81 | unsigned int is_sched:1; |
| 81 | }; | 82 | }; |
| 82 | 83 | ||
| 83 | #define QUADD_HRT_MIN_FREQ 100 | 84 | #define QUADD_HRT_MIN_FREQ 100 |
diff --git a/drivers/misc/tegra-profiler/main.c b/drivers/misc/tegra-profiler/main.c index 1e5a5d3d2..8d76225c5 100644 --- a/drivers/misc/tegra-profiler/main.c +++ b/drivers/misc/tegra-profiler/main.c | |||
| @@ -60,16 +60,6 @@ static struct quadd_comm_cap_for_cpu *get_capabilities_for_cpu_int(int cpuid) | |||
| 60 | return &per_cpu(per_cpu_caps, cpuid); | 60 | return &per_cpu(per_cpu_caps, cpuid); |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | int quadd_mode_is_trace_all(void) | ||
| 64 | { | ||
| 65 | return ctx.mode_is_trace_all; | ||
| 66 | } | ||
| 67 | |||
| 68 | int quadd_mode_is_sampling(void) | ||
| 69 | { | ||
| 70 | return ctx.mode_is_sampling; | ||
| 71 | } | ||
| 72 | |||
| 73 | int tegra_profiler_try_lock(void) | 63 | int tegra_profiler_try_lock(void) |
| 74 | { | 64 | { |
| 75 | return atomic_cmpxchg(&ctx.tegra_profiler_lock, 0, 1); | 65 | return atomic_cmpxchg(&ctx.tegra_profiler_lock, 0, 1); |
| @@ -92,14 +82,12 @@ static int start(void) | |||
| 92 | } | 82 | } |
| 93 | 83 | ||
| 94 | if (!atomic_cmpxchg(&ctx.started, 0, 1)) { | 84 | if (!atomic_cmpxchg(&ctx.started, 0, 1)) { |
| 95 | preempt_disable(); | 85 | if (quadd_mode_is_sampling(&ctx)) { |
| 96 | |||
| 97 | if (quadd_mode_is_sampling()) { | ||
| 98 | if (ctx.pmu) { | 86 | if (ctx.pmu) { |
| 99 | err = ctx.pmu->enable(); | 87 | err = ctx.pmu->enable(); |
| 100 | if (err) { | 88 | if (err) { |
| 101 | pr_err("error: pmu enable\n"); | 89 | pr_err("error: pmu enable\n"); |
| 102 | goto errout_preempt; | 90 | goto errout; |
| 103 | } | 91 | } |
| 104 | } | 92 | } |
| 105 | 93 | ||
| @@ -107,7 +95,7 @@ static int start(void) | |||
| 107 | err = ctx.pl310->enable(); | 95 | err = ctx.pl310->enable(); |
| 108 | if (err) { | 96 | if (err) { |
| 109 | pr_err("error: pl310 enable\n"); | 97 | pr_err("error: pl310 enable\n"); |
| 110 | goto errout_preempt; | 98 | goto errout; |
| 111 | } | 99 | } |
| 112 | } | 100 | } |
| 113 | } | 101 | } |
| @@ -117,11 +105,9 @@ static int start(void) | |||
| 117 | err = quadd_hrt_start(); | 105 | err = quadd_hrt_start(); |
| 118 | if (err) { | 106 | if (err) { |
| 119 | pr_err("error: hrt start\n"); | 107 | pr_err("error: hrt start\n"); |
| 120 | goto errout_preempt; | 108 | goto errout; |
| 121 | } | 109 | } |
| 122 | 110 | ||
| 123 | preempt_enable(); | ||
| 124 | |||
| 125 | err = quadd_power_clk_start(); | 111 | err = quadd_power_clk_start(); |
| 126 | if (err < 0) { | 112 | if (err < 0) { |
| 127 | pr_err("error: power_clk start\n"); | 113 | pr_err("error: power_clk start\n"); |
| @@ -131,9 +117,6 @@ static int start(void) | |||
| 131 | 117 | ||
| 132 | return 0; | 118 | return 0; |
| 133 | 119 | ||
| 134 | errout_preempt: | ||
| 135 | preempt_enable(); | ||
| 136 | |||
| 137 | errout: | 120 | errout: |
| 138 | atomic_set(&ctx.started, 0); | 121 | atomic_set(&ctx.started, 0); |
| 139 | tegra_profiler_unlock(); | 122 | tegra_profiler_unlock(); |
| @@ -268,10 +251,10 @@ static int verify_app(struct quadd_parameters *p, uid_t task_uid) | |||
| 268 | static int | 251 | static int |
| 269 | set_parameters(struct quadd_parameters *p) | 252 | set_parameters(struct quadd_parameters *p) |
| 270 | { | 253 | { |
| 271 | int i, err, nr_pl310 = 0; | 254 | int i, err = 0, nr_pl310 = 0; |
| 272 | uid_t task_uid, current_uid; | 255 | uid_t task_uid, current_uid; |
| 273 | struct quadd_event *pl310_events; | 256 | struct quadd_event *pl310_events; |
| 274 | struct task_struct *task; | 257 | struct task_struct *task = NULL; |
| 275 | u64 *low_addr_p; | 258 | u64 *low_addr_p; |
| 276 | u32 extra; | 259 | u32 extra; |
| 277 | 260 | ||
| @@ -279,49 +262,61 @@ set_parameters(struct quadd_parameters *p) | |||
| 279 | 262 | ||
| 280 | ctx.mode_is_sampling = | 263 | ctx.mode_is_sampling = |
| 281 | extra & QUADD_PARAM_EXTRA_SAMPLING ? 1 : 0; | 264 | extra & QUADD_PARAM_EXTRA_SAMPLING ? 1 : 0; |
| 265 | ctx.mode_is_tracing = | ||
| 266 | extra & QUADD_PARAM_EXTRA_TRACING ? 1 : 0; | ||
| 267 | ctx.mode_is_sample_all = | ||
| 268 | extra & QUADD_PARAM_EXTRA_SAMPLE_ALL_TASKS ? 1 : 0; | ||
| 282 | ctx.mode_is_trace_all = p->trace_all_tasks; | 269 | ctx.mode_is_trace_all = p->trace_all_tasks; |
| 283 | 270 | ctx.mode_is_sample_tree = | |
| 284 | pr_info("flag: sampling: %s\n", | 271 | extra & QUADD_PARAM_EXTRA_SAMPLE_TREE ? 1 : 0; |
| 285 | ctx.mode_is_sampling ? "yes" : "no"); | 272 | ctx.mode_is_trace_tree = |
| 286 | pr_info("flag: trace all: %s\n", | 273 | extra & QUADD_PARAM_EXTRA_TRACE_TREE ? 1 : 0; |
| 287 | ctx.mode_is_trace_all ? "yes" : "no"); | 274 | |
| 288 | 275 | pr_info("flags: s/t/sa/ta/st/tt: %u/%u/%u/%u/%u/%u\n", | |
| 289 | if (ctx.mode_is_trace_all && !capable(CAP_SYS_ADMIN)) { | 276 | ctx.mode_is_sampling, |
| 290 | pr_err("error: trace all tasks mode is allowed only for root\n"); | 277 | ctx.mode_is_tracing, |
| 278 | ctx.mode_is_sample_all, | ||
| 279 | ctx.mode_is_trace_all, | ||
| 280 | ctx.mode_is_sample_tree, | ||
| 281 | ctx.mode_is_trace_tree); | ||
| 282 | |||
| 283 | if ((ctx.mode_is_trace_all || ctx.mode_is_sample_all) && | ||
| 284 | !capable(CAP_SYS_ADMIN)) { | ||
| 285 | pr_err("error: \"all tasks\" modes are allowed only for root\n"); | ||
| 291 | return -EACCES; | 286 | return -EACCES; |
| 292 | } | 287 | } |
| 293 | 288 | ||
| 294 | p->package_name[sizeof(p->package_name) - 1] = '\0'; | 289 | p->package_name[sizeof(p->package_name) - 1] = '\0'; |
| 295 | ctx.param = *p; | 290 | ctx.param = *p; |
| 296 | 291 | ||
| 297 | if (!ctx.mode_is_trace_all || ctx.mode_is_sampling) { | 292 | current_uid = from_kuid(&init_user_ns, current_fsuid()); |
| 298 | if (!validate_freq(p->freq)) { | 293 | pr_info("owner uid: %u\n", current_uid); |
| 294 | |||
| 295 | if ((ctx.mode_is_tracing && !ctx.mode_is_trace_all) || | ||
| 296 | (ctx.mode_is_sampling && !ctx.mode_is_sample_all)) { | ||
| 297 | if (ctx.mode_is_sampling && !validate_freq(p->freq)) { | ||
| 299 | pr_err("error: incorrect frequency: %u\n", p->freq); | 298 | pr_err("error: incorrect frequency: %u\n", p->freq); |
| 300 | return -EINVAL; | 299 | return -EINVAL; |
| 301 | } | 300 | } |
| 302 | 301 | ||
| 303 | /* Currently only one process */ | 302 | /* Currently only first process */ |
| 304 | if (p->nr_pids != 1) | 303 | if (p->nr_pids != 1) |
| 305 | return -EINVAL; | 304 | return -EINVAL; |
| 306 | 305 | ||
| 307 | rcu_read_lock(); | 306 | task = get_pid_task(find_vpid(p->pids[0]), PIDTYPE_PID); |
| 308 | task = pid_task(find_vpid(p->pids[0]), PIDTYPE_PID); | ||
| 309 | rcu_read_unlock(); | ||
| 310 | if (!task) { | 307 | if (!task) { |
| 311 | pr_err("error: process not found: %u\n", p->pids[0]); | 308 | pr_err("error: process not found: %u\n", p->pids[0]); |
| 312 | return -ESRCH; | 309 | return -ESRCH; |
| 313 | } | 310 | } |
| 314 | 311 | ||
| 315 | current_uid = from_kuid(&init_user_ns, current_fsuid()); | ||
| 316 | task_uid = from_kuid(&init_user_ns, task_uid(task)); | 312 | task_uid = from_kuid(&init_user_ns, task_uid(task)); |
| 317 | 313 | pr_info("task uid: %u\n", task_uid); | |
| 318 | pr_info("owner/task uids: %u/%u\n", current_uid, task_uid); | ||
| 319 | 314 | ||
| 320 | if (!capable(CAP_SYS_ADMIN)) { | 315 | if (!capable(CAP_SYS_ADMIN)) { |
| 321 | if (current_uid != task_uid) { | 316 | if (current_uid != task_uid) { |
| 322 | err = verify_app(p, task_uid); | 317 | err = verify_app(p, task_uid); |
| 323 | if (err < 0) | 318 | if (err < 0) |
| 324 | return err; | 319 | goto out_put_task; |
| 325 | } | 320 | } |
| 326 | ctx.collect_kernel_ips = 0; | 321 | ctx.collect_kernel_ips = 0; |
| 327 | } else { | 322 | } else { |
| @@ -335,8 +330,10 @@ set_parameters(struct quadd_parameters *p) | |||
| 335 | type = event->type; | 330 | type = event->type; |
| 336 | id = event->id; | 331 | id = event->id; |
| 337 | 332 | ||
| 338 | if (type != QUADD_EVENT_TYPE_HARDWARE) | 333 | if (type != QUADD_EVENT_TYPE_HARDWARE) { |
| 339 | return -EINVAL; | 334 | err = -EINVAL; |
| 335 | goto out_put_task; | ||
| 336 | } | ||
| 340 | 337 | ||
| 341 | if (ctx.pl310 && | 338 | if (ctx.pl310 && |
| 342 | ctx.pl310_info.nr_supp_events > 0 && | 339 | ctx.pl310_info.nr_supp_events > 0 && |
| @@ -348,12 +345,14 @@ set_parameters(struct quadd_parameters *p) | |||
| 348 | 345 | ||
| 349 | if (nr_pl310++ > 1) { | 346 | if (nr_pl310++ > 1) { |
| 350 | pr_err("error: multiply pl310 events\n"); | 347 | pr_err("error: multiply pl310 events\n"); |
| 351 | return -EINVAL; | 348 | err = -EINVAL; |
| 349 | goto out_put_task; | ||
| 352 | } | 350 | } |
| 353 | } else { | 351 | } else { |
| 354 | pr_err("Bad event: %s\n", | 352 | pr_err("Bad event: %s\n", |
| 355 | quadd_get_hw_event_str(id)); | 353 | quadd_get_hw_event_str(id)); |
| 356 | return -EINVAL; | 354 | err = -EINVAL; |
| 355 | goto out_put_task; | ||
| 357 | } | 356 | } |
| 358 | } | 357 | } |
| 359 | 358 | ||
| @@ -365,7 +364,7 @@ set_parameters(struct quadd_parameters *p) | |||
| 365 | pl310_events, 1); | 364 | pl310_events, 1); |
| 366 | if (err) { | 365 | if (err) { |
| 367 | pr_info("pl310 set_parameters: error\n"); | 366 | pr_info("pl310 set_parameters: error\n"); |
| 368 | return err; | 367 | goto out_put_task; |
| 369 | } | 368 | } |
| 370 | ctx.pl310_info.active = 1; | 369 | ctx.pl310_info.active = 1; |
| 371 | } else { | 370 | } else { |
| @@ -381,12 +380,16 @@ set_parameters(struct quadd_parameters *p) | |||
| 381 | 380 | ||
| 382 | err = quadd_unwind_start(task); | 381 | err = quadd_unwind_start(task); |
| 383 | if (err) | 382 | if (err) |
| 384 | return err; | 383 | goto out_put_task; |
| 385 | } | 384 | } |
| 386 | 385 | ||
| 387 | pr_info("New parameters have been applied\n"); | 386 | pr_info("New parameters have been applied\n"); |
| 388 | 387 | ||
| 389 | return 0; | 388 | out_put_task: |
| 389 | if (task) | ||
| 390 | put_task_struct(task); | ||
| 391 | |||
| 392 | return err; | ||
| 390 | } | 393 | } |
| 391 | 394 | ||
| 392 | static void | 395 | static void |
| @@ -734,7 +737,7 @@ static int __init quadd_module_init(void) | |||
| 734 | return err; | 737 | return err; |
| 735 | } | 738 | } |
| 736 | 739 | ||
| 737 | ctx.comm = quadd_comm_events_init(&control); | 740 | ctx.comm = quadd_comm_events_init(&ctx, &control); |
| 738 | if (IS_ERR(ctx.comm)) { | 741 | if (IS_ERR(ctx.comm)) { |
| 739 | pr_err("error: COMM init failed\n"); | 742 | pr_err("error: COMM init failed\n"); |
| 740 | return PTR_ERR(ctx.comm); | 743 | return PTR_ERR(ctx.comm); |
diff --git a/drivers/misc/tegra-profiler/mmap.c b/drivers/misc/tegra-profiler/mmap.c index 43b7648b6..3e8a5c729 100644 --- a/drivers/misc/tegra-profiler/mmap.c +++ b/drivers/misc/tegra-profiler/mmap.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * drivers/misc/tegra-profiler/mmap.c | 2 | * drivers/misc/tegra-profiler/mmap.c |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved. | 4 | * Copyright (c) 2015-2018, NVIDIA CORPORATION. All rights reserved. |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
| 7 | * under the terms and conditions of the GNU General Public License, | 7 | * under the terms and conditions of the GNU General Public License, |
| @@ -24,20 +24,24 @@ | |||
| 24 | 24 | ||
| 25 | #include <linux/tegra_profiler.h> | 25 | #include <linux/tegra_profiler.h> |
| 26 | 26 | ||
| 27 | #include "quadd.h" | ||
| 27 | #include "mmap.h" | 28 | #include "mmap.h" |
| 28 | #include "comm.h" | 29 | #include "comm.h" |
| 29 | #include "hrt.h" | 30 | #include "hrt.h" |
| 30 | 31 | ||
| 31 | #define TMP_BUFFER_SIZE (PATH_MAX + sizeof(u64)) | 32 | #define TMP_BUFFER_SIZE (PATH_MAX + sizeof(u64)) |
| 33 | #define QUADD_MMAP_TREE_MAX_LEVEL 32 | ||
| 32 | 34 | ||
| 33 | static void | 35 | static void |
| 34 | put_mmap_sample(struct quadd_mmap_data *s, char *filename, | 36 | put_mmap_sample(struct quadd_mmap_data *s, char *filename, |
| 35 | size_t length, unsigned long pgoff, int is_file_exists) | 37 | size_t length, unsigned long pgoff, |
| 38 | int is_file_exists, pid_t __tgid) | ||
| 36 | { | 39 | { |
| 37 | u64 mmap_ed = 0; | 40 | u64 mmap_ed = 0; |
| 38 | struct quadd_record_data r; | 41 | struct quadd_record_data r; |
| 39 | struct quadd_iovec vec[3]; | 42 | struct quadd_iovec vec[4]; |
| 40 | u64 pgoff_val = (u64)pgoff << PAGE_SHIFT; | 43 | u64 pgoff_val = (u64)pgoff << PAGE_SHIFT; |
| 44 | u32 tgid = (u32)__tgid; | ||
| 41 | 45 | ||
| 42 | r.record_type = QUADD_RECORD_TYPE_MMAP; | 46 | r.record_type = QUADD_RECORD_TYPE_MMAP; |
| 43 | 47 | ||
| @@ -58,39 +62,35 @@ put_mmap_sample(struct quadd_mmap_data *s, char *filename, | |||
| 58 | vec[2].base = filename; | 62 | vec[2].base = filename; |
| 59 | vec[2].len = length; | 63 | vec[2].len = length; |
| 60 | 64 | ||
| 61 | pr_debug("MMAP: pid: %u, file_name: '%s', addr: %#llx - %#llx, len: %llx, pgoff: %#llx\n", | 65 | vec[3].base = &tgid; |
| 62 | s->pid, filename, | 66 | vec[3].len = sizeof(tgid); |
| 67 | |||
| 68 | pr_debug("[%d] MMAP: tid: %u,pid: %u,'%s',%#llx-%#llx(%llx,%#llx)\n", | ||
| 69 | smp_processor_id(), s->pid, tgid, filename, | ||
| 63 | s->addr, s->addr + s->len, s->len, pgoff_val); | 70 | s->addr, s->addr + s->len, s->len, pgoff_val); |
| 64 | 71 | ||
| 65 | quadd_put_sample(&r, vec, ARRAY_SIZE(vec)); | 72 | quadd_put_sample_this_cpu(&r, vec, ARRAY_SIZE(vec)); |
| 66 | } | 73 | } |
| 67 | 74 | ||
| 68 | void quadd_process_mmap(struct vm_area_struct *vma, pid_t pid) | 75 | static void |
| 76 | process_mmap(struct vm_area_struct *vma, struct task_struct *task, | ||
| 77 | char *buf, size_t buf_size) | ||
| 69 | { | 78 | { |
| 79 | pid_t tgid; | ||
| 70 | int is_file_exists; | 80 | int is_file_exists; |
| 71 | struct file *vm_file; | 81 | struct file *vm_file; |
| 72 | struct path *path; | 82 | char *file_name; |
| 73 | char *file_name, *tmp_buf = NULL; | ||
| 74 | struct quadd_mmap_data sample; | 83 | struct quadd_mmap_data sample; |
| 75 | size_t length, length_aligned; | 84 | size_t length, length_aligned; |
| 76 | 85 | ||
| 77 | if (!vma) | ||
| 78 | return; | ||
| 79 | |||
| 80 | if (!(vma->vm_flags & VM_EXEC)) | 86 | if (!(vma->vm_flags & VM_EXEC)) |
| 81 | return; | 87 | return; |
| 82 | 88 | ||
| 83 | tmp_buf = kzalloc(TMP_BUFFER_SIZE, GFP_ATOMIC); | ||
| 84 | if (!tmp_buf) | ||
| 85 | return; | ||
| 86 | |||
| 87 | vm_file = vma->vm_file; | 89 | vm_file = vma->vm_file; |
| 88 | if (vm_file) { | 90 | if (vm_file) { |
| 89 | path = &vm_file->f_path; | 91 | file_name = file_path(vm_file, buf, PATH_MAX); |
| 90 | |||
| 91 | file_name = d_path(path, tmp_buf, PATH_MAX); | ||
| 92 | if (IS_ERR(file_name)) | 92 | if (IS_ERR(file_name)) |
| 93 | goto out; | 93 | return; |
| 94 | 94 | ||
| 95 | length = strlen(file_name) + 1; | 95 | length = strlen(file_name) + 1; |
| 96 | is_file_exists = 1; | 96 | is_file_exists = 1; |
| @@ -113,12 +113,12 @@ void quadd_process_mmap(struct vm_area_struct *vma, pid_t pid) | |||
| 113 | } | 113 | } |
| 114 | 114 | ||
| 115 | if (name) | 115 | if (name) |
| 116 | strlcpy(tmp_buf, name, TMP_BUFFER_SIZE); | 116 | strlcpy(buf, name, buf_size); |
| 117 | else | 117 | else |
| 118 | snprintf(tmp_buf, TMP_BUFFER_SIZE, "[vma:%08lx-%08lx]", | 118 | snprintf(buf, buf_size, "[vma:%08lx-%08lx]", |
| 119 | vma->vm_start, vma->vm_end); | 119 | vma->vm_start, vma->vm_end); |
| 120 | 120 | ||
| 121 | file_name = tmp_buf; | 121 | file_name = buf; |
| 122 | length = strlen(file_name) + 1; | 122 | length = strlen(file_name) + 1; |
| 123 | 123 | ||
| 124 | is_file_exists = 0; | 124 | is_file_exists = 0; |
| @@ -126,110 +126,160 @@ void quadd_process_mmap(struct vm_area_struct *vma, pid_t pid) | |||
| 126 | 126 | ||
| 127 | length_aligned = ALIGN(length, sizeof(u64)); | 127 | length_aligned = ALIGN(length, sizeof(u64)); |
| 128 | 128 | ||
| 129 | sample.pid = pid; | 129 | sample.pid = task_pid_nr(task); |
| 130 | tgid = task_tgid_nr(task); | ||
| 130 | sample.user_mode = 1; | 131 | sample.user_mode = 1; |
| 131 | 132 | ||
| 132 | sample.addr = vma->vm_start; | 133 | sample.addr = vma->vm_start; |
| 133 | sample.len = vma->vm_end - vma->vm_start; | 134 | sample.len = vma->vm_end - vma->vm_start; |
| 134 | 135 | ||
| 135 | put_mmap_sample(&sample, file_name, length_aligned, | 136 | put_mmap_sample(&sample, file_name, length_aligned, |
| 136 | vma->vm_pgoff, is_file_exists); | 137 | vma->vm_pgoff, is_file_exists, tgid); |
| 138 | } | ||
| 137 | 139 | ||
| 138 | out: | 140 | void quadd_process_mmap(struct vm_area_struct *vma, struct task_struct *task) |
| 139 | kfree(tmp_buf); | 141 | { |
| 142 | char *buf; | ||
| 143 | |||
| 144 | buf = kzalloc(TMP_BUFFER_SIZE, GFP_ATOMIC); | ||
| 145 | if (!buf) | ||
| 146 | return; | ||
| 147 | |||
| 148 | preempt_disable(); | ||
| 149 | process_mmap(vma, task, buf, TMP_BUFFER_SIZE); | ||
| 150 | preempt_enable(); | ||
| 151 | |||
| 152 | kfree(buf); | ||
| 140 | } | 153 | } |
| 141 | 154 | ||
| 142 | int quadd_get_current_mmap(pid_t pid) | 155 | static void get_process_vmas(struct task_struct *task) |
| 143 | { | 156 | { |
| 144 | int is_file_exists; | 157 | char *buf; |
| 145 | struct vm_area_struct *vma; | ||
| 146 | struct file *vm_file; | ||
| 147 | struct path *path; | ||
| 148 | char *file_name; | ||
| 149 | struct task_struct *task; | ||
| 150 | struct mm_struct *mm; | 158 | struct mm_struct *mm; |
| 151 | struct quadd_mmap_data sample; | 159 | struct vm_area_struct *vma; |
| 152 | size_t length, length_aligned; | 160 | |
| 153 | char *tmp_buf; | 161 | if (!task) |
| 154 | 162 | return; | |
| 155 | rcu_read_lock(); | 163 | |
| 156 | task = pid_task(find_vpid(pid), PIDTYPE_PID); | 164 | mm = get_task_mm(task); |
| 157 | rcu_read_unlock(); | 165 | if (!mm) |
| 158 | if (!task) { | 166 | return; |
| 159 | pr_err("Process not found: %d\n", pid); | 167 | |
| 160 | return -ESRCH; | 168 | down_read(&mm->mmap_sem); |
| 161 | } | 169 | |
| 170 | buf = kzalloc(TMP_BUFFER_SIZE, GFP_ATOMIC); | ||
| 171 | if (!buf) | ||
| 172 | goto out_put_mm; | ||
| 173 | |||
| 174 | preempt_disable(); | ||
| 175 | for (vma = mm->mmap; vma; vma = vma->vm_next) | ||
| 176 | process_mmap(vma, task, buf, TMP_BUFFER_SIZE); | ||
| 177 | preempt_enable(); | ||
| 178 | |||
| 179 | kfree(buf); | ||
| 180 | |||
| 181 | out_put_mm: | ||
| 182 | up_read(&mm->mmap_sem); | ||
| 183 | mmput(mm); | ||
| 184 | } | ||
| 162 | 185 | ||
| 163 | mm = task->mm; | 186 | static void |
| 164 | if (!mm) { | 187 | __get_process_vmas(struct task_struct *task, |
| 165 | pr_warn("mm is not existed for task: %d\n", pid); | 188 | struct mm_struct *mm, char *buf, size_t buf_size) |
| 166 | return 0; | 189 | { |
| 190 | struct vm_area_struct *vma; | ||
| 191 | |||
| 192 | for (vma = mm->mmap; vma; vma = vma->vm_next) | ||
| 193 | process_mmap(vma, task, buf, buf_size); | ||
| 194 | } | ||
| 195 | |||
| 196 | static int | ||
| 197 | is_sample_process(struct task_struct *from, struct pid *root_pid) | ||
| 198 | { | ||
| 199 | struct task_struct *p; | ||
| 200 | |||
| 201 | for (p = from; p != &init_task;) { | ||
| 202 | if (task_pid_nr(p) == pid_nr(root_pid)) | ||
| 203 | return 1; | ||
| 204 | |||
| 205 | rcu_read_lock(); | ||
| 206 | p = rcu_dereference(p->real_parent); | ||
| 207 | rcu_read_unlock(); | ||
| 167 | } | 208 | } |
| 168 | 209 | ||
| 169 | pr_info("Get mapped memory objects\n"); | 210 | return 0; |
| 211 | } | ||
| 212 | |||
| 213 | static void get_all_processes(struct pid *root_pid) | ||
| 214 | { | ||
| 215 | char *buf; | ||
| 216 | struct task_struct *p; | ||
| 217 | |||
| 218 | buf = kzalloc(TMP_BUFFER_SIZE, GFP_ATOMIC); | ||
| 219 | if (!buf) | ||
| 220 | return; | ||
| 170 | 221 | ||
| 171 | tmp_buf = kzalloc(TMP_BUFFER_SIZE, GFP_ATOMIC); | 222 | read_lock(&tasklist_lock); |
| 172 | if (!tmp_buf) | 223 | for_each_process(p) { |
| 173 | return -ENOMEM; | 224 | struct mm_struct *mm; |
| 174 | 225 | ||
| 175 | for (vma = mm->mmap; vma; vma = vma->vm_next) { | 226 | if (p->flags & PF_KTHREAD) |
| 176 | if (!(vma->vm_flags & VM_EXEC)) | ||
| 177 | continue; | 227 | continue; |
| 178 | 228 | ||
| 179 | vm_file = vma->vm_file; | 229 | if (root_pid && !is_sample_process(p, root_pid)) |
| 180 | if (vm_file) { | 230 | continue; |
| 181 | path = &vm_file->f_path; | ||
| 182 | |||
| 183 | file_name = d_path(path, tmp_buf, PATH_MAX); | ||
| 184 | if (IS_ERR(file_name)) | ||
| 185 | continue; | ||
| 186 | 231 | ||
| 187 | length = strlen(file_name) + 1; | 232 | rcu_read_lock(); |
| 188 | is_file_exists = 1; | 233 | task_lock(p); |
| 234 | if (likely(p->mm)) { | ||
| 235 | mm = p->mm; | ||
| 189 | } else { | 236 | } else { |
| 190 | const char *name = NULL; | 237 | mm = NULL; |
| 191 | 238 | task_unlock(p); | |
| 192 | name = arch_vma_name(vma); | 239 | } |
| 193 | if (!name) { | 240 | rcu_read_unlock(); |
| 194 | mm = vma->vm_mm; | 241 | |
| 195 | 242 | if (!mm) | |
| 196 | if (!mm) { | 243 | continue; |
| 197 | name = "[vdso]"; | ||
| 198 | } else if (vma->vm_start <= mm->start_brk && | ||
| 199 | vma->vm_end >= mm->brk) { | ||
| 200 | name = "[heap]"; | ||
| 201 | } else if (vma->vm_start <= mm->start_stack && | ||
| 202 | vma->vm_end >= mm->start_stack) { | ||
| 203 | name = "[stack]"; | ||
| 204 | } | ||
| 205 | } | ||
| 206 | 244 | ||
| 207 | if (name) | 245 | if (!down_read_trylock(&mm->mmap_sem)) |
| 208 | strlcpy(tmp_buf, name, TMP_BUFFER_SIZE); | 246 | goto __continue; |
| 209 | else | ||
| 210 | snprintf(tmp_buf, TMP_BUFFER_SIZE, | ||
| 211 | "[vma:%08lx-%08lx]", | ||
| 212 | vma->vm_start, vma->vm_end); | ||
| 213 | 247 | ||
| 214 | file_name = tmp_buf; | 248 | __get_process_vmas(p, mm, buf, TMP_BUFFER_SIZE); |
| 215 | length = strlen(file_name) + 1; | ||
| 216 | 249 | ||
| 217 | is_file_exists = 0; | 250 | up_read(&mm->mmap_sem); |
| 218 | } | 251 | __continue: |
| 252 | task_unlock(p); | ||
| 253 | } | ||
| 254 | read_unlock(&tasklist_lock); | ||
| 219 | 255 | ||
| 220 | length_aligned = ALIGN(length, sizeof(u64)); | 256 | kfree(buf); |
| 257 | } | ||
| 221 | 258 | ||
| 222 | sample.pid = pid; | 259 | void quadd_get_mmaps(struct quadd_ctx *ctx) |
| 223 | sample.user_mode = 1; | 260 | { |
| 261 | struct pid *pid; | ||
| 262 | struct task_struct *task; | ||
| 263 | struct quadd_parameters *param = &ctx->param; | ||
| 224 | 264 | ||
| 225 | sample.addr = vma->vm_start; | 265 | if (!quadd_mode_is_sampling(ctx)) |
| 226 | sample.len = vma->vm_end - vma->vm_start; | 266 | return; |
| 227 | 267 | ||
| 228 | put_mmap_sample(&sample, file_name, length_aligned, | 268 | if (quadd_mode_is_sample_all(ctx)) { |
| 229 | vma->vm_pgoff, is_file_exists); | 269 | get_all_processes(NULL); |
| 270 | return; | ||
| 230 | } | 271 | } |
| 231 | 272 | ||
| 232 | kfree(tmp_buf); | 273 | pid = find_vpid(param->pids[0]); |
| 233 | 274 | ||
| 234 | return 0; | 275 | task = get_pid_task(pid, PIDTYPE_PID); |
| 276 | if (!task) | ||
| 277 | return; | ||
| 278 | |||
| 279 | if (quadd_mode_is_sample_tree(ctx)) | ||
| 280 | get_all_processes(pid); | ||
| 281 | else | ||
| 282 | get_process_vmas(task); | ||
| 283 | |||
| 284 | put_task_struct(task); | ||
| 235 | } | 285 | } |
diff --git a/drivers/misc/tegra-profiler/mmap.h b/drivers/misc/tegra-profiler/mmap.h index 4928f939f..993a38c0c 100644 --- a/drivers/misc/tegra-profiler/mmap.h +++ b/drivers/misc/tegra-profiler/mmap.h | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * drivers/misc/tegra-profiler/mmap.h | 2 | * drivers/misc/tegra-profiler/mmap.h |
| 3 | * | 3 | * |
| 4 | * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. | 4 | * Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved. |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
| 7 | * under the terms and conditions of the GNU General Public License, | 7 | * under the terms and conditions of the GNU General Public License, |
| @@ -17,9 +17,11 @@ | |||
| 17 | #ifndef __QUADD_MMAP_H | 17 | #ifndef __QUADD_MMAP_H |
| 18 | #define __QUADD_MMAP_H | 18 | #define __QUADD_MMAP_H |
| 19 | 19 | ||
| 20 | #include <linux/types.h> | 20 | struct vm_area_struct; |
| 21 | struct task_struct; | ||
| 22 | struct quadd_ctx; | ||
| 21 | 23 | ||
| 22 | void quadd_process_mmap(struct vm_area_struct *vma, pid_t pid); | 24 | void quadd_process_mmap(struct vm_area_struct *vma, struct task_struct *task); |
| 23 | int quadd_get_current_mmap(pid_t pid); | 25 | void quadd_get_mmaps(struct quadd_ctx *ctx); |
| 24 | 26 | ||
| 25 | #endif /* __QUADD_MMAP_H */ | 27 | #endif /* __QUADD_MMAP_H */ |
diff --git a/drivers/misc/tegra-profiler/quadd.h b/drivers/misc/tegra-profiler/quadd.h index 7af3dfbb2..f85599c78 100644 --- a/drivers/misc/tegra-profiler/quadd.h +++ b/drivers/misc/tegra-profiler/quadd.h | |||
| @@ -56,8 +56,8 @@ struct source_info { | |||
| 56 | 56 | ||
| 57 | unsigned int raw_event_mask; | 57 | unsigned int raw_event_mask; |
| 58 | 58 | ||
| 59 | int is_present; | 59 | unsigned int is_present:1; |
| 60 | int active; | 60 | unsigned int active:1; |
| 61 | }; | 61 | }; |
| 62 | 62 | ||
| 63 | struct quadd_ctx { | 63 | struct quadd_ctx { |
| @@ -77,18 +77,49 @@ struct quadd_ctx { | |||
| 77 | atomic_t started; | 77 | atomic_t started; |
| 78 | atomic_t tegra_profiler_lock; | 78 | atomic_t tegra_profiler_lock; |
| 79 | 79 | ||
| 80 | int collect_kernel_ips; | 80 | unsigned int collect_kernel_ips:1; |
| 81 | 81 | ||
| 82 | int mode_is_trace_all; | 82 | unsigned int mode_is_sampling:1; |
| 83 | int mode_is_sampling; | 83 | unsigned int mode_is_tracing:1; |
| 84 | unsigned int mode_is_sample_all:1; | ||
| 85 | unsigned int mode_is_trace_all:1; | ||
| 86 | unsigned int mode_is_sample_tree:1; | ||
| 87 | unsigned int mode_is_trace_tree:1; | ||
| 84 | }; | 88 | }; |
| 85 | 89 | ||
| 90 | static inline int quadd_mode_is_sampling(struct quadd_ctx *ctx) | ||
| 91 | { | ||
| 92 | return ctx->mode_is_sampling; | ||
| 93 | } | ||
| 94 | |||
| 95 | static inline int quadd_mode_is_tracing(struct quadd_ctx *ctx) | ||
| 96 | { | ||
| 97 | return ctx->mode_is_tracing; | ||
| 98 | } | ||
| 99 | |||
| 100 | static inline int quadd_mode_is_sample_all(struct quadd_ctx *ctx) | ||
| 101 | { | ||
| 102 | return ctx->mode_is_sample_all; | ||
| 103 | } | ||
| 104 | |||
| 105 | static inline int quadd_mode_is_trace_all(struct quadd_ctx *ctx) | ||
| 106 | { | ||
| 107 | return ctx->mode_is_trace_all; | ||
| 108 | } | ||
| 109 | |||
| 110 | static inline int quadd_mode_is_sample_tree(struct quadd_ctx *ctx) | ||
| 111 | { | ||
| 112 | return ctx->mode_is_sample_tree; | ||
| 113 | } | ||
| 114 | |||
| 115 | static inline int quadd_mode_is_trace_tree(struct quadd_ctx *ctx) | ||
| 116 | { | ||
| 117 | return ctx->mode_is_trace_tree; | ||
| 118 | } | ||
| 119 | |||
| 86 | void quadd_get_state(struct quadd_module_state *state); | 120 | void quadd_get_state(struct quadd_module_state *state); |
| 87 | 121 | ||
| 88 | int tegra_profiler_try_lock(void); | 122 | int tegra_profiler_try_lock(void); |
| 89 | void tegra_profiler_unlock(void); | 123 | void tegra_profiler_unlock(void); |
| 90 | 124 | ||
| 91 | int quadd_mode_is_trace_all(void); | ||
| 92 | int quadd_mode_is_sampling(void); | ||
| 93 | |||
| 94 | #endif /* __QUADD_H */ | 125 | #endif /* __QUADD_H */ |
diff --git a/drivers/misc/tegra-profiler/quadd_proc.c b/drivers/misc/tegra-profiler/quadd_proc.c index 0dc0490fe..8eb25558f 100644 --- a/drivers/misc/tegra-profiler/quadd_proc.c +++ b/drivers/misc/tegra-profiler/quadd_proc.c | |||
| @@ -89,7 +89,7 @@ static int show_capabilities(struct seq_file *f, void *offset) | |||
| 89 | seq_printf(f, "pmu arch: %s\n", | 89 | seq_printf(f, "pmu arch: %s\n", |
| 90 | arch->name); | 90 | arch->name); |
| 91 | if (arch->pmuver_is_set) | 91 | if (arch->pmuver_is_set) |
| 92 | seq_printf(f, "pmu arch version: %d\n", | 92 | seq_printf(f, "pmu arch version: %u\n", |
| 93 | arch->pmuver); | 93 | arch->pmuver); |
| 94 | 94 | ||
| 95 | seq_printf(f, "l2 cache: %s\n", | 95 | seq_printf(f, "l2 cache: %s\n", |
diff --git a/drivers/misc/tegra-profiler/version.h b/drivers/misc/tegra-profiler/version.h index e1b72d69e..6b620d727 100644 --- a/drivers/misc/tegra-profiler/version.h +++ b/drivers/misc/tegra-profiler/version.h | |||
| @@ -17,7 +17,7 @@ | |||
| 17 | #ifndef __QUADD_VERSION_H | 17 | #ifndef __QUADD_VERSION_H |
| 18 | #define __QUADD_VERSION_H | 18 | #define __QUADD_VERSION_H |
| 19 | 19 | ||
| 20 | #define QUADD_MODULE_VERSION "1.121" | 20 | #define QUADD_MODULE_VERSION "1.122" |
| 21 | #define QUADD_MODULE_BRANCH "Dev" | 21 | #define QUADD_MODULE_BRANCH "Dev" |
| 22 | 22 | ||
| 23 | #endif /* __QUADD_VERSION_H */ | 23 | #endif /* __QUADD_VERSION_H */ |
diff --git a/include/linux/tegra_profiler.h b/include/linux/tegra_profiler.h index d101ccc1a..2b08a2f90 100644 --- a/include/linux/tegra_profiler.h +++ b/include/linux/tegra_profiler.h | |||
| @@ -19,8 +19,8 @@ | |||
| 19 | 19 | ||
| 20 | #include <linux/ioctl.h> | 20 | #include <linux/ioctl.h> |
| 21 | 21 | ||
| 22 | #define QUADD_SAMPLES_VERSION 42 | 22 | #define QUADD_SAMPLES_VERSION 43 |
| 23 | #define QUADD_IO_VERSION 24 | 23 | #define QUADD_IO_VERSION 25 |
| 24 | 24 | ||
| 25 | #define QUADD_IO_VERSION_DYNAMIC_RB 5 | 25 | #define QUADD_IO_VERSION_DYNAMIC_RB 5 |
| 26 | #define QUADD_IO_VERSION_RB_MAX_FILL_COUNT 6 | 26 | #define QUADD_IO_VERSION_RB_MAX_FILL_COUNT 6 |
| @@ -42,33 +42,35 @@ | |||
| 42 | #define QUADD_IO_VERSION_RAW_EVENTS 22 | 42 | #define QUADD_IO_VERSION_RAW_EVENTS 22 |
| 43 | #define QUADD_IO_VERSION_SAMPLING_MODE 23 | 43 | #define QUADD_IO_VERSION_SAMPLING_MODE 23 |
| 44 | #define QUADD_IO_VERSION_FORCE_ARCH_TIMER 24 | 44 | #define QUADD_IO_VERSION_FORCE_ARCH_TIMER 24 |
| 45 | 45 | #define QUADD_IO_VERSION_SAMPLE_ALL_TASKS 25 | |
| 46 | #define QUADD_SAMPLE_VERSION_THUMB_MODE_FLAG 17 | 46 | |
| 47 | #define QUADD_SAMPLE_VERSION_GROUP_SAMPLES 18 | 47 | #define QUADD_SAMPLE_VERSION_THUMB_MODE_FLAG 17 |
| 48 | #define QUADD_SAMPLE_VERSION_THREAD_STATE_FLD 19 | 48 | #define QUADD_SAMPLE_VERSION_GROUP_SAMPLES 18 |
| 49 | #define QUADD_SAMPLE_VERSION_BT_UNWIND_TABLES 22 | 49 | #define QUADD_SAMPLE_VERSION_THREAD_STATE_FLD 19 |
| 50 | #define QUADD_SAMPLE_VERSION_SUPPORT_IP64 23 | 50 | #define QUADD_SAMPLE_VERSION_BT_UNWIND_TABLES 22 |
| 51 | #define QUADD_SAMPLE_VERSION_SPECIAL_MMAP 24 | 51 | #define QUADD_SAMPLE_VERSION_SUPPORT_IP64 23 |
| 52 | #define QUADD_SAMPLE_VERSION_UNWIND_MIXED 25 | 52 | #define QUADD_SAMPLE_VERSION_SPECIAL_MMAP 24 |
| 53 | #define QUADD_SAMPLE_VERSION_UNW_ENTRY_TYPE 26 | 53 | #define QUADD_SAMPLE_VERSION_UNWIND_MIXED 25 |
| 54 | #define QUADD_SAMPLE_VERSION_USE_ARCH_TIMER 27 | 54 | #define QUADD_SAMPLE_VERSION_UNW_ENTRY_TYPE 26 |
| 55 | #define QUADD_SAMPLE_VERSION_SCHED_SAMPLES 28 | 55 | #define QUADD_SAMPLE_VERSION_USE_ARCH_TIMER 27 |
| 56 | #define QUADD_SAMPLE_VERSION_HDR_UNW_METHOD 29 | 56 | #define QUADD_SAMPLE_VERSION_SCHED_SAMPLES 28 |
| 57 | #define QUADD_SAMPLE_VERSION_HDR_ARCH_TIMER 30 | 57 | #define QUADD_SAMPLE_VERSION_HDR_UNW_METHOD 29 |
| 58 | #define QUADD_SAMPLE_VERSION_STACK_OFFSET 31 | 58 | #define QUADD_SAMPLE_VERSION_HDR_ARCH_TIMER 30 |
| 59 | #define QUADD_SAMPLE_VERSION_SCHED_TASK_STATE 32 | 59 | #define QUADD_SAMPLE_VERSION_STACK_OFFSET 31 |
| 60 | #define QUADD_SAMPLE_VERSION_URCS 33 | 60 | #define QUADD_SAMPLE_VERSION_SCHED_TASK_STATE 32 |
| 61 | #define QUADD_SAMPLE_VERSION_HOTPLUG 34 | 61 | #define QUADD_SAMPLE_VERSION_URCS 33 |
| 62 | #define QUADD_SAMPLE_VERSION_PER_CPU_SETUP 35 | 62 | #define QUADD_SAMPLE_VERSION_HOTPLUG 34 |
| 63 | #define QUADD_SAMPLE_VERSION_REPORT_TGID 36 | 63 | #define QUADD_SAMPLE_VERSION_PER_CPU_SETUP 35 |
| 64 | #define QUADD_SAMPLE_VERSION_MMAP_TS 37 | 64 | #define QUADD_SAMPLE_VERSION_REPORT_TGID 36 |
| 65 | #define QUADD_SAMPLE_VERSION_RAW_EVENTS 38 | 65 | #define QUADD_SAMPLE_VERSION_MMAP_TS 37 |
| 66 | #define QUADD_SAMPLE_VERSION_OVERHEAD_INFO 39 | 66 | #define QUADD_SAMPLE_VERSION_RAW_EVENTS 38 |
| 67 | #define QUADD_SAMPLE_VERSION_REPORT_VPID 40 | 67 | #define QUADD_SAMPLE_VERSION_OVERHEAD_INFO 39 |
| 68 | #define QUADD_SAMPLE_VERSION_SCHED_REPORT_VPID 41 | 68 | #define QUADD_SAMPLE_VERSION_REPORT_VPID 40 |
| 69 | #define QUADD_SAMPLE_VERSION_SAMPLING_MODE 42 | 69 | #define QUADD_SAMPLE_VERSION_SCHED_REPORT_VPID 41 |
| 70 | 70 | #define QUADD_SAMPLE_VERSION_SAMPLING_MODE 42 | |
| 71 | #define QUADD_MMAP_HEADER_VERSION 1 | 71 | #define QUADD_SAMPLE_VERSION_SAMPLE_ALL_TASKS 43 |
| 72 | |||
| 73 | #define QUADD_MMAP_HEADER_VERSION 1 | ||
| 72 | 74 | ||
| 73 | #define QUADD_MAX_COUNTERS 32 | 75 | #define QUADD_MAX_COUNTERS 32 |
| 74 | #define QUADD_MAX_PROCESS 64 | 76 | #define QUADD_MAX_PROCESS 64 |
| @@ -359,6 +361,10 @@ struct quadd_debug_data { | |||
| 359 | #define QUADD_HDR_HAS_CPUID (1 << 6) | 361 | #define QUADD_HDR_HAS_CPUID (1 << 6) |
| 360 | #define QUADD_HDR_MODE_TRACE_ALL (1 << 7) | 362 | #define QUADD_HDR_MODE_TRACE_ALL (1 << 7) |
| 361 | #define QUADD_HDR_MODE_SAMPLING (1 << 8) | 363 | #define QUADD_HDR_MODE_SAMPLING (1 << 8) |
| 364 | #define QUADD_HDR_MODE_TRACING (1 << 9) | ||
| 365 | #define QUADD_HDR_MODE_SAMPLE_ALL (1 << 10) | ||
| 366 | #define QUADD_HDR_MODE_SAMPLE_TREE (1 << 11) | ||
| 367 | #define QUADD_HDR_MODE_TRACE_TREE (1 << 12) | ||
| 362 | 368 | ||
| 363 | struct quadd_header_data { | 369 | struct quadd_header_data { |
| 364 | u16 magic; | 370 | u16 magic; |
| @@ -419,6 +425,10 @@ enum { | |||
| 419 | #define QUADD_PARAM_EXTRA_PER_PMU_SETUP (1 << 8) | 425 | #define QUADD_PARAM_EXTRA_PER_PMU_SETUP (1 << 8) |
| 420 | #define QUADD_PARAM_EXTRA_SAMPLING (1 << 9) | 426 | #define QUADD_PARAM_EXTRA_SAMPLING (1 << 9) |
| 421 | #define QUADD_PARAM_EXTRA_FORCE_ARCH_TIMER (1 << 10) | 427 | #define QUADD_PARAM_EXTRA_FORCE_ARCH_TIMER (1 << 10) |
| 428 | #define QUADD_PARAM_EXTRA_SAMPLE_ALL_TASKS (1 << 11) | ||
| 429 | #define QUADD_PARAM_EXTRA_SAMPLE_TREE (1 << 12) | ||
| 430 | #define QUADD_PARAM_EXTRA_TRACING (1 << 13) | ||
| 431 | #define QUADD_PARAM_EXTRA_TRACE_TREE (1 << 14) | ||
| 422 | 432 | ||
| 423 | enum { | 433 | enum { |
| 424 | QUADD_EVENT_TYPE_RAW = 0, | 434 | QUADD_EVENT_TYPE_RAW = 0, |
