Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rtla/timerlat: Give timerlat auto analysis its own instance

Currently, the auto-analysis is attached to the timerlat top instance.
The idea was to avoid creating another instance just for that, so one
instance could be reused.

The drawback is that, by doing so, the auto-analysis run for the entire
session, consuming CPU time. On my 24 box CPUs for timerlat with a 100
us period consumed 50 % with auto analysis, but only 16 % without.

By creating an instance for auto-analysis, we can keep the processing
stopped until a stop tracing condition is hit. Once it happens,
timerlat auto-analysis can use its own trace instance to parse only
the end of the trace.

By doing so, auto-analysis stop consuming cpu time when it is not
needed.

If the --aa-only is passed, the timerlat top instance is reused for
auto analysis.

Link: https://lkml.kernel.org/r/346b7168c1bae552a415715ec6d23c129a43bdb7.1686066600.git.bristot@kernel.org

Cc: William White <chwhite@redhat.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Tested-by: Juri Lelli <juri.lelli@redhat.com>
Signed-off-by: Daniel Bristot de Oliveira <bristot@kernel.org>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>

authored by

Daniel Bristot de Oliveira and committed by
Steven Rostedt (Google)
c66552be c58a3f8c

+67 -21
+33 -2
tools/tracing/rtla/src/timerlat_aa.c
··· 8 8 #include "utils.h" 9 9 #include "osnoise.h" 10 10 #include "timerlat.h" 11 + #include <unistd.h> 11 12 12 13 enum timelat_state { 13 14 TIMERLAT_INIT = 0, ··· 234 233 * 235 234 * Returns 0 on success, -1 otherwise. 236 235 */ 237 - int timerlat_aa_handler(struct trace_seq *s, struct tep_record *record, 236 + static int timerlat_aa_handler(struct trace_seq *s, struct tep_record *record, 238 237 struct tep_event *event, void *context) 239 238 { 240 239 struct timerlat_aa_context *taa_ctx = timerlat_aa_get_ctx(); ··· 666 665 ns_to_usf(total)); 667 666 } 668 667 668 + static int timerlat_auto_analysis_collect_trace(struct timerlat_aa_context *taa_ctx) 669 + { 670 + struct trace_instance *trace = &taa_ctx->tool->trace; 671 + int retval; 672 + 673 + retval = tracefs_iterate_raw_events(trace->tep, 674 + trace->inst, 675 + NULL, 676 + 0, 677 + collect_registered_events, 678 + trace); 679 + if (retval < 0) { 680 + err_msg("Error iterating on events\n"); 681 + return 0; 682 + } 683 + 684 + return 1; 685 + } 686 + 669 687 /** 670 688 * timerlat_auto_analysis - Analyze the collected data 671 689 */ ··· 696 676 int max_exit_from_idle_cpu; 697 677 struct tep_handle *tep; 698 678 int cpu; 679 + 680 + timerlat_auto_analysis_collect_trace(taa_ctx); 699 681 700 682 /* bring stop tracing to the ns scale */ 701 683 irq_thresh = irq_thresh * 1000; ··· 860 838 */ 861 839 static void timerlat_aa_unregister_events(struct osnoise_tool *tool, int dump_tasks) 862 840 { 841 + 842 + tep_unregister_event_handler(tool->trace.tep, -1, "ftrace", "timerlat", 843 + timerlat_aa_handler, tool); 844 + 863 845 tracefs_event_disable(tool->trace.inst, "osnoise", NULL); 864 846 865 847 tep_unregister_event_handler(tool->trace.tep, -1, "osnoise", "nmi_noise", ··· 900 874 static int timerlat_aa_register_events(struct osnoise_tool *tool, int dump_tasks) 901 875 { 902 876 int retval; 877 + 878 + tep_register_event_handler(tool->trace.tep, -1, "ftrace", "timerlat", 879 + timerlat_aa_handler, tool); 880 + 903 881 904 882 /* 905 883 * register auto-analysis handlers. ··· 985 955 * 986 956 * Returns 0 on success, -1 otherwise. 987 957 */ 988 - int timerlat_aa_init(struct osnoise_tool *tool, int nr_cpus, int dump_tasks) 958 + int timerlat_aa_init(struct osnoise_tool *tool, int dump_tasks) 989 959 { 960 + int nr_cpus = sysconf(_SC_NPROCESSORS_CONF); 990 961 struct timerlat_aa_context *taa_ctx; 991 962 int retval; 992 963
+1 -4
tools/tracing/rtla/src/timerlat_aa.h
··· 3 3 * Copyright (C) 2023 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org> 4 4 */ 5 5 6 - int timerlat_aa_init(struct osnoise_tool *tool, int nr_cpus, int dump_task); 6 + int timerlat_aa_init(struct osnoise_tool *tool, int dump_task); 7 7 void timerlat_aa_destroy(void); 8 - 9 - int timerlat_aa_handler(struct trace_seq *s, struct tep_record *record, 10 - struct tep_event *event, void *context); 11 8 12 9 void timerlat_auto_analysis(int irq_thresh, int thread_thresh);
+33 -15
tools/tracing/rtla/src/timerlat_top.c
··· 156 156 timerlat_top_update(top, cpu, thread, latency); 157 157 } 158 158 159 - if (!params->no_aa) 160 - timerlat_aa_handler(s, record, event, context); 161 - 162 159 return 0; 163 160 } 164 161 ··· 641 644 { 642 645 struct osnoise_tool *top; 643 646 int nr_cpus; 644 - int retval; 645 647 646 648 nr_cpus = sysconf(_SC_NPROCESSORS_CONF); 647 649 ··· 656 660 657 661 tep_register_event_handler(top->trace.tep, -1, "ftrace", "timerlat", 658 662 timerlat_top_handler, top); 659 - 660 - /* 661 - * If no auto analysis, we are ready. 662 - */ 663 - if (params->no_aa) 664 - return top; 665 - 666 - retval = timerlat_aa_init(top, nr_cpus, params->dump_tasks); 667 - if (retval) 668 - goto out_err; 669 663 670 664 return top; 671 665 ··· 688 702 struct timerlat_top_params *params; 689 703 struct osnoise_tool *record = NULL; 690 704 struct osnoise_tool *top = NULL; 705 + struct osnoise_tool *aa = NULL; 691 706 struct trace_instance *trace; 692 707 int dma_latency_fd = -1; 693 708 int return_value = 1; ··· 761 774 trace_instance_start(&record->trace); 762 775 } 763 776 777 + if (!params->no_aa) { 778 + if (params->aa_only) { 779 + /* as top is not used for display, use it for aa */ 780 + aa = top; 781 + } else { 782 + /* otherwise, a new instance is needed */ 783 + aa = osnoise_init_tool("timerlat_aa"); 784 + if (!aa) 785 + goto out_top; 786 + } 787 + 788 + retval = timerlat_aa_init(aa, params->dump_tasks); 789 + if (retval) { 790 + err_msg("Failed to enable the auto analysis instance\n"); 791 + goto out_top; 792 + } 793 + 794 + /* if it is re-using the main instance, there is no need to start it */ 795 + if (aa != top) { 796 + retval = enable_timerlat(&aa->trace); 797 + if (retval) { 798 + err_msg("Failed to enable timerlat tracer\n"); 799 + goto out_top; 800 + } 801 + 802 + trace_instance_start(&aa->trace); 803 + } 804 + } 805 + 764 806 top->start_time = time(NULL); 765 807 timerlat_top_set_signals(params); 766 808 ··· 845 829 } 846 830 847 831 out_top: 832 + timerlat_aa_destroy(); 848 833 if (dma_latency_fd >= 0) 849 834 close(dma_latency_fd); 850 835 trace_events_destroy(&record->trace, params->events); 851 836 params->events = NULL; 852 837 out_free: 853 838 timerlat_free_top(top->data); 854 - timerlat_aa_destroy(); 839 + if (aa && aa != top) 840 + osnoise_destroy_tool(aa); 855 841 osnoise_destroy_tool(record); 856 842 osnoise_destroy_tool(top); 857 843 free(params);