162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2021 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org> 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#define _GNU_SOURCE 762306a36Sopenharmony_ci#include <getopt.h> 862306a36Sopenharmony_ci#include <stdlib.h> 962306a36Sopenharmony_ci#include <string.h> 1062306a36Sopenharmony_ci#include <signal.h> 1162306a36Sopenharmony_ci#include <unistd.h> 1262306a36Sopenharmony_ci#include <stdio.h> 1362306a36Sopenharmony_ci#include <time.h> 1462306a36Sopenharmony_ci#include <sched.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "osnoise.h" 1762306a36Sopenharmony_ci#include "utils.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cienum osnoise_mode { 2062306a36Sopenharmony_ci MODE_OSNOISE = 0, 2162306a36Sopenharmony_ci MODE_HWNOISE 2262306a36Sopenharmony_ci}; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* 2562306a36Sopenharmony_ci * osnoise top parameters 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_cistruct osnoise_top_params { 2862306a36Sopenharmony_ci char *cpus; 2962306a36Sopenharmony_ci cpu_set_t monitored_cpus; 3062306a36Sopenharmony_ci char *trace_output; 3162306a36Sopenharmony_ci char *cgroup_name; 3262306a36Sopenharmony_ci unsigned long long runtime; 3362306a36Sopenharmony_ci unsigned long long period; 3462306a36Sopenharmony_ci long long threshold; 3562306a36Sopenharmony_ci long long stop_us; 3662306a36Sopenharmony_ci long long stop_total_us; 3762306a36Sopenharmony_ci int sleep_time; 3862306a36Sopenharmony_ci int duration; 3962306a36Sopenharmony_ci int quiet; 4062306a36Sopenharmony_ci int set_sched; 4162306a36Sopenharmony_ci int cgroup; 4262306a36Sopenharmony_ci int hk_cpus; 4362306a36Sopenharmony_ci cpu_set_t hk_cpu_set; 4462306a36Sopenharmony_ci struct sched_attr sched_param; 4562306a36Sopenharmony_ci struct trace_events *events; 4662306a36Sopenharmony_ci enum osnoise_mode mode; 4762306a36Sopenharmony_ci}; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistruct osnoise_top_cpu { 5062306a36Sopenharmony_ci unsigned long long sum_runtime; 5162306a36Sopenharmony_ci unsigned long long sum_noise; 5262306a36Sopenharmony_ci unsigned long long max_noise; 5362306a36Sopenharmony_ci unsigned long long max_sample; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci unsigned long long hw_count; 5662306a36Sopenharmony_ci unsigned long long nmi_count; 5762306a36Sopenharmony_ci unsigned long long irq_count; 5862306a36Sopenharmony_ci unsigned long long softirq_count; 5962306a36Sopenharmony_ci unsigned long long thread_count; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci int sum_cycles; 6262306a36Sopenharmony_ci}; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistruct osnoise_top_data { 6562306a36Sopenharmony_ci struct osnoise_top_cpu *cpu_data; 6662306a36Sopenharmony_ci int nr_cpus; 6762306a36Sopenharmony_ci}; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* 7062306a36Sopenharmony_ci * osnoise_free_top - free runtime data 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_cistatic void 7362306a36Sopenharmony_ciosnoise_free_top(struct osnoise_top_data *data) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci free(data->cpu_data); 7662306a36Sopenharmony_ci free(data); 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/* 8062306a36Sopenharmony_ci * osnoise_alloc_histogram - alloc runtime data 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_cistatic struct osnoise_top_data *osnoise_alloc_top(int nr_cpus) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci struct osnoise_top_data *data; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci data = calloc(1, sizeof(*data)); 8762306a36Sopenharmony_ci if (!data) 8862306a36Sopenharmony_ci return NULL; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci data->nr_cpus = nr_cpus; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci /* one set of histograms per CPU */ 9362306a36Sopenharmony_ci data->cpu_data = calloc(1, sizeof(*data->cpu_data) * nr_cpus); 9462306a36Sopenharmony_ci if (!data->cpu_data) 9562306a36Sopenharmony_ci goto cleanup; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci return data; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cicleanup: 10062306a36Sopenharmony_ci osnoise_free_top(data); 10162306a36Sopenharmony_ci return NULL; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* 10562306a36Sopenharmony_ci * osnoise_top_handler - this is the handler for osnoise tracer events 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_cistatic int 10862306a36Sopenharmony_ciosnoise_top_handler(struct trace_seq *s, struct tep_record *record, 10962306a36Sopenharmony_ci struct tep_event *event, void *context) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct trace_instance *trace = context; 11262306a36Sopenharmony_ci struct osnoise_tool *tool; 11362306a36Sopenharmony_ci unsigned long long val; 11462306a36Sopenharmony_ci struct osnoise_top_cpu *cpu_data; 11562306a36Sopenharmony_ci struct osnoise_top_data *data; 11662306a36Sopenharmony_ci int cpu = record->cpu; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci tool = container_of(trace, struct osnoise_tool, trace); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci data = tool->data; 12162306a36Sopenharmony_ci cpu_data = &data->cpu_data[cpu]; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci cpu_data->sum_cycles++; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci tep_get_field_val(s, event, "runtime", record, &val, 1); 12662306a36Sopenharmony_ci update_sum(&cpu_data->sum_runtime, &val); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci tep_get_field_val(s, event, "noise", record, &val, 1); 12962306a36Sopenharmony_ci update_max(&cpu_data->max_noise, &val); 13062306a36Sopenharmony_ci update_sum(&cpu_data->sum_noise, &val); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci tep_get_field_val(s, event, "max_sample", record, &val, 1); 13362306a36Sopenharmony_ci update_max(&cpu_data->max_sample, &val); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci tep_get_field_val(s, event, "hw_count", record, &val, 1); 13662306a36Sopenharmony_ci update_sum(&cpu_data->hw_count, &val); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci tep_get_field_val(s, event, "nmi_count", record, &val, 1); 13962306a36Sopenharmony_ci update_sum(&cpu_data->nmi_count, &val); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci tep_get_field_val(s, event, "irq_count", record, &val, 1); 14262306a36Sopenharmony_ci update_sum(&cpu_data->irq_count, &val); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci tep_get_field_val(s, event, "softirq_count", record, &val, 1); 14562306a36Sopenharmony_ci update_sum(&cpu_data->softirq_count, &val); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci tep_get_field_val(s, event, "thread_count", record, &val, 1); 14862306a36Sopenharmony_ci update_sum(&cpu_data->thread_count, &val); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci return 0; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci/* 15462306a36Sopenharmony_ci * osnoise_top_header - print the header of the tool output 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_cistatic void osnoise_top_header(struct osnoise_tool *top) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci struct osnoise_top_params *params = top->params; 15962306a36Sopenharmony_ci struct trace_seq *s = top->trace.seq; 16062306a36Sopenharmony_ci char duration[26]; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci get_duration(top->start_time, duration, sizeof(duration)); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci trace_seq_printf(s, "\033[2;37;40m"); 16562306a36Sopenharmony_ci trace_seq_printf(s, " "); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (params->mode == MODE_OSNOISE) { 16862306a36Sopenharmony_ci trace_seq_printf(s, "Operating System Noise"); 16962306a36Sopenharmony_ci trace_seq_printf(s, " "); 17062306a36Sopenharmony_ci } else if (params->mode == MODE_HWNOISE) { 17162306a36Sopenharmony_ci trace_seq_printf(s, "Hardware-related Noise"); 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci trace_seq_printf(s, " "); 17562306a36Sopenharmony_ci trace_seq_printf(s, "\033[0;0;0m"); 17662306a36Sopenharmony_ci trace_seq_printf(s, "\n"); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci trace_seq_printf(s, "duration: %9s | time is in us\n", duration); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci trace_seq_printf(s, "\033[2;30;47m"); 18162306a36Sopenharmony_ci trace_seq_printf(s, "CPU Period Runtime "); 18262306a36Sopenharmony_ci trace_seq_printf(s, " Noise "); 18362306a36Sopenharmony_ci trace_seq_printf(s, " %% CPU Aval "); 18462306a36Sopenharmony_ci trace_seq_printf(s, " Max Noise Max Single "); 18562306a36Sopenharmony_ci trace_seq_printf(s, " HW NMI"); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (params->mode == MODE_HWNOISE) 18862306a36Sopenharmony_ci goto eol; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci trace_seq_printf(s, " IRQ Softirq Thread"); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cieol: 19362306a36Sopenharmony_ci trace_seq_printf(s, "\033[0;0;0m"); 19462306a36Sopenharmony_ci trace_seq_printf(s, "\n"); 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci/* 19862306a36Sopenharmony_ci * clear_terminal - clears the output terminal 19962306a36Sopenharmony_ci */ 20062306a36Sopenharmony_cistatic void clear_terminal(struct trace_seq *seq) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci if (!config_debug) 20362306a36Sopenharmony_ci trace_seq_printf(seq, "\033c"); 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci/* 20762306a36Sopenharmony_ci * osnoise_top_print - prints the output of a given CPU 20862306a36Sopenharmony_ci */ 20962306a36Sopenharmony_cistatic void osnoise_top_print(struct osnoise_tool *tool, int cpu) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci struct osnoise_top_params *params = tool->params; 21262306a36Sopenharmony_ci struct trace_seq *s = tool->trace.seq; 21362306a36Sopenharmony_ci struct osnoise_top_cpu *cpu_data; 21462306a36Sopenharmony_ci struct osnoise_top_data *data; 21562306a36Sopenharmony_ci int percentage; 21662306a36Sopenharmony_ci int decimal; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci data = tool->data; 21962306a36Sopenharmony_ci cpu_data = &data->cpu_data[cpu]; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci if (!cpu_data->sum_runtime) 22262306a36Sopenharmony_ci return; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci percentage = ((cpu_data->sum_runtime - cpu_data->sum_noise) * 10000000) 22562306a36Sopenharmony_ci / cpu_data->sum_runtime; 22662306a36Sopenharmony_ci decimal = percentage % 100000; 22762306a36Sopenharmony_ci percentage = percentage / 100000; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci trace_seq_printf(s, "%3d #%-6d %12llu ", cpu, cpu_data->sum_cycles, cpu_data->sum_runtime); 23062306a36Sopenharmony_ci trace_seq_printf(s, "%12llu ", cpu_data->sum_noise); 23162306a36Sopenharmony_ci trace_seq_printf(s, " %3d.%05d", percentage, decimal); 23262306a36Sopenharmony_ci trace_seq_printf(s, "%12llu %12llu", cpu_data->max_noise, cpu_data->max_sample); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci trace_seq_printf(s, "%12llu ", cpu_data->hw_count); 23562306a36Sopenharmony_ci trace_seq_printf(s, "%12llu ", cpu_data->nmi_count); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci if (params->mode == MODE_HWNOISE) { 23862306a36Sopenharmony_ci trace_seq_printf(s, "\n"); 23962306a36Sopenharmony_ci return; 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci trace_seq_printf(s, "%12llu ", cpu_data->irq_count); 24362306a36Sopenharmony_ci trace_seq_printf(s, "%12llu ", cpu_data->softirq_count); 24462306a36Sopenharmony_ci trace_seq_printf(s, "%12llu\n", cpu_data->thread_count); 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci/* 24862306a36Sopenharmony_ci * osnoise_print_stats - print data for all cpus 24962306a36Sopenharmony_ci */ 25062306a36Sopenharmony_cistatic void 25162306a36Sopenharmony_ciosnoise_print_stats(struct osnoise_top_params *params, struct osnoise_tool *top) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci struct trace_instance *trace = &top->trace; 25462306a36Sopenharmony_ci static int nr_cpus = -1; 25562306a36Sopenharmony_ci int i; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci if (nr_cpus == -1) 25862306a36Sopenharmony_ci nr_cpus = sysconf(_SC_NPROCESSORS_CONF); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci if (!params->quiet) 26162306a36Sopenharmony_ci clear_terminal(trace->seq); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci osnoise_top_header(top); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci for (i = 0; i < nr_cpus; i++) { 26662306a36Sopenharmony_ci if (params->cpus && !CPU_ISSET(i, ¶ms->monitored_cpus)) 26762306a36Sopenharmony_ci continue; 26862306a36Sopenharmony_ci osnoise_top_print(top, i); 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci trace_seq_do_printf(trace->seq); 27262306a36Sopenharmony_ci trace_seq_reset(trace->seq); 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci/* 27662306a36Sopenharmony_ci * osnoise_top_usage - prints osnoise top usage message 27762306a36Sopenharmony_ci */ 27862306a36Sopenharmony_cistatic void osnoise_top_usage(struct osnoise_top_params *params, char *usage) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci int i; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci static const char * const msg[] = { 28362306a36Sopenharmony_ci " [-h] [-q] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\", 28462306a36Sopenharmony_ci " [-T us] [-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] \\", 28562306a36Sopenharmony_ci " [-c cpu-list] [-H cpu-list] [-P priority] [-C[=cgroup_name]]", 28662306a36Sopenharmony_ci "", 28762306a36Sopenharmony_ci " -h/--help: print this menu", 28862306a36Sopenharmony_ci " -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit", 28962306a36Sopenharmony_ci " -p/--period us: osnoise period in us", 29062306a36Sopenharmony_ci " -r/--runtime us: osnoise runtime in us", 29162306a36Sopenharmony_ci " -s/--stop us: stop trace if a single sample is higher than the argument in us", 29262306a36Sopenharmony_ci " -S/--stop-total us: stop trace if the total sample is higher than the argument in us", 29362306a36Sopenharmony_ci " -T/--threshold us: the minimum delta to be considered a noise", 29462306a36Sopenharmony_ci " -c/--cpus cpu-list: list of cpus to run osnoise threads", 29562306a36Sopenharmony_ci " -H/--house-keeping cpus: run rtla control threads only on the given cpus", 29662306a36Sopenharmony_ci " -C/--cgroup[=cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited", 29762306a36Sopenharmony_ci " -d/--duration time[s|m|h|d]: duration of the session", 29862306a36Sopenharmony_ci " -D/--debug: print debug info", 29962306a36Sopenharmony_ci " -t/--trace[=file]: save the stopped trace to [file|osnoise_trace.txt]", 30062306a36Sopenharmony_ci " -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed", 30162306a36Sopenharmony_ci " --filter <filter>: enable a trace event filter to the previous -e event", 30262306a36Sopenharmony_ci " --trigger <trigger>: enable a trace event trigger to the previous -e event", 30362306a36Sopenharmony_ci " -q/--quiet print only a summary at the end", 30462306a36Sopenharmony_ci " -P/--priority o:prio|r:prio|f:prio|d:runtime:period : set scheduling parameters", 30562306a36Sopenharmony_ci " o:prio - use SCHED_OTHER with prio", 30662306a36Sopenharmony_ci " r:prio - use SCHED_RR with prio", 30762306a36Sopenharmony_ci " f:prio - use SCHED_FIFO with prio", 30862306a36Sopenharmony_ci " d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period", 30962306a36Sopenharmony_ci " in nanoseconds", 31062306a36Sopenharmony_ci NULL, 31162306a36Sopenharmony_ci }; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci if (usage) 31462306a36Sopenharmony_ci fprintf(stderr, "%s\n", usage); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (params->mode == MODE_OSNOISE) { 31762306a36Sopenharmony_ci fprintf(stderr, 31862306a36Sopenharmony_ci "rtla osnoise top: a per-cpu summary of the OS noise (version %s)\n", 31962306a36Sopenharmony_ci VERSION); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci fprintf(stderr, " usage: rtla osnoise [top]"); 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (params->mode == MODE_HWNOISE) { 32562306a36Sopenharmony_ci fprintf(stderr, 32662306a36Sopenharmony_ci "rtla hwnoise: a summary of hardware-related noise (version %s)\n", 32762306a36Sopenharmony_ci VERSION); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci fprintf(stderr, " usage: rtla hwnoise"); 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci for (i = 0; msg[i]; i++) 33362306a36Sopenharmony_ci fprintf(stderr, "%s\n", msg[i]); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (usage) 33662306a36Sopenharmony_ci exit(EXIT_FAILURE); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci exit(EXIT_SUCCESS); 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci/* 34262306a36Sopenharmony_ci * osnoise_top_parse_args - allocs, parse and fill the cmd line parameters 34362306a36Sopenharmony_ci */ 34462306a36Sopenharmony_cistruct osnoise_top_params *osnoise_top_parse_args(int argc, char **argv) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci struct osnoise_top_params *params; 34762306a36Sopenharmony_ci struct trace_events *tevent; 34862306a36Sopenharmony_ci int retval; 34962306a36Sopenharmony_ci int c; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci params = calloc(1, sizeof(*params)); 35262306a36Sopenharmony_ci if (!params) 35362306a36Sopenharmony_ci exit(1); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci if (strcmp(argv[0], "hwnoise") == 0) { 35662306a36Sopenharmony_ci params->mode = MODE_HWNOISE; 35762306a36Sopenharmony_ci /* 35862306a36Sopenharmony_ci * Reduce CPU usage for 75% to avoid killing the system. 35962306a36Sopenharmony_ci */ 36062306a36Sopenharmony_ci params->runtime = 750000; 36162306a36Sopenharmony_ci params->period = 1000000; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci while (1) { 36562306a36Sopenharmony_ci static struct option long_options[] = { 36662306a36Sopenharmony_ci {"auto", required_argument, 0, 'a'}, 36762306a36Sopenharmony_ci {"cpus", required_argument, 0, 'c'}, 36862306a36Sopenharmony_ci {"cgroup", optional_argument, 0, 'C'}, 36962306a36Sopenharmony_ci {"debug", no_argument, 0, 'D'}, 37062306a36Sopenharmony_ci {"duration", required_argument, 0, 'd'}, 37162306a36Sopenharmony_ci {"event", required_argument, 0, 'e'}, 37262306a36Sopenharmony_ci {"house-keeping", required_argument, 0, 'H'}, 37362306a36Sopenharmony_ci {"help", no_argument, 0, 'h'}, 37462306a36Sopenharmony_ci {"period", required_argument, 0, 'p'}, 37562306a36Sopenharmony_ci {"priority", required_argument, 0, 'P'}, 37662306a36Sopenharmony_ci {"quiet", no_argument, 0, 'q'}, 37762306a36Sopenharmony_ci {"runtime", required_argument, 0, 'r'}, 37862306a36Sopenharmony_ci {"stop", required_argument, 0, 's'}, 37962306a36Sopenharmony_ci {"stop-total", required_argument, 0, 'S'}, 38062306a36Sopenharmony_ci {"threshold", required_argument, 0, 'T'}, 38162306a36Sopenharmony_ci {"trace", optional_argument, 0, 't'}, 38262306a36Sopenharmony_ci {"trigger", required_argument, 0, '0'}, 38362306a36Sopenharmony_ci {"filter", required_argument, 0, '1'}, 38462306a36Sopenharmony_ci {0, 0, 0, 0} 38562306a36Sopenharmony_ci }; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci /* getopt_long stores the option index here. */ 38862306a36Sopenharmony_ci int option_index = 0; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci c = getopt_long(argc, argv, "a:c:C::d:De:hH:p:P:qr:s:S:t::T:0:1:", 39162306a36Sopenharmony_ci long_options, &option_index); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci /* Detect the end of the options. */ 39462306a36Sopenharmony_ci if (c == -1) 39562306a36Sopenharmony_ci break; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci switch (c) { 39862306a36Sopenharmony_ci case 'a': 39962306a36Sopenharmony_ci /* set sample stop to auto_thresh */ 40062306a36Sopenharmony_ci params->stop_us = get_llong_from_str(optarg); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci /* set sample threshold to 1 */ 40362306a36Sopenharmony_ci params->threshold = 1; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* set trace */ 40662306a36Sopenharmony_ci params->trace_output = "osnoise_trace.txt"; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci break; 40962306a36Sopenharmony_ci case 'c': 41062306a36Sopenharmony_ci retval = parse_cpu_set(optarg, ¶ms->monitored_cpus); 41162306a36Sopenharmony_ci if (retval) 41262306a36Sopenharmony_ci osnoise_top_usage(params, "\nInvalid -c cpu list\n"); 41362306a36Sopenharmony_ci params->cpus = optarg; 41462306a36Sopenharmony_ci break; 41562306a36Sopenharmony_ci case 'C': 41662306a36Sopenharmony_ci params->cgroup = 1; 41762306a36Sopenharmony_ci if (!optarg) { 41862306a36Sopenharmony_ci /* will inherit this cgroup */ 41962306a36Sopenharmony_ci params->cgroup_name = NULL; 42062306a36Sopenharmony_ci } else if (*optarg == '=') { 42162306a36Sopenharmony_ci /* skip the = */ 42262306a36Sopenharmony_ci params->cgroup_name = ++optarg; 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci break; 42562306a36Sopenharmony_ci case 'D': 42662306a36Sopenharmony_ci config_debug = 1; 42762306a36Sopenharmony_ci break; 42862306a36Sopenharmony_ci case 'd': 42962306a36Sopenharmony_ci params->duration = parse_seconds_duration(optarg); 43062306a36Sopenharmony_ci if (!params->duration) 43162306a36Sopenharmony_ci osnoise_top_usage(params, "Invalid -D duration\n"); 43262306a36Sopenharmony_ci break; 43362306a36Sopenharmony_ci case 'e': 43462306a36Sopenharmony_ci tevent = trace_event_alloc(optarg); 43562306a36Sopenharmony_ci if (!tevent) { 43662306a36Sopenharmony_ci err_msg("Error alloc trace event"); 43762306a36Sopenharmony_ci exit(EXIT_FAILURE); 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (params->events) 44162306a36Sopenharmony_ci tevent->next = params->events; 44262306a36Sopenharmony_ci params->events = tevent; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci break; 44562306a36Sopenharmony_ci case 'h': 44662306a36Sopenharmony_ci case '?': 44762306a36Sopenharmony_ci osnoise_top_usage(params, NULL); 44862306a36Sopenharmony_ci break; 44962306a36Sopenharmony_ci case 'H': 45062306a36Sopenharmony_ci params->hk_cpus = 1; 45162306a36Sopenharmony_ci retval = parse_cpu_set(optarg, ¶ms->hk_cpu_set); 45262306a36Sopenharmony_ci if (retval) { 45362306a36Sopenharmony_ci err_msg("Error parsing house keeping CPUs\n"); 45462306a36Sopenharmony_ci exit(EXIT_FAILURE); 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci break; 45762306a36Sopenharmony_ci case 'p': 45862306a36Sopenharmony_ci params->period = get_llong_from_str(optarg); 45962306a36Sopenharmony_ci if (params->period > 10000000) 46062306a36Sopenharmony_ci osnoise_top_usage(params, "Period longer than 10 s\n"); 46162306a36Sopenharmony_ci break; 46262306a36Sopenharmony_ci case 'P': 46362306a36Sopenharmony_ci retval = parse_prio(optarg, ¶ms->sched_param); 46462306a36Sopenharmony_ci if (retval == -1) 46562306a36Sopenharmony_ci osnoise_top_usage(params, "Invalid -P priority"); 46662306a36Sopenharmony_ci params->set_sched = 1; 46762306a36Sopenharmony_ci break; 46862306a36Sopenharmony_ci case 'q': 46962306a36Sopenharmony_ci params->quiet = 1; 47062306a36Sopenharmony_ci break; 47162306a36Sopenharmony_ci case 'r': 47262306a36Sopenharmony_ci params->runtime = get_llong_from_str(optarg); 47362306a36Sopenharmony_ci if (params->runtime < 100) 47462306a36Sopenharmony_ci osnoise_top_usage(params, "Runtime shorter than 100 us\n"); 47562306a36Sopenharmony_ci break; 47662306a36Sopenharmony_ci case 's': 47762306a36Sopenharmony_ci params->stop_us = get_llong_from_str(optarg); 47862306a36Sopenharmony_ci break; 47962306a36Sopenharmony_ci case 'S': 48062306a36Sopenharmony_ci params->stop_total_us = get_llong_from_str(optarg); 48162306a36Sopenharmony_ci break; 48262306a36Sopenharmony_ci case 't': 48362306a36Sopenharmony_ci if (optarg) 48462306a36Sopenharmony_ci /* skip = */ 48562306a36Sopenharmony_ci params->trace_output = &optarg[1]; 48662306a36Sopenharmony_ci else 48762306a36Sopenharmony_ci params->trace_output = "osnoise_trace.txt"; 48862306a36Sopenharmony_ci break; 48962306a36Sopenharmony_ci case 'T': 49062306a36Sopenharmony_ci params->threshold = get_llong_from_str(optarg); 49162306a36Sopenharmony_ci break; 49262306a36Sopenharmony_ci case '0': /* trigger */ 49362306a36Sopenharmony_ci if (params->events) { 49462306a36Sopenharmony_ci retval = trace_event_add_trigger(params->events, optarg); 49562306a36Sopenharmony_ci if (retval) { 49662306a36Sopenharmony_ci err_msg("Error adding trigger %s\n", optarg); 49762306a36Sopenharmony_ci exit(EXIT_FAILURE); 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci } else { 50062306a36Sopenharmony_ci osnoise_top_usage(params, "--trigger requires a previous -e\n"); 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci break; 50362306a36Sopenharmony_ci case '1': /* filter */ 50462306a36Sopenharmony_ci if (params->events) { 50562306a36Sopenharmony_ci retval = trace_event_add_filter(params->events, optarg); 50662306a36Sopenharmony_ci if (retval) { 50762306a36Sopenharmony_ci err_msg("Error adding filter %s\n", optarg); 50862306a36Sopenharmony_ci exit(EXIT_FAILURE); 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci } else { 51162306a36Sopenharmony_ci osnoise_top_usage(params, "--filter requires a previous -e\n"); 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci break; 51462306a36Sopenharmony_ci default: 51562306a36Sopenharmony_ci osnoise_top_usage(params, "Invalid option"); 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci if (geteuid()) { 52062306a36Sopenharmony_ci err_msg("osnoise needs root permission\n"); 52162306a36Sopenharmony_ci exit(EXIT_FAILURE); 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci return params; 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci/* 52862306a36Sopenharmony_ci * osnoise_top_apply_config - apply the top configs to the initialized tool 52962306a36Sopenharmony_ci */ 53062306a36Sopenharmony_cistatic int 53162306a36Sopenharmony_ciosnoise_top_apply_config(struct osnoise_tool *tool, struct osnoise_top_params *params) 53262306a36Sopenharmony_ci{ 53362306a36Sopenharmony_ci int retval; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci if (!params->sleep_time) 53662306a36Sopenharmony_ci params->sleep_time = 1; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci if (params->cpus) { 53962306a36Sopenharmony_ci retval = osnoise_set_cpus(tool->context, params->cpus); 54062306a36Sopenharmony_ci if (retval) { 54162306a36Sopenharmony_ci err_msg("Failed to apply CPUs config\n"); 54262306a36Sopenharmony_ci goto out_err; 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if (params->runtime || params->period) { 54762306a36Sopenharmony_ci retval = osnoise_set_runtime_period(tool->context, 54862306a36Sopenharmony_ci params->runtime, 54962306a36Sopenharmony_ci params->period); 55062306a36Sopenharmony_ci if (retval) { 55162306a36Sopenharmony_ci err_msg("Failed to set runtime and/or period\n"); 55262306a36Sopenharmony_ci goto out_err; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci if (params->stop_us) { 55762306a36Sopenharmony_ci retval = osnoise_set_stop_us(tool->context, params->stop_us); 55862306a36Sopenharmony_ci if (retval) { 55962306a36Sopenharmony_ci err_msg("Failed to set stop us\n"); 56062306a36Sopenharmony_ci goto out_err; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci if (params->stop_total_us) { 56562306a36Sopenharmony_ci retval = osnoise_set_stop_total_us(tool->context, params->stop_total_us); 56662306a36Sopenharmony_ci if (retval) { 56762306a36Sopenharmony_ci err_msg("Failed to set stop total us\n"); 56862306a36Sopenharmony_ci goto out_err; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci if (params->threshold) { 57362306a36Sopenharmony_ci retval = osnoise_set_tracing_thresh(tool->context, params->threshold); 57462306a36Sopenharmony_ci if (retval) { 57562306a36Sopenharmony_ci err_msg("Failed to set tracing_thresh\n"); 57662306a36Sopenharmony_ci goto out_err; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci if (params->mode == MODE_HWNOISE) { 58162306a36Sopenharmony_ci retval = osnoise_set_irq_disable(tool->context, 1); 58262306a36Sopenharmony_ci if (retval) { 58362306a36Sopenharmony_ci err_msg("Failed to set OSNOISE_IRQ_DISABLE option\n"); 58462306a36Sopenharmony_ci goto out_err; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (params->hk_cpus) { 58962306a36Sopenharmony_ci retval = sched_setaffinity(getpid(), sizeof(params->hk_cpu_set), 59062306a36Sopenharmony_ci ¶ms->hk_cpu_set); 59162306a36Sopenharmony_ci if (retval == -1) { 59262306a36Sopenharmony_ci err_msg("Failed to set rtla to the house keeping CPUs\n"); 59362306a36Sopenharmony_ci goto out_err; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci } else if (params->cpus) { 59662306a36Sopenharmony_ci /* 59762306a36Sopenharmony_ci * Even if the user do not set a house-keeping CPU, try to 59862306a36Sopenharmony_ci * move rtla to a CPU set different to the one where the user 59962306a36Sopenharmony_ci * set the workload to run. 60062306a36Sopenharmony_ci * 60162306a36Sopenharmony_ci * No need to check results as this is an automatic attempt. 60262306a36Sopenharmony_ci */ 60362306a36Sopenharmony_ci auto_house_keeping(¶ms->monitored_cpus); 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci return 0; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ciout_err: 60962306a36Sopenharmony_ci return -1; 61062306a36Sopenharmony_ci} 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci/* 61362306a36Sopenharmony_ci * osnoise_init_top - initialize a osnoise top tool with parameters 61462306a36Sopenharmony_ci */ 61562306a36Sopenharmony_cistruct osnoise_tool *osnoise_init_top(struct osnoise_top_params *params) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci struct osnoise_tool *tool; 61862306a36Sopenharmony_ci int nr_cpus; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci nr_cpus = sysconf(_SC_NPROCESSORS_CONF); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci tool = osnoise_init_tool("osnoise_top"); 62362306a36Sopenharmony_ci if (!tool) 62462306a36Sopenharmony_ci return NULL; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci tool->data = osnoise_alloc_top(nr_cpus); 62762306a36Sopenharmony_ci if (!tool->data) 62862306a36Sopenharmony_ci goto out_err; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci tool->params = params; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci tep_register_event_handler(tool->trace.tep, -1, "ftrace", "osnoise", 63362306a36Sopenharmony_ci osnoise_top_handler, NULL); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci return tool; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ciout_err: 63862306a36Sopenharmony_ci osnoise_free_top(tool->data); 63962306a36Sopenharmony_ci osnoise_destroy_tool(tool); 64062306a36Sopenharmony_ci return NULL; 64162306a36Sopenharmony_ci} 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_cistatic int stop_tracing; 64462306a36Sopenharmony_cistatic void stop_top(int sig) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci stop_tracing = 1; 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci/* 65062306a36Sopenharmony_ci * osnoise_top_set_signals - handles the signal to stop the tool 65162306a36Sopenharmony_ci */ 65262306a36Sopenharmony_cistatic void osnoise_top_set_signals(struct osnoise_top_params *params) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci signal(SIGINT, stop_top); 65562306a36Sopenharmony_ci if (params->duration) { 65662306a36Sopenharmony_ci signal(SIGALRM, stop_top); 65762306a36Sopenharmony_ci alarm(params->duration); 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci} 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ciint osnoise_top_main(int argc, char **argv) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci struct osnoise_top_params *params; 66462306a36Sopenharmony_ci struct osnoise_tool *record = NULL; 66562306a36Sopenharmony_ci struct osnoise_tool *tool = NULL; 66662306a36Sopenharmony_ci struct trace_instance *trace; 66762306a36Sopenharmony_ci int return_value = 1; 66862306a36Sopenharmony_ci int retval; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci params = osnoise_top_parse_args(argc, argv); 67162306a36Sopenharmony_ci if (!params) 67262306a36Sopenharmony_ci exit(1); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci tool = osnoise_init_top(params); 67562306a36Sopenharmony_ci if (!tool) { 67662306a36Sopenharmony_ci err_msg("Could not init osnoise top\n"); 67762306a36Sopenharmony_ci goto out_exit; 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci retval = osnoise_top_apply_config(tool, params); 68162306a36Sopenharmony_ci if (retval) { 68262306a36Sopenharmony_ci err_msg("Could not apply config\n"); 68362306a36Sopenharmony_ci goto out_free; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci trace = &tool->trace; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci retval = enable_osnoise(trace); 68962306a36Sopenharmony_ci if (retval) { 69062306a36Sopenharmony_ci err_msg("Failed to enable osnoise tracer\n"); 69162306a36Sopenharmony_ci goto out_free; 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci if (params->set_sched) { 69562306a36Sopenharmony_ci retval = set_comm_sched_attr("osnoise/", ¶ms->sched_param); 69662306a36Sopenharmony_ci if (retval) { 69762306a36Sopenharmony_ci err_msg("Failed to set sched parameters\n"); 69862306a36Sopenharmony_ci goto out_free; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci if (params->cgroup) { 70362306a36Sopenharmony_ci retval = set_comm_cgroup("osnoise/", params->cgroup_name); 70462306a36Sopenharmony_ci if (!retval) { 70562306a36Sopenharmony_ci err_msg("Failed to move threads to cgroup\n"); 70662306a36Sopenharmony_ci goto out_free; 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci } 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci if (params->trace_output) { 71162306a36Sopenharmony_ci record = osnoise_init_trace_tool("osnoise"); 71262306a36Sopenharmony_ci if (!record) { 71362306a36Sopenharmony_ci err_msg("Failed to enable the trace instance\n"); 71462306a36Sopenharmony_ci goto out_free; 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci if (params->events) { 71862306a36Sopenharmony_ci retval = trace_events_enable(&record->trace, params->events); 71962306a36Sopenharmony_ci if (retval) 72062306a36Sopenharmony_ci goto out_top; 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci /* 72562306a36Sopenharmony_ci * Start the tracer here, after having set all instances. 72662306a36Sopenharmony_ci * 72762306a36Sopenharmony_ci * Let the trace instance start first for the case of hitting a stop 72862306a36Sopenharmony_ci * tracing while enabling other instances. The trace instance is the 72962306a36Sopenharmony_ci * one with most valuable information. 73062306a36Sopenharmony_ci */ 73162306a36Sopenharmony_ci if (params->trace_output) 73262306a36Sopenharmony_ci trace_instance_start(&record->trace); 73362306a36Sopenharmony_ci trace_instance_start(trace); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci tool->start_time = time(NULL); 73662306a36Sopenharmony_ci osnoise_top_set_signals(params); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci while (!stop_tracing) { 73962306a36Sopenharmony_ci sleep(params->sleep_time); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci retval = tracefs_iterate_raw_events(trace->tep, 74262306a36Sopenharmony_ci trace->inst, 74362306a36Sopenharmony_ci NULL, 74462306a36Sopenharmony_ci 0, 74562306a36Sopenharmony_ci collect_registered_events, 74662306a36Sopenharmony_ci trace); 74762306a36Sopenharmony_ci if (retval < 0) { 74862306a36Sopenharmony_ci err_msg("Error iterating on events\n"); 74962306a36Sopenharmony_ci goto out_top; 75062306a36Sopenharmony_ci } 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci if (!params->quiet) 75362306a36Sopenharmony_ci osnoise_print_stats(params, tool); 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci if (trace_is_off(&tool->trace, &record->trace)) 75662306a36Sopenharmony_ci break; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci } 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci osnoise_print_stats(params, tool); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci return_value = 0; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci if (trace_is_off(&tool->trace, &record->trace)) { 76562306a36Sopenharmony_ci printf("osnoise hit stop tracing\n"); 76662306a36Sopenharmony_ci if (params->trace_output) { 76762306a36Sopenharmony_ci printf(" Saving trace to %s\n", params->trace_output); 76862306a36Sopenharmony_ci save_trace_to_file(record->trace.inst, params->trace_output); 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci } 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ciout_top: 77362306a36Sopenharmony_ci trace_events_destroy(&record->trace, params->events); 77462306a36Sopenharmony_ci params->events = NULL; 77562306a36Sopenharmony_ciout_free: 77662306a36Sopenharmony_ci osnoise_free_top(tool->data); 77762306a36Sopenharmony_ci osnoise_destroy_tool(record); 77862306a36Sopenharmony_ci osnoise_destroy_tool(tool); 77962306a36Sopenharmony_ci free(params); 78062306a36Sopenharmony_ciout_exit: 78162306a36Sopenharmony_ci exit(return_value); 78262306a36Sopenharmony_ci} 783