diff options
Diffstat (limited to 'tools/perf/util/event.c')
-rw-r--r-- | tools/perf/util/event.c | 163 |
1 files changed, 132 insertions, 31 deletions
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 10366b87d0b5..47eff4767edb 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -678,23 +678,21 @@ out: | |||
678 | return err; | 678 | return err; |
679 | } | 679 | } |
680 | 680 | ||
681 | int perf_event__synthesize_threads(struct perf_tool *tool, | 681 | static int __perf_event__synthesize_threads(struct perf_tool *tool, |
682 | perf_event__handler_t process, | 682 | perf_event__handler_t process, |
683 | struct machine *machine, | 683 | struct machine *machine, |
684 | bool mmap_data, | 684 | bool mmap_data, |
685 | unsigned int proc_map_timeout) | 685 | unsigned int proc_map_timeout, |
686 | struct dirent **dirent, | ||
687 | int start, | ||
688 | int num) | ||
686 | { | 689 | { |
687 | union perf_event *comm_event, *mmap_event, *fork_event; | 690 | union perf_event *comm_event, *mmap_event, *fork_event; |
688 | union perf_event *namespaces_event; | 691 | union perf_event *namespaces_event; |
689 | char proc_path[PATH_MAX]; | ||
690 | struct dirent **dirent; | ||
691 | int err = -1; | 692 | int err = -1; |
692 | char *end; | 693 | char *end; |
693 | pid_t pid; | 694 | pid_t pid; |
694 | int n, i; | 695 | int i; |
695 | |||
696 | if (machine__is_default_guest(machine)) | ||
697 | return 0; | ||
698 | 696 | ||
699 | comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); | 697 | comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); |
700 | if (comm_event == NULL) | 698 | if (comm_event == NULL) |
@@ -714,34 +712,25 @@ int perf_event__synthesize_threads(struct perf_tool *tool, | |||
714 | if (namespaces_event == NULL) | 712 | if (namespaces_event == NULL) |
715 | goto out_free_fork; | 713 | goto out_free_fork; |
716 | 714 | ||
717 | snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir); | 715 | for (i = start; i < start + num; i++) { |
718 | n = scandir(proc_path, &dirent, 0, alphasort); | ||
719 | |||
720 | if (n < 0) | ||
721 | goto out_free_namespaces; | ||
722 | |||
723 | for (i = 0; i < n; i++) { | ||
724 | if (!isdigit(dirent[i]->d_name[0])) | 716 | if (!isdigit(dirent[i]->d_name[0])) |
725 | continue; | 717 | continue; |
726 | 718 | ||
727 | pid = (pid_t)strtol(dirent[i]->d_name, &end, 10); | 719 | pid = (pid_t)strtol(dirent[i]->d_name, &end, 10); |
728 | /* only interested in proper numerical dirents */ | 720 | /* only interested in proper numerical dirents */ |
729 | if (!*end) { | 721 | if (*end) |
730 | /* | 722 | continue; |
731 | * We may race with exiting thread, so don't stop just because | 723 | /* |
732 | * one thread couldn't be synthesized. | 724 | * We may race with exiting thread, so don't stop just because |
733 | */ | 725 | * one thread couldn't be synthesized. |
734 | __event__synthesize_thread(comm_event, mmap_event, fork_event, | 726 | */ |
735 | namespaces_event, pid, 1, process, | 727 | __event__synthesize_thread(comm_event, mmap_event, fork_event, |
736 | tool, machine, mmap_data, | 728 | namespaces_event, pid, 1, process, |
737 | proc_map_timeout); | 729 | tool, machine, mmap_data, |
738 | } | 730 | proc_map_timeout); |
739 | free(dirent[i]); | ||
740 | } | 731 | } |
741 | free(dirent); | ||
742 | err = 0; | 732 | err = 0; |
743 | 733 | ||
744 | out_free_namespaces: | ||
745 | free(namespaces_event); | 734 | free(namespaces_event); |
746 | out_free_fork: | 735 | out_free_fork: |
747 | free(fork_event); | 736 | free(fork_event); |
@@ -753,6 +742,118 @@ out: | |||
753 | return err; | 742 | return err; |
754 | } | 743 | } |
755 | 744 | ||
745 | struct synthesize_threads_arg { | ||
746 | struct perf_tool *tool; | ||
747 | perf_event__handler_t process; | ||
748 | struct machine *machine; | ||
749 | bool mmap_data; | ||
750 | unsigned int proc_map_timeout; | ||
751 | struct dirent **dirent; | ||
752 | int num; | ||
753 | int start; | ||
754 | }; | ||
755 | |||
756 | static void *synthesize_threads_worker(void *arg) | ||
757 | { | ||
758 | struct synthesize_threads_arg *args = arg; | ||
759 | |||
760 | __perf_event__synthesize_threads(args->tool, args->process, | ||
761 | args->machine, args->mmap_data, | ||
762 | args->proc_map_timeout, args->dirent, | ||
763 | args->start, args->num); | ||
764 | return NULL; | ||
765 | } | ||
766 | |||
767 | int perf_event__synthesize_threads(struct perf_tool *tool, | ||
768 | perf_event__handler_t process, | ||
769 | struct machine *machine, | ||
770 | bool mmap_data, | ||
771 | unsigned int proc_map_timeout, | ||
772 | unsigned int nr_threads_synthesize) | ||
773 | { | ||
774 | struct synthesize_threads_arg *args = NULL; | ||
775 | pthread_t *synthesize_threads = NULL; | ||
776 | char proc_path[PATH_MAX]; | ||
777 | struct dirent **dirent; | ||
778 | int num_per_thread; | ||
779 | int m, n, i, j; | ||
780 | int thread_nr; | ||
781 | int base = 0; | ||
782 | int err = -1; | ||
783 | |||
784 | |||
785 | if (machine__is_default_guest(machine)) | ||
786 | return 0; | ||
787 | |||
788 | snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir); | ||
789 | n = scandir(proc_path, &dirent, 0, alphasort); | ||
790 | if (n < 0) | ||
791 | return err; | ||
792 | |||
793 | if (nr_threads_synthesize == UINT_MAX) | ||
794 | thread_nr = sysconf(_SC_NPROCESSORS_ONLN); | ||
795 | else | ||
796 | thread_nr = nr_threads_synthesize; | ||
797 | |||
798 | if (thread_nr <= 1) { | ||
799 | err = __perf_event__synthesize_threads(tool, process, | ||
800 | machine, mmap_data, | ||
801 | proc_map_timeout, | ||
802 | dirent, base, n); | ||
803 | goto free_dirent; | ||
804 | } | ||
805 | if (thread_nr > n) | ||
806 | thread_nr = n; | ||
807 | |||
808 | synthesize_threads = calloc(sizeof(pthread_t), thread_nr); | ||
809 | if (synthesize_threads == NULL) | ||
810 | goto free_dirent; | ||
811 | |||
812 | args = calloc(sizeof(*args), thread_nr); | ||
813 | if (args == NULL) | ||
814 | goto free_threads; | ||
815 | |||
816 | num_per_thread = n / thread_nr; | ||
817 | m = n % thread_nr; | ||
818 | for (i = 0; i < thread_nr; i++) { | ||
819 | args[i].tool = tool; | ||
820 | args[i].process = process; | ||
821 | args[i].machine = machine; | ||
822 | args[i].mmap_data = mmap_data; | ||
823 | args[i].proc_map_timeout = proc_map_timeout; | ||
824 | args[i].dirent = dirent; | ||
825 | } | ||
826 | for (i = 0; i < m; i++) { | ||
827 | args[i].num = num_per_thread + 1; | ||
828 | args[i].start = i * args[i].num; | ||
829 | } | ||
830 | if (i != 0) | ||
831 | base = args[i-1].start + args[i-1].num; | ||
832 | for (j = i; j < thread_nr; j++) { | ||
833 | args[j].num = num_per_thread; | ||
834 | args[j].start = base + (j - i) * args[i].num; | ||
835 | } | ||
836 | |||
837 | for (i = 0; i < thread_nr; i++) { | ||
838 | if (pthread_create(&synthesize_threads[i], NULL, | ||
839 | synthesize_threads_worker, &args[i])) | ||
840 | goto out_join; | ||
841 | } | ||
842 | err = 0; | ||
843 | out_join: | ||
844 | for (i = 0; i < thread_nr; i++) | ||
845 | pthread_join(synthesize_threads[i], NULL); | ||
846 | free(args); | ||
847 | free_threads: | ||
848 | free(synthesize_threads); | ||
849 | free_dirent: | ||
850 | for (i = 0; i < n; i++) | ||
851 | free(dirent[i]); | ||
852 | free(dirent); | ||
853 | |||
854 | return err; | ||
855 | } | ||
856 | |||
756 | struct process_symbol_args { | 857 | struct process_symbol_args { |
757 | const char *name; | 858 | const char *name; |
758 | u64 start; | 859 | u64 start; |