Commit 3aadb65d authored by Tomas Glozar's avatar Tomas Glozar Committed by Steven Rostedt (Google)
Browse files

rtla/timerlat: Add action on end feature

Implement actions on end next to actions on threshold. A new option,
--on-end is added, parallel to --on-threshold. Instead of being
executed whenever a latency threshold is reached, it is executed at the
end of the measurement.

For example:

$ rtla timerlat hist -d 5s --on-end trace

will save the trace output at the end.

All actions supported by --on-threshold are also supported by --on-end,
except for continue, which does nothing with --on-end.

Cc: John Kacur <jkacur@redhat.com>
Cc: Luis Goncalves <lgoncalv@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Chang Yin <cyin@redhat.com>
Cc: Costa Shulyupin <costa.shul@redhat.com>
Cc: Crystal Wood <crwood@redhat.com>
Cc: Gabriele Monaco <gmonaco@redhat.com>
Link: https://lore.kernel.org/20250626123405.1496931-6-tglozar@redhat.com


Signed-off-by: default avatarTomas Glozar <tglozar@redhat.com>
Signed-off-by: default avatarSteven Rostedt (Google) <rostedt@goodmis.org>
parent 8d933d5c
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -48,7 +48,10 @@ struct timerlat_params {
	struct sched_attr	sched_param;
	struct trace_events	*events;
	enum timerlat_tracing_mode mode;
	struct actions actions;

	struct actions threshold_actions;
	struct actions end_actions;

	union {
		struct {
			/* top only */
+30 −14
Original line number Diff line number Diff line
@@ -758,6 +758,7 @@ static void timerlat_hist_usage(char *usage)
		"	     --trace-buffer-size kB: set the per-cpu trace buffer size in kB",
		"	     --deepest-idle-state n: only go down to idle state n on cpus used by timerlat to reduce exit from idle latency",
		"	     --on-threshold <action>: define action to be executed at latency threshold, multiple are allowed",
		"	     --on-end <action>: define action to be executed at measurement end, multiple are allowed",
		NULL,
	};

@@ -793,7 +794,8 @@ static struct timerlat_params
	if (!params)
		exit(1);

	actions_init(&params->actions);
	actions_init(&params->threshold_actions);
	actions_init(&params->end_actions);

	/* disabled by default */
	params->dma_latency = -1;
@@ -846,6 +848,7 @@ static struct timerlat_params
			{"trace-buffer-size",	required_argument,	0, '\3'},
			{"deepest-idle-state",	required_argument,	0, '\4'},
			{"on-threshold",	required_argument,	0, '\5'},
			{"on-end",		required_argument,	0, '\6'},
			{0, 0, 0, 0}
		};

@@ -1038,7 +1041,14 @@ static struct timerlat_params
			params->deepest_idle_state = get_llong_from_str(optarg);
			break;
		case '\5':
			retval = actions_parse(&params->actions, optarg);
			retval = actions_parse(&params->threshold_actions, optarg);
			if (retval) {
				err_msg("Invalid action %s\n", optarg);
				exit(EXIT_FAILURE);
			}
			break;
		case '\6':
			retval = actions_parse(&params->end_actions, optarg);
			if (retval) {
				err_msg("Invalid action %s\n", optarg);
				exit(EXIT_FAILURE);
@@ -1050,7 +1060,7 @@ static struct timerlat_params
	}

	if (trace_output)
		actions_add_trace_output(&params->actions, trace_output);
		actions_add_trace_output(&params->threshold_actions, trace_output);

	if (geteuid()) {
		err_msg("rtla needs root permission\n");
@@ -1077,7 +1087,8 @@ static struct timerlat_params
	 * mixed mode
	 */
	if (params->mode == TRACING_MODE_BPF &&
	    (params->actions.present[ACTION_TRACE_OUTPUT] || !params->no_aa))
	    (params->threshold_actions.present[ACTION_TRACE_OUTPUT] ||
	     params->end_actions.present[ACTION_TRACE_OUTPUT] || !params->no_aa))
		params->mode = TRACING_MODE_MIXED;

	return params;
@@ -1270,13 +1281,15 @@ int timerlat_hist_main(int argc, char *argv[])
		}
	}

	if (params->actions.present[ACTION_TRACE_OUTPUT]) {
	if (params->threshold_actions.present[ACTION_TRACE_OUTPUT] ||
	    params->end_actions.present[ACTION_TRACE_OUTPUT]) {
		record = osnoise_init_trace_tool("timerlat");
		if (!record) {
			err_msg("Failed to enable the trace instance\n");
			goto out_free;
		}
		params->actions.trace_output_inst = record->trace.inst;
		params->threshold_actions.trace_output_inst = record->trace.inst;
		params->end_actions.trace_output_inst = record->trace.inst;

		if (params->events) {
			retval = trace_events_enable(&record->trace, params->events);
@@ -1342,7 +1355,7 @@ int timerlat_hist_main(int argc, char *argv[])
	 * tracing while enabling other instances. The trace instance is the
	 * one with most valuable information.
	 */
	if (params->actions.present[ACTION_TRACE_OUTPUT])
	if (record)
		trace_instance_start(&record->trace);
	if (!params->no_aa)
		trace_instance_start(&aa->trace);
@@ -1375,14 +1388,14 @@ int timerlat_hist_main(int argc, char *argv[])
			}

			if (osnoise_trace_is_off(tool, record)) {
				actions_perform(&params->actions);
				actions_perform(&params->threshold_actions);

				if (!params->actions.continue_flag)
				if (!params->threshold_actions.continue_flag)
					/* continue flag not set, break */
					break;

				/* continue action reached, re-enable tracing */
				if (params->actions.present[ACTION_TRACE_OUTPUT])
				if (record)
					trace_instance_start(&record->trace);
				if (!params->no_aa)
					trace_instance_start(&aa->trace);
@@ -1403,14 +1416,14 @@ int timerlat_hist_main(int argc, char *argv[])

			if (!stop_tracing) {
				/* Threshold overflow, perform actions on threshold */
				actions_perform(&params->actions);
				actions_perform(&params->threshold_actions);

				if (!params->actions.continue_flag)
				if (!params->threshold_actions.continue_flag)
					/* continue flag not set, break */
					break;

				/* continue action reached, re-enable tracing */
				if (params->actions.present[ACTION_TRACE_OUTPUT])
				if (record)
					trace_instance_start(&record->trace);
				if (!params->no_aa)
					trace_instance_start(&aa->trace);
@@ -1435,6 +1448,8 @@ int timerlat_hist_main(int argc, char *argv[])

	timerlat_print_stats(params, tool);

	actions_perform(&params->end_actions);

	return_value = PASSED;

	if (osnoise_trace_is_off(tool, record) && !stop_tracing) {
@@ -1464,7 +1479,8 @@ int timerlat_hist_main(int argc, char *argv[])
	osnoise_destroy_tool(aa);
	osnoise_destroy_tool(record);
	osnoise_destroy_tool(tool);
	actions_destroy(&params->actions);
	actions_destroy(&params->threshold_actions);
	actions_destroy(&params->end_actions);
	if (params->mode != TRACING_MODE_TRACEFS)
		timerlat_bpf_destroy();
	free(params);
+31 −14
Original line number Diff line number Diff line
@@ -517,6 +517,7 @@ static void timerlat_top_usage(char *usage)
		"	     --trace-buffer-size kB: set the per-cpu trace buffer size in kB",
		"	     --deepest-idle-state n: only go down to idle state n on cpus used by timerlat to reduce exit from idle latency",
		"	     --on-threshold <action>: define action to be executed at latency threshold, multiple are allowed",
		"	     --on-end: define action to be executed at measurement end, multiple are allowed",
		NULL,
	};

@@ -552,7 +553,8 @@ static struct timerlat_params
	if (!params)
		exit(1);

	actions_init(&params->actions);
	actions_init(&params->threshold_actions);
	actions_init(&params->end_actions);

	/* disabled by default */
	params->dma_latency = -1;
@@ -597,6 +599,7 @@ static struct timerlat_params
			{"trace-buffer-size",	required_argument,	0, '7'},
			{"deepest-idle-state",	required_argument,	0, '8'},
			{"on-threshold",	required_argument,	0, '9'},
			{"on-end",		required_argument,	0, '\1'},
			{0, 0, 0, 0}
		};

@@ -623,6 +626,7 @@ static struct timerlat_params

			/* set trace */
			trace_output = "timerlat_trace.txt";

			break;
		case '5':
			/* it is here because it is similar to -a */
@@ -776,7 +780,14 @@ static struct timerlat_params
			params->deepest_idle_state = get_llong_from_str(optarg);
			break;
		case '9':
			retval = actions_parse(&params->actions, optarg);
			retval = actions_parse(&params->threshold_actions, optarg);
			if (retval) {
				err_msg("Invalid action %s\n", optarg);
				exit(EXIT_FAILURE);
			}
			break;
		case '\1':
			retval = actions_parse(&params->end_actions, optarg);
			if (retval) {
				err_msg("Invalid action %s\n", optarg);
				exit(EXIT_FAILURE);
@@ -788,7 +799,7 @@ static struct timerlat_params
	}

	if (trace_output)
		actions_add_trace_output(&params->actions, trace_output);
		actions_add_trace_output(&params->threshold_actions, trace_output);

	if (geteuid()) {
		err_msg("rtla needs root permission\n");
@@ -812,7 +823,8 @@ static struct timerlat_params
	 * mixed mode
	 */
	if (params->mode == TRACING_MODE_BPF &&
	    (params->actions.present[ACTION_TRACE_OUTPUT] || !params->no_aa))
	    (params->threshold_actions.present[ACTION_TRACE_OUTPUT] ||
	     params->end_actions.present[ACTION_TRACE_OUTPUT] || !params->no_aa))
		params->mode = TRACING_MODE_MIXED;

	return params;
@@ -934,14 +946,14 @@ timerlat_top_main_loop(struct osnoise_tool *top,
			timerlat_print_stats(params, top);

		if (osnoise_trace_is_off(top, record)) {
			actions_perform(&params->actions);
			actions_perform(&params->threshold_actions);

			if (!params->actions.continue_flag)
			if (!params->threshold_actions.continue_flag)
				/* continue flag not set, break */
				break;

			/* continue action reached, re-enable tracing */
			if (params->actions.present[ACTION_TRACE_OUTPUT])
			if (record)
				trace_instance_start(&record->trace);
			if (!params->no_aa)
				trace_instance_start(&aa->trace);
@@ -993,14 +1005,14 @@ timerlat_top_bpf_main_loop(struct osnoise_tool *top,

		if (wait_retval == 1) {
			/* Stopping requested by tracer */
			actions_perform(&params->actions);
			actions_perform(&params->threshold_actions);

			if (!params->actions.continue_flag)
			if (!params->threshold_actions.continue_flag)
				/* continue flag not set, break */
				break;

			/* continue action reached, re-enable tracing */
			if (params->actions.present[ACTION_TRACE_OUTPUT])
			if (record)
				trace_instance_start(&record->trace);
			if (!params->no_aa)
				trace_instance_start(&aa->trace);
@@ -1128,13 +1140,15 @@ int timerlat_top_main(int argc, char *argv[])
		}
	}

	if (params->actions.present[ACTION_TRACE_OUTPUT]) {
	if (params->threshold_actions.present[ACTION_TRACE_OUTPUT] ||
	    params->end_actions.present[ACTION_TRACE_OUTPUT]) {
		record = osnoise_init_trace_tool("timerlat");
		if (!record) {
			err_msg("Failed to enable the trace instance\n");
			goto out_free;
		}
		params->actions.trace_output_inst = record->trace.inst;
		params->threshold_actions.trace_output_inst = record->trace.inst;
		params->end_actions.trace_output_inst = record->trace.inst;

		if (params->events) {
			retval = trace_events_enable(&record->trace, params->events);
@@ -1201,7 +1215,7 @@ int timerlat_top_main(int argc, char *argv[])
	 * tracing while enabling other instances. The trace instance is the
	 * one with most valuable information.
	 */
	if (params->actions.present[ACTION_TRACE_OUTPUT])
	if (record)
		trace_instance_start(&record->trace);
	if (!params->no_aa)
		trace_instance_start(&aa->trace);
@@ -1236,6 +1250,8 @@ int timerlat_top_main(int argc, char *argv[])

	timerlat_print_stats(params, top);

	actions_perform(&params->end_actions);

	return_value = PASSED;

	if (osnoise_trace_is_off(top, record) && !stop_tracing) {
@@ -1276,7 +1292,8 @@ int timerlat_top_main(int argc, char *argv[])
		osnoise_destroy_tool(aa);
	osnoise_destroy_tool(record);
	osnoise_destroy_tool(top);
	actions_destroy(&params->actions);
	actions_destroy(&params->threshold_actions);
	actions_destroy(&params->end_actions);
	if (params->mode != TRACING_MODE_TRACEFS)
		timerlat_bpf_destroy();
	free(params);