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#include <pthread.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "utils.h" 1862306a36Sopenharmony_ci#include "osnoise.h" 1962306a36Sopenharmony_ci#include "timerlat.h" 2062306a36Sopenharmony_ci#include "timerlat_aa.h" 2162306a36Sopenharmony_ci#include "timerlat_u.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistruct timerlat_hist_params { 2462306a36Sopenharmony_ci char *cpus; 2562306a36Sopenharmony_ci cpu_set_t monitored_cpus; 2662306a36Sopenharmony_ci char *trace_output; 2762306a36Sopenharmony_ci char *cgroup_name; 2862306a36Sopenharmony_ci unsigned long long runtime; 2962306a36Sopenharmony_ci long long stop_us; 3062306a36Sopenharmony_ci long long stop_total_us; 3162306a36Sopenharmony_ci long long timerlat_period_us; 3262306a36Sopenharmony_ci long long print_stack; 3362306a36Sopenharmony_ci int sleep_time; 3462306a36Sopenharmony_ci int output_divisor; 3562306a36Sopenharmony_ci int duration; 3662306a36Sopenharmony_ci int set_sched; 3762306a36Sopenharmony_ci int dma_latency; 3862306a36Sopenharmony_ci int cgroup; 3962306a36Sopenharmony_ci int hk_cpus; 4062306a36Sopenharmony_ci int no_aa; 4162306a36Sopenharmony_ci int dump_tasks; 4262306a36Sopenharmony_ci int user_hist; 4362306a36Sopenharmony_ci cpu_set_t hk_cpu_set; 4462306a36Sopenharmony_ci struct sched_attr sched_param; 4562306a36Sopenharmony_ci struct trace_events *events; 4662306a36Sopenharmony_ci char no_irq; 4762306a36Sopenharmony_ci char no_thread; 4862306a36Sopenharmony_ci char no_header; 4962306a36Sopenharmony_ci char no_summary; 5062306a36Sopenharmony_ci char no_index; 5162306a36Sopenharmony_ci char with_zeros; 5262306a36Sopenharmony_ci int bucket_size; 5362306a36Sopenharmony_ci int entries; 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistruct timerlat_hist_cpu { 5762306a36Sopenharmony_ci int *irq; 5862306a36Sopenharmony_ci int *thread; 5962306a36Sopenharmony_ci int *user; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci int irq_count; 6262306a36Sopenharmony_ci int thread_count; 6362306a36Sopenharmony_ci int user_count; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci unsigned long long min_irq; 6662306a36Sopenharmony_ci unsigned long long sum_irq; 6762306a36Sopenharmony_ci unsigned long long max_irq; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci unsigned long long min_thread; 7062306a36Sopenharmony_ci unsigned long long sum_thread; 7162306a36Sopenharmony_ci unsigned long long max_thread; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci unsigned long long min_user; 7462306a36Sopenharmony_ci unsigned long long sum_user; 7562306a36Sopenharmony_ci unsigned long long max_user; 7662306a36Sopenharmony_ci}; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistruct timerlat_hist_data { 7962306a36Sopenharmony_ci struct timerlat_hist_cpu *hist; 8062306a36Sopenharmony_ci int entries; 8162306a36Sopenharmony_ci int bucket_size; 8262306a36Sopenharmony_ci int nr_cpus; 8362306a36Sopenharmony_ci}; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* 8662306a36Sopenharmony_ci * timerlat_free_histogram - free runtime data 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_cistatic void 8962306a36Sopenharmony_citimerlat_free_histogram(struct timerlat_hist_data *data) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci int cpu; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci /* one histogram for IRQ and one for thread, per CPU */ 9462306a36Sopenharmony_ci for (cpu = 0; cpu < data->nr_cpus; cpu++) { 9562306a36Sopenharmony_ci if (data->hist[cpu].irq) 9662306a36Sopenharmony_ci free(data->hist[cpu].irq); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (data->hist[cpu].thread) 9962306a36Sopenharmony_ci free(data->hist[cpu].thread); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (data->hist[cpu].user) 10262306a36Sopenharmony_ci free(data->hist[cpu].user); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci /* one set of histograms per CPU */ 10762306a36Sopenharmony_ci if (data->hist) 10862306a36Sopenharmony_ci free(data->hist); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci free(data); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/* 11462306a36Sopenharmony_ci * timerlat_alloc_histogram - alloc runtime data 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_cistatic struct timerlat_hist_data 11762306a36Sopenharmony_ci*timerlat_alloc_histogram(int nr_cpus, int entries, int bucket_size) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct timerlat_hist_data *data; 12062306a36Sopenharmony_ci int cpu; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci data = calloc(1, sizeof(*data)); 12362306a36Sopenharmony_ci if (!data) 12462306a36Sopenharmony_ci return NULL; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci data->entries = entries; 12762306a36Sopenharmony_ci data->bucket_size = bucket_size; 12862306a36Sopenharmony_ci data->nr_cpus = nr_cpus; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* one set of histograms per CPU */ 13162306a36Sopenharmony_ci data->hist = calloc(1, sizeof(*data->hist) * nr_cpus); 13262306a36Sopenharmony_ci if (!data->hist) 13362306a36Sopenharmony_ci goto cleanup; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci /* one histogram for IRQ and one for thread, per cpu */ 13662306a36Sopenharmony_ci for (cpu = 0; cpu < nr_cpus; cpu++) { 13762306a36Sopenharmony_ci data->hist[cpu].irq = calloc(1, sizeof(*data->hist->irq) * (entries + 1)); 13862306a36Sopenharmony_ci if (!data->hist[cpu].irq) 13962306a36Sopenharmony_ci goto cleanup; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci data->hist[cpu].thread = calloc(1, sizeof(*data->hist->thread) * (entries + 1)); 14262306a36Sopenharmony_ci if (!data->hist[cpu].thread) 14362306a36Sopenharmony_ci goto cleanup; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci data->hist[cpu].user = calloc(1, sizeof(*data->hist->user) * (entries + 1)); 14662306a36Sopenharmony_ci if (!data->hist[cpu].user) 14762306a36Sopenharmony_ci goto cleanup; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* set the min to max */ 15162306a36Sopenharmony_ci for (cpu = 0; cpu < nr_cpus; cpu++) { 15262306a36Sopenharmony_ci data->hist[cpu].min_irq = ~0; 15362306a36Sopenharmony_ci data->hist[cpu].min_thread = ~0; 15462306a36Sopenharmony_ci data->hist[cpu].min_user = ~0; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci return data; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cicleanup: 16062306a36Sopenharmony_ci timerlat_free_histogram(data); 16162306a36Sopenharmony_ci return NULL; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci/* 16562306a36Sopenharmony_ci * timerlat_hist_update - record a new timerlat occurent on cpu, updating data 16662306a36Sopenharmony_ci */ 16762306a36Sopenharmony_cistatic void 16862306a36Sopenharmony_citimerlat_hist_update(struct osnoise_tool *tool, int cpu, 16962306a36Sopenharmony_ci unsigned long long context, 17062306a36Sopenharmony_ci unsigned long long latency) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci struct timerlat_hist_params *params = tool->params; 17362306a36Sopenharmony_ci struct timerlat_hist_data *data = tool->data; 17462306a36Sopenharmony_ci int entries = data->entries; 17562306a36Sopenharmony_ci int bucket; 17662306a36Sopenharmony_ci int *hist; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (params->output_divisor) 17962306a36Sopenharmony_ci latency = latency / params->output_divisor; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci bucket = latency / data->bucket_size; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (!context) { 18462306a36Sopenharmony_ci hist = data->hist[cpu].irq; 18562306a36Sopenharmony_ci data->hist[cpu].irq_count++; 18662306a36Sopenharmony_ci update_min(&data->hist[cpu].min_irq, &latency); 18762306a36Sopenharmony_ci update_sum(&data->hist[cpu].sum_irq, &latency); 18862306a36Sopenharmony_ci update_max(&data->hist[cpu].max_irq, &latency); 18962306a36Sopenharmony_ci } else if (context == 1) { 19062306a36Sopenharmony_ci hist = data->hist[cpu].thread; 19162306a36Sopenharmony_ci data->hist[cpu].thread_count++; 19262306a36Sopenharmony_ci update_min(&data->hist[cpu].min_thread, &latency); 19362306a36Sopenharmony_ci update_sum(&data->hist[cpu].sum_thread, &latency); 19462306a36Sopenharmony_ci update_max(&data->hist[cpu].max_thread, &latency); 19562306a36Sopenharmony_ci } else { /* user */ 19662306a36Sopenharmony_ci hist = data->hist[cpu].user; 19762306a36Sopenharmony_ci data->hist[cpu].user_count++; 19862306a36Sopenharmony_ci update_min(&data->hist[cpu].min_user, &latency); 19962306a36Sopenharmony_ci update_sum(&data->hist[cpu].sum_user, &latency); 20062306a36Sopenharmony_ci update_max(&data->hist[cpu].max_user, &latency); 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (bucket < entries) 20462306a36Sopenharmony_ci hist[bucket]++; 20562306a36Sopenharmony_ci else 20662306a36Sopenharmony_ci hist[entries]++; 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci/* 21062306a36Sopenharmony_ci * timerlat_hist_handler - this is the handler for timerlat tracer events 21162306a36Sopenharmony_ci */ 21262306a36Sopenharmony_cistatic int 21362306a36Sopenharmony_citimerlat_hist_handler(struct trace_seq *s, struct tep_record *record, 21462306a36Sopenharmony_ci struct tep_event *event, void *data) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci struct trace_instance *trace = data; 21762306a36Sopenharmony_ci unsigned long long context, latency; 21862306a36Sopenharmony_ci struct osnoise_tool *tool; 21962306a36Sopenharmony_ci int cpu = record->cpu; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci tool = container_of(trace, struct osnoise_tool, trace); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci tep_get_field_val(s, event, "context", record, &context, 1); 22462306a36Sopenharmony_ci tep_get_field_val(s, event, "timer_latency", record, &latency, 1); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci timerlat_hist_update(tool, cpu, context, latency); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci return 0; 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci/* 23262306a36Sopenharmony_ci * timerlat_hist_header - print the header of the tracer to the output 23362306a36Sopenharmony_ci */ 23462306a36Sopenharmony_cistatic void timerlat_hist_header(struct osnoise_tool *tool) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci struct timerlat_hist_params *params = tool->params; 23762306a36Sopenharmony_ci struct timerlat_hist_data *data = tool->data; 23862306a36Sopenharmony_ci struct trace_seq *s = tool->trace.seq; 23962306a36Sopenharmony_ci char duration[26]; 24062306a36Sopenharmony_ci int cpu; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci if (params->no_header) 24362306a36Sopenharmony_ci return; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci get_duration(tool->start_time, duration, sizeof(duration)); 24662306a36Sopenharmony_ci trace_seq_printf(s, "# RTLA timerlat histogram\n"); 24762306a36Sopenharmony_ci trace_seq_printf(s, "# Time unit is %s (%s)\n", 24862306a36Sopenharmony_ci params->output_divisor == 1 ? "nanoseconds" : "microseconds", 24962306a36Sopenharmony_ci params->output_divisor == 1 ? "ns" : "us"); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci trace_seq_printf(s, "# Duration: %s\n", duration); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci if (!params->no_index) 25462306a36Sopenharmony_ci trace_seq_printf(s, "Index"); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci for (cpu = 0; cpu < data->nr_cpus; cpu++) { 25762306a36Sopenharmony_ci if (params->cpus && !CPU_ISSET(cpu, ¶ms->monitored_cpus)) 25862306a36Sopenharmony_ci continue; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) 26162306a36Sopenharmony_ci continue; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci if (!params->no_irq) 26462306a36Sopenharmony_ci trace_seq_printf(s, " IRQ-%03d", cpu); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (!params->no_thread) 26762306a36Sopenharmony_ci trace_seq_printf(s, " Thr-%03d", cpu); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (params->user_hist) 27062306a36Sopenharmony_ci trace_seq_printf(s, " Usr-%03d", cpu); 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci trace_seq_printf(s, "\n"); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci trace_seq_do_printf(s); 27662306a36Sopenharmony_ci trace_seq_reset(s); 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci/* 28062306a36Sopenharmony_ci * timerlat_print_summary - print the summary of the hist data to the output 28162306a36Sopenharmony_ci */ 28262306a36Sopenharmony_cistatic void 28362306a36Sopenharmony_citimerlat_print_summary(struct timerlat_hist_params *params, 28462306a36Sopenharmony_ci struct trace_instance *trace, 28562306a36Sopenharmony_ci struct timerlat_hist_data *data) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci int cpu; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (params->no_summary) 29062306a36Sopenharmony_ci return; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (!params->no_index) 29362306a36Sopenharmony_ci trace_seq_printf(trace->seq, "count:"); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci for (cpu = 0; cpu < data->nr_cpus; cpu++) { 29662306a36Sopenharmony_ci if (params->cpus && !CPU_ISSET(cpu, ¶ms->monitored_cpus)) 29762306a36Sopenharmony_ci continue; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) 30062306a36Sopenharmony_ci continue; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci if (!params->no_irq) 30362306a36Sopenharmony_ci trace_seq_printf(trace->seq, "%9d ", 30462306a36Sopenharmony_ci data->hist[cpu].irq_count); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (!params->no_thread) 30762306a36Sopenharmony_ci trace_seq_printf(trace->seq, "%9d ", 30862306a36Sopenharmony_ci data->hist[cpu].thread_count); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (params->user_hist) 31162306a36Sopenharmony_ci trace_seq_printf(trace->seq, "%9d ", 31262306a36Sopenharmony_ci data->hist[cpu].user_count); 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci trace_seq_printf(trace->seq, "\n"); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (!params->no_index) 31762306a36Sopenharmony_ci trace_seq_printf(trace->seq, "min: "); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci for (cpu = 0; cpu < data->nr_cpus; cpu++) { 32062306a36Sopenharmony_ci if (params->cpus && !CPU_ISSET(cpu, ¶ms->monitored_cpus)) 32162306a36Sopenharmony_ci continue; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) 32462306a36Sopenharmony_ci continue; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (!params->no_irq) 32762306a36Sopenharmony_ci trace_seq_printf(trace->seq, "%9llu ", 32862306a36Sopenharmony_ci data->hist[cpu].min_irq); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (!params->no_thread) 33162306a36Sopenharmony_ci trace_seq_printf(trace->seq, "%9llu ", 33262306a36Sopenharmony_ci data->hist[cpu].min_thread); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (params->user_hist) 33562306a36Sopenharmony_ci trace_seq_printf(trace->seq, "%9llu ", 33662306a36Sopenharmony_ci data->hist[cpu].min_user); 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci trace_seq_printf(trace->seq, "\n"); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (!params->no_index) 34162306a36Sopenharmony_ci trace_seq_printf(trace->seq, "avg: "); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci for (cpu = 0; cpu < data->nr_cpus; cpu++) { 34462306a36Sopenharmony_ci if (params->cpus && !CPU_ISSET(cpu, ¶ms->monitored_cpus)) 34562306a36Sopenharmony_ci continue; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) 34862306a36Sopenharmony_ci continue; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci if (!params->no_irq) { 35162306a36Sopenharmony_ci if (data->hist[cpu].irq_count) 35262306a36Sopenharmony_ci trace_seq_printf(trace->seq, "%9llu ", 35362306a36Sopenharmony_ci data->hist[cpu].sum_irq / data->hist[cpu].irq_count); 35462306a36Sopenharmony_ci else 35562306a36Sopenharmony_ci trace_seq_printf(trace->seq, " - "); 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (!params->no_thread) { 35962306a36Sopenharmony_ci if (data->hist[cpu].thread_count) 36062306a36Sopenharmony_ci trace_seq_printf(trace->seq, "%9llu ", 36162306a36Sopenharmony_ci data->hist[cpu].sum_thread / data->hist[cpu].thread_count); 36262306a36Sopenharmony_ci else 36362306a36Sopenharmony_ci trace_seq_printf(trace->seq, " - "); 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci if (params->user_hist) { 36762306a36Sopenharmony_ci if (data->hist[cpu].user_count) 36862306a36Sopenharmony_ci trace_seq_printf(trace->seq, "%9llu ", 36962306a36Sopenharmony_ci data->hist[cpu].sum_user / data->hist[cpu].user_count); 37062306a36Sopenharmony_ci else 37162306a36Sopenharmony_ci trace_seq_printf(trace->seq, " - "); 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci trace_seq_printf(trace->seq, "\n"); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (!params->no_index) 37762306a36Sopenharmony_ci trace_seq_printf(trace->seq, "max: "); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci for (cpu = 0; cpu < data->nr_cpus; cpu++) { 38062306a36Sopenharmony_ci if (params->cpus && !CPU_ISSET(cpu, ¶ms->monitored_cpus)) 38162306a36Sopenharmony_ci continue; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) 38462306a36Sopenharmony_ci continue; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (!params->no_irq) 38762306a36Sopenharmony_ci trace_seq_printf(trace->seq, "%9llu ", 38862306a36Sopenharmony_ci data->hist[cpu].max_irq); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci if (!params->no_thread) 39162306a36Sopenharmony_ci trace_seq_printf(trace->seq, "%9llu ", 39262306a36Sopenharmony_ci data->hist[cpu].max_thread); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (params->user_hist) 39562306a36Sopenharmony_ci trace_seq_printf(trace->seq, "%9llu ", 39662306a36Sopenharmony_ci data->hist[cpu].max_user); 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci trace_seq_printf(trace->seq, "\n"); 39962306a36Sopenharmony_ci trace_seq_do_printf(trace->seq); 40062306a36Sopenharmony_ci trace_seq_reset(trace->seq); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci/* 40462306a36Sopenharmony_ci * timerlat_print_stats - print data for all CPUs 40562306a36Sopenharmony_ci */ 40662306a36Sopenharmony_cistatic void 40762306a36Sopenharmony_citimerlat_print_stats(struct timerlat_hist_params *params, struct osnoise_tool *tool) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci struct timerlat_hist_data *data = tool->data; 41062306a36Sopenharmony_ci struct trace_instance *trace = &tool->trace; 41162306a36Sopenharmony_ci int bucket, cpu; 41262306a36Sopenharmony_ci int total; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci timerlat_hist_header(tool); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci for (bucket = 0; bucket < data->entries; bucket++) { 41762306a36Sopenharmony_ci total = 0; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (!params->no_index) 42062306a36Sopenharmony_ci trace_seq_printf(trace->seq, "%-6d", 42162306a36Sopenharmony_ci bucket * data->bucket_size); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci for (cpu = 0; cpu < data->nr_cpus; cpu++) { 42462306a36Sopenharmony_ci if (params->cpus && !CPU_ISSET(cpu, ¶ms->monitored_cpus)) 42562306a36Sopenharmony_ci continue; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) 42862306a36Sopenharmony_ci continue; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (!params->no_irq) { 43162306a36Sopenharmony_ci total += data->hist[cpu].irq[bucket]; 43262306a36Sopenharmony_ci trace_seq_printf(trace->seq, "%9d ", 43362306a36Sopenharmony_ci data->hist[cpu].irq[bucket]); 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if (!params->no_thread) { 43762306a36Sopenharmony_ci total += data->hist[cpu].thread[bucket]; 43862306a36Sopenharmony_ci trace_seq_printf(trace->seq, "%9d ", 43962306a36Sopenharmony_ci data->hist[cpu].thread[bucket]); 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (params->user_hist) { 44362306a36Sopenharmony_ci total += data->hist[cpu].user[bucket]; 44462306a36Sopenharmony_ci trace_seq_printf(trace->seq, "%9d ", 44562306a36Sopenharmony_ci data->hist[cpu].user[bucket]); 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci if (total == 0 && !params->with_zeros) { 45162306a36Sopenharmony_ci trace_seq_reset(trace->seq); 45262306a36Sopenharmony_ci continue; 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci trace_seq_printf(trace->seq, "\n"); 45662306a36Sopenharmony_ci trace_seq_do_printf(trace->seq); 45762306a36Sopenharmony_ci trace_seq_reset(trace->seq); 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci if (!params->no_index) 46162306a36Sopenharmony_ci trace_seq_printf(trace->seq, "over: "); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci for (cpu = 0; cpu < data->nr_cpus; cpu++) { 46462306a36Sopenharmony_ci if (params->cpus && !CPU_ISSET(cpu, ¶ms->monitored_cpus)) 46562306a36Sopenharmony_ci continue; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci if (!data->hist[cpu].irq_count && !data->hist[cpu].thread_count) 46862306a36Sopenharmony_ci continue; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci if (!params->no_irq) 47162306a36Sopenharmony_ci trace_seq_printf(trace->seq, "%9d ", 47262306a36Sopenharmony_ci data->hist[cpu].irq[data->entries]); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if (!params->no_thread) 47562306a36Sopenharmony_ci trace_seq_printf(trace->seq, "%9d ", 47662306a36Sopenharmony_ci data->hist[cpu].thread[data->entries]); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci if (params->user_hist) 47962306a36Sopenharmony_ci trace_seq_printf(trace->seq, "%9d ", 48062306a36Sopenharmony_ci data->hist[cpu].user[data->entries]); 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci trace_seq_printf(trace->seq, "\n"); 48362306a36Sopenharmony_ci trace_seq_do_printf(trace->seq); 48462306a36Sopenharmony_ci trace_seq_reset(trace->seq); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci timerlat_print_summary(params, trace, data); 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci/* 49062306a36Sopenharmony_ci * timerlat_hist_usage - prints timerlat top usage message 49162306a36Sopenharmony_ci */ 49262306a36Sopenharmony_cistatic void timerlat_hist_usage(char *usage) 49362306a36Sopenharmony_ci{ 49462306a36Sopenharmony_ci int i; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci char *msg[] = { 49762306a36Sopenharmony_ci "", 49862306a36Sopenharmony_ci " usage: [rtla] timerlat hist [-h] [-q] [-d s] [-D] [-n] [-a us] [-p us] [-i us] [-T us] [-s us] \\", 49962306a36Sopenharmony_ci " [-t[=file]] [-e sys[:event]] [--filter <filter>] [--trigger <trigger>] [-c cpu-list] [-H cpu-list]\\", 50062306a36Sopenharmony_ci " [-P priority] [-E N] [-b N] [--no-irq] [--no-thread] [--no-header] [--no-summary] \\", 50162306a36Sopenharmony_ci " [--no-index] [--with-zeros] [--dma-latency us] [-C[=cgroup_name]] [--no-aa] [--dump-task] [-u]", 50262306a36Sopenharmony_ci "", 50362306a36Sopenharmony_ci " -h/--help: print this menu", 50462306a36Sopenharmony_ci " -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit", 50562306a36Sopenharmony_ci " -p/--period us: timerlat period in us", 50662306a36Sopenharmony_ci " -i/--irq us: stop trace if the irq latency is higher than the argument in us", 50762306a36Sopenharmony_ci " -T/--thread us: stop trace if the thread latency is higher than the argument in us", 50862306a36Sopenharmony_ci " -s/--stack us: save the stack trace at the IRQ if a thread latency is higher than the argument in us", 50962306a36Sopenharmony_ci " -c/--cpus cpus: run the tracer only on the given cpus", 51062306a36Sopenharmony_ci " -H/--house-keeping cpus: run rtla control threads only on the given cpus", 51162306a36Sopenharmony_ci " -C/--cgroup[=cgroup_name]: set cgroup, if no cgroup_name is passed, the rtla's cgroup will be inherited", 51262306a36Sopenharmony_ci " -d/--duration time[m|h|d]: duration of the session in seconds", 51362306a36Sopenharmony_ci " --dump-tasks: prints the task running on all CPUs if stop conditions are met (depends on !--no-aa)", 51462306a36Sopenharmony_ci " -D/--debug: print debug info", 51562306a36Sopenharmony_ci " -t/--trace[=file]: save the stopped trace to [file|timerlat_trace.txt]", 51662306a36Sopenharmony_ci " -e/--event <sys:event>: enable the <sys:event> in the trace instance, multiple -e are allowed", 51762306a36Sopenharmony_ci " --filter <filter>: enable a trace event filter to the previous -e event", 51862306a36Sopenharmony_ci " --trigger <trigger>: enable a trace event trigger to the previous -e event", 51962306a36Sopenharmony_ci " -n/--nano: display data in nanoseconds", 52062306a36Sopenharmony_ci " --no-aa: disable auto-analysis, reducing rtla timerlat cpu usage", 52162306a36Sopenharmony_ci " -b/--bucket-size N: set the histogram bucket size (default 1)", 52262306a36Sopenharmony_ci " -E/--entries N: set the number of entries of the histogram (default 256)", 52362306a36Sopenharmony_ci " --no-irq: ignore IRQ latencies", 52462306a36Sopenharmony_ci " --no-thread: ignore thread latencies", 52562306a36Sopenharmony_ci " --no-header: do not print header", 52662306a36Sopenharmony_ci " --no-summary: do not print summary", 52762306a36Sopenharmony_ci " --no-index: do not print index", 52862306a36Sopenharmony_ci " --with-zeros: print zero only entries", 52962306a36Sopenharmony_ci " --dma-latency us: set /dev/cpu_dma_latency latency <us> to reduce exit from idle latency", 53062306a36Sopenharmony_ci " -P/--priority o:prio|r:prio|f:prio|d:runtime:period : set scheduling parameters", 53162306a36Sopenharmony_ci " o:prio - use SCHED_OTHER with prio", 53262306a36Sopenharmony_ci " r:prio - use SCHED_RR with prio", 53362306a36Sopenharmony_ci " f:prio - use SCHED_FIFO with prio", 53462306a36Sopenharmony_ci " d:runtime[us|ms|s]:period[us|ms|s] - use SCHED_DEADLINE with runtime and period", 53562306a36Sopenharmony_ci " in nanoseconds", 53662306a36Sopenharmony_ci " -u/--user-threads: use rtla user-space threads instead of in-kernel timerlat threads", 53762306a36Sopenharmony_ci NULL, 53862306a36Sopenharmony_ci }; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci if (usage) 54162306a36Sopenharmony_ci fprintf(stderr, "%s\n", usage); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci fprintf(stderr, "rtla timerlat hist: a per-cpu histogram of the timer latency (version %s)\n", 54462306a36Sopenharmony_ci VERSION); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci for (i = 0; msg[i]; i++) 54762306a36Sopenharmony_ci fprintf(stderr, "%s\n", msg[i]); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci if (usage) 55062306a36Sopenharmony_ci exit(EXIT_FAILURE); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci exit(EXIT_SUCCESS); 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci/* 55662306a36Sopenharmony_ci * timerlat_hist_parse_args - allocs, parse and fill the cmd line parameters 55762306a36Sopenharmony_ci */ 55862306a36Sopenharmony_cistatic struct timerlat_hist_params 55962306a36Sopenharmony_ci*timerlat_hist_parse_args(int argc, char *argv[]) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci struct timerlat_hist_params *params; 56262306a36Sopenharmony_ci struct trace_events *tevent; 56362306a36Sopenharmony_ci int auto_thresh; 56462306a36Sopenharmony_ci int retval; 56562306a36Sopenharmony_ci int c; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci params = calloc(1, sizeof(*params)); 56862306a36Sopenharmony_ci if (!params) 56962306a36Sopenharmony_ci exit(1); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci /* disabled by default */ 57262306a36Sopenharmony_ci params->dma_latency = -1; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci /* display data in microseconds */ 57562306a36Sopenharmony_ci params->output_divisor = 1000; 57662306a36Sopenharmony_ci params->bucket_size = 1; 57762306a36Sopenharmony_ci params->entries = 256; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci while (1) { 58062306a36Sopenharmony_ci static struct option long_options[] = { 58162306a36Sopenharmony_ci {"auto", required_argument, 0, 'a'}, 58262306a36Sopenharmony_ci {"cpus", required_argument, 0, 'c'}, 58362306a36Sopenharmony_ci {"cgroup", optional_argument, 0, 'C'}, 58462306a36Sopenharmony_ci {"bucket-size", required_argument, 0, 'b'}, 58562306a36Sopenharmony_ci {"debug", no_argument, 0, 'D'}, 58662306a36Sopenharmony_ci {"entries", required_argument, 0, 'E'}, 58762306a36Sopenharmony_ci {"duration", required_argument, 0, 'd'}, 58862306a36Sopenharmony_ci {"house-keeping", required_argument, 0, 'H'}, 58962306a36Sopenharmony_ci {"help", no_argument, 0, 'h'}, 59062306a36Sopenharmony_ci {"irq", required_argument, 0, 'i'}, 59162306a36Sopenharmony_ci {"nano", no_argument, 0, 'n'}, 59262306a36Sopenharmony_ci {"period", required_argument, 0, 'p'}, 59362306a36Sopenharmony_ci {"priority", required_argument, 0, 'P'}, 59462306a36Sopenharmony_ci {"stack", required_argument, 0, 's'}, 59562306a36Sopenharmony_ci {"thread", required_argument, 0, 'T'}, 59662306a36Sopenharmony_ci {"trace", optional_argument, 0, 't'}, 59762306a36Sopenharmony_ci {"user-threads", no_argument, 0, 'u'}, 59862306a36Sopenharmony_ci {"event", required_argument, 0, 'e'}, 59962306a36Sopenharmony_ci {"no-irq", no_argument, 0, '0'}, 60062306a36Sopenharmony_ci {"no-thread", no_argument, 0, '1'}, 60162306a36Sopenharmony_ci {"no-header", no_argument, 0, '2'}, 60262306a36Sopenharmony_ci {"no-summary", no_argument, 0, '3'}, 60362306a36Sopenharmony_ci {"no-index", no_argument, 0, '4'}, 60462306a36Sopenharmony_ci {"with-zeros", no_argument, 0, '5'}, 60562306a36Sopenharmony_ci {"trigger", required_argument, 0, '6'}, 60662306a36Sopenharmony_ci {"filter", required_argument, 0, '7'}, 60762306a36Sopenharmony_ci {"dma-latency", required_argument, 0, '8'}, 60862306a36Sopenharmony_ci {"no-aa", no_argument, 0, '9'}, 60962306a36Sopenharmony_ci {"dump-task", no_argument, 0, '\1'}, 61062306a36Sopenharmony_ci {0, 0, 0, 0} 61162306a36Sopenharmony_ci }; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci /* getopt_long stores the option index here. */ 61462306a36Sopenharmony_ci int option_index = 0; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci c = getopt_long(argc, argv, "a:c:C::b:d:e:E:DhH:i:np:P:s:t::T:u0123456:7:8:9\1", 61762306a36Sopenharmony_ci long_options, &option_index); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci /* detect the end of the options. */ 62062306a36Sopenharmony_ci if (c == -1) 62162306a36Sopenharmony_ci break; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci switch (c) { 62462306a36Sopenharmony_ci case 'a': 62562306a36Sopenharmony_ci auto_thresh = get_llong_from_str(optarg); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci /* set thread stop to auto_thresh */ 62862306a36Sopenharmony_ci params->stop_total_us = auto_thresh; 62962306a36Sopenharmony_ci params->stop_us = auto_thresh; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci /* get stack trace */ 63262306a36Sopenharmony_ci params->print_stack = auto_thresh; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci /* set trace */ 63562306a36Sopenharmony_ci params->trace_output = "timerlat_trace.txt"; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci break; 63862306a36Sopenharmony_ci case 'c': 63962306a36Sopenharmony_ci retval = parse_cpu_set(optarg, ¶ms->monitored_cpus); 64062306a36Sopenharmony_ci if (retval) 64162306a36Sopenharmony_ci timerlat_hist_usage("\nInvalid -c cpu list\n"); 64262306a36Sopenharmony_ci params->cpus = optarg; 64362306a36Sopenharmony_ci break; 64462306a36Sopenharmony_ci case 'C': 64562306a36Sopenharmony_ci params->cgroup = 1; 64662306a36Sopenharmony_ci if (!optarg) { 64762306a36Sopenharmony_ci /* will inherit this cgroup */ 64862306a36Sopenharmony_ci params->cgroup_name = NULL; 64962306a36Sopenharmony_ci } else if (*optarg == '=') { 65062306a36Sopenharmony_ci /* skip the = */ 65162306a36Sopenharmony_ci params->cgroup_name = ++optarg; 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci break; 65462306a36Sopenharmony_ci case 'b': 65562306a36Sopenharmony_ci params->bucket_size = get_llong_from_str(optarg); 65662306a36Sopenharmony_ci if ((params->bucket_size == 0) || (params->bucket_size >= 1000000)) 65762306a36Sopenharmony_ci timerlat_hist_usage("Bucket size needs to be > 0 and <= 1000000\n"); 65862306a36Sopenharmony_ci break; 65962306a36Sopenharmony_ci case 'D': 66062306a36Sopenharmony_ci config_debug = 1; 66162306a36Sopenharmony_ci break; 66262306a36Sopenharmony_ci case 'd': 66362306a36Sopenharmony_ci params->duration = parse_seconds_duration(optarg); 66462306a36Sopenharmony_ci if (!params->duration) 66562306a36Sopenharmony_ci timerlat_hist_usage("Invalid -D duration\n"); 66662306a36Sopenharmony_ci break; 66762306a36Sopenharmony_ci case 'e': 66862306a36Sopenharmony_ci tevent = trace_event_alloc(optarg); 66962306a36Sopenharmony_ci if (!tevent) { 67062306a36Sopenharmony_ci err_msg("Error alloc trace event"); 67162306a36Sopenharmony_ci exit(EXIT_FAILURE); 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci if (params->events) 67562306a36Sopenharmony_ci tevent->next = params->events; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci params->events = tevent; 67862306a36Sopenharmony_ci break; 67962306a36Sopenharmony_ci case 'E': 68062306a36Sopenharmony_ci params->entries = get_llong_from_str(optarg); 68162306a36Sopenharmony_ci if ((params->entries < 10) || (params->entries > 9999999)) 68262306a36Sopenharmony_ci timerlat_hist_usage("Entries must be > 10 and < 9999999\n"); 68362306a36Sopenharmony_ci break; 68462306a36Sopenharmony_ci case 'h': 68562306a36Sopenharmony_ci case '?': 68662306a36Sopenharmony_ci timerlat_hist_usage(NULL); 68762306a36Sopenharmony_ci break; 68862306a36Sopenharmony_ci case 'H': 68962306a36Sopenharmony_ci params->hk_cpus = 1; 69062306a36Sopenharmony_ci retval = parse_cpu_set(optarg, ¶ms->hk_cpu_set); 69162306a36Sopenharmony_ci if (retval) { 69262306a36Sopenharmony_ci err_msg("Error parsing house keeping CPUs\n"); 69362306a36Sopenharmony_ci exit(EXIT_FAILURE); 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci break; 69662306a36Sopenharmony_ci case 'i': 69762306a36Sopenharmony_ci params->stop_us = get_llong_from_str(optarg); 69862306a36Sopenharmony_ci break; 69962306a36Sopenharmony_ci case 'n': 70062306a36Sopenharmony_ci params->output_divisor = 1; 70162306a36Sopenharmony_ci break; 70262306a36Sopenharmony_ci case 'p': 70362306a36Sopenharmony_ci params->timerlat_period_us = get_llong_from_str(optarg); 70462306a36Sopenharmony_ci if (params->timerlat_period_us > 1000000) 70562306a36Sopenharmony_ci timerlat_hist_usage("Period longer than 1 s\n"); 70662306a36Sopenharmony_ci break; 70762306a36Sopenharmony_ci case 'P': 70862306a36Sopenharmony_ci retval = parse_prio(optarg, ¶ms->sched_param); 70962306a36Sopenharmony_ci if (retval == -1) 71062306a36Sopenharmony_ci timerlat_hist_usage("Invalid -P priority"); 71162306a36Sopenharmony_ci params->set_sched = 1; 71262306a36Sopenharmony_ci break; 71362306a36Sopenharmony_ci case 's': 71462306a36Sopenharmony_ci params->print_stack = get_llong_from_str(optarg); 71562306a36Sopenharmony_ci break; 71662306a36Sopenharmony_ci case 'T': 71762306a36Sopenharmony_ci params->stop_total_us = get_llong_from_str(optarg); 71862306a36Sopenharmony_ci break; 71962306a36Sopenharmony_ci case 't': 72062306a36Sopenharmony_ci if (optarg) 72162306a36Sopenharmony_ci /* skip = */ 72262306a36Sopenharmony_ci params->trace_output = &optarg[1]; 72362306a36Sopenharmony_ci else 72462306a36Sopenharmony_ci params->trace_output = "timerlat_trace.txt"; 72562306a36Sopenharmony_ci break; 72662306a36Sopenharmony_ci case 'u': 72762306a36Sopenharmony_ci params->user_hist = 1; 72862306a36Sopenharmony_ci break; 72962306a36Sopenharmony_ci case '0': /* no irq */ 73062306a36Sopenharmony_ci params->no_irq = 1; 73162306a36Sopenharmony_ci break; 73262306a36Sopenharmony_ci case '1': /* no thread */ 73362306a36Sopenharmony_ci params->no_thread = 1; 73462306a36Sopenharmony_ci break; 73562306a36Sopenharmony_ci case '2': /* no header */ 73662306a36Sopenharmony_ci params->no_header = 1; 73762306a36Sopenharmony_ci break; 73862306a36Sopenharmony_ci case '3': /* no summary */ 73962306a36Sopenharmony_ci params->no_summary = 1; 74062306a36Sopenharmony_ci break; 74162306a36Sopenharmony_ci case '4': /* no index */ 74262306a36Sopenharmony_ci params->no_index = 1; 74362306a36Sopenharmony_ci break; 74462306a36Sopenharmony_ci case '5': /* with zeros */ 74562306a36Sopenharmony_ci params->with_zeros = 1; 74662306a36Sopenharmony_ci break; 74762306a36Sopenharmony_ci case '6': /* trigger */ 74862306a36Sopenharmony_ci if (params->events) { 74962306a36Sopenharmony_ci retval = trace_event_add_trigger(params->events, optarg); 75062306a36Sopenharmony_ci if (retval) { 75162306a36Sopenharmony_ci err_msg("Error adding trigger %s\n", optarg); 75262306a36Sopenharmony_ci exit(EXIT_FAILURE); 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci } else { 75562306a36Sopenharmony_ci timerlat_hist_usage("--trigger requires a previous -e\n"); 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci break; 75862306a36Sopenharmony_ci case '7': /* filter */ 75962306a36Sopenharmony_ci if (params->events) { 76062306a36Sopenharmony_ci retval = trace_event_add_filter(params->events, optarg); 76162306a36Sopenharmony_ci if (retval) { 76262306a36Sopenharmony_ci err_msg("Error adding filter %s\n", optarg); 76362306a36Sopenharmony_ci exit(EXIT_FAILURE); 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci } else { 76662306a36Sopenharmony_ci timerlat_hist_usage("--filter requires a previous -e\n"); 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci break; 76962306a36Sopenharmony_ci case '8': 77062306a36Sopenharmony_ci params->dma_latency = get_llong_from_str(optarg); 77162306a36Sopenharmony_ci if (params->dma_latency < 0 || params->dma_latency > 10000) { 77262306a36Sopenharmony_ci err_msg("--dma-latency needs to be >= 0 and < 10000"); 77362306a36Sopenharmony_ci exit(EXIT_FAILURE); 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci break; 77662306a36Sopenharmony_ci case '9': 77762306a36Sopenharmony_ci params->no_aa = 1; 77862306a36Sopenharmony_ci break; 77962306a36Sopenharmony_ci case '\1': 78062306a36Sopenharmony_ci params->dump_tasks = 1; 78162306a36Sopenharmony_ci break; 78262306a36Sopenharmony_ci default: 78362306a36Sopenharmony_ci timerlat_hist_usage("Invalid option"); 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci } 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci if (geteuid()) { 78862306a36Sopenharmony_ci err_msg("rtla needs root permission\n"); 78962306a36Sopenharmony_ci exit(EXIT_FAILURE); 79062306a36Sopenharmony_ci } 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci if (params->no_irq && params->no_thread) 79362306a36Sopenharmony_ci timerlat_hist_usage("no-irq and no-thread set, there is nothing to do here"); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci if (params->no_index && !params->with_zeros) 79662306a36Sopenharmony_ci timerlat_hist_usage("no-index set with with-zeros is not set - it does not make sense"); 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci /* 79962306a36Sopenharmony_ci * Auto analysis only happens if stop tracing, thus: 80062306a36Sopenharmony_ci */ 80162306a36Sopenharmony_ci if (!params->stop_us && !params->stop_total_us) 80262306a36Sopenharmony_ci params->no_aa = 1; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci return params; 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci/* 80862306a36Sopenharmony_ci * timerlat_hist_apply_config - apply the hist configs to the initialized tool 80962306a36Sopenharmony_ci */ 81062306a36Sopenharmony_cistatic int 81162306a36Sopenharmony_citimerlat_hist_apply_config(struct osnoise_tool *tool, struct timerlat_hist_params *params) 81262306a36Sopenharmony_ci{ 81362306a36Sopenharmony_ci int retval, i; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci if (!params->sleep_time) 81662306a36Sopenharmony_ci params->sleep_time = 1; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci if (params->cpus) { 81962306a36Sopenharmony_ci retval = osnoise_set_cpus(tool->context, params->cpus); 82062306a36Sopenharmony_ci if (retval) { 82162306a36Sopenharmony_ci err_msg("Failed to apply CPUs config\n"); 82262306a36Sopenharmony_ci goto out_err; 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci } else { 82562306a36Sopenharmony_ci for (i = 0; i < sysconf(_SC_NPROCESSORS_CONF); i++) 82662306a36Sopenharmony_ci CPU_SET(i, ¶ms->monitored_cpus); 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci if (params->stop_us) { 83062306a36Sopenharmony_ci retval = osnoise_set_stop_us(tool->context, params->stop_us); 83162306a36Sopenharmony_ci if (retval) { 83262306a36Sopenharmony_ci err_msg("Failed to set stop us\n"); 83362306a36Sopenharmony_ci goto out_err; 83462306a36Sopenharmony_ci } 83562306a36Sopenharmony_ci } 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci if (params->stop_total_us) { 83862306a36Sopenharmony_ci retval = osnoise_set_stop_total_us(tool->context, params->stop_total_us); 83962306a36Sopenharmony_ci if (retval) { 84062306a36Sopenharmony_ci err_msg("Failed to set stop total us\n"); 84162306a36Sopenharmony_ci goto out_err; 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci if (params->timerlat_period_us) { 84662306a36Sopenharmony_ci retval = osnoise_set_timerlat_period_us(tool->context, params->timerlat_period_us); 84762306a36Sopenharmony_ci if (retval) { 84862306a36Sopenharmony_ci err_msg("Failed to set timerlat period\n"); 84962306a36Sopenharmony_ci goto out_err; 85062306a36Sopenharmony_ci } 85162306a36Sopenharmony_ci } 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci if (params->print_stack) { 85462306a36Sopenharmony_ci retval = osnoise_set_print_stack(tool->context, params->print_stack); 85562306a36Sopenharmony_ci if (retval) { 85662306a36Sopenharmony_ci err_msg("Failed to set print stack\n"); 85762306a36Sopenharmony_ci goto out_err; 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci if (params->hk_cpus) { 86262306a36Sopenharmony_ci retval = sched_setaffinity(getpid(), sizeof(params->hk_cpu_set), 86362306a36Sopenharmony_ci ¶ms->hk_cpu_set); 86462306a36Sopenharmony_ci if (retval == -1) { 86562306a36Sopenharmony_ci err_msg("Failed to set rtla to the house keeping CPUs\n"); 86662306a36Sopenharmony_ci goto out_err; 86762306a36Sopenharmony_ci } 86862306a36Sopenharmony_ci } else if (params->cpus) { 86962306a36Sopenharmony_ci /* 87062306a36Sopenharmony_ci * Even if the user do not set a house-keeping CPU, try to 87162306a36Sopenharmony_ci * move rtla to a CPU set different to the one where the user 87262306a36Sopenharmony_ci * set the workload to run. 87362306a36Sopenharmony_ci * 87462306a36Sopenharmony_ci * No need to check results as this is an automatic attempt. 87562306a36Sopenharmony_ci */ 87662306a36Sopenharmony_ci auto_house_keeping(¶ms->monitored_cpus); 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci if (params->user_hist) { 88062306a36Sopenharmony_ci retval = osnoise_set_workload(tool->context, 0); 88162306a36Sopenharmony_ci if (retval) { 88262306a36Sopenharmony_ci err_msg("Failed to set OSNOISE_WORKLOAD option\n"); 88362306a36Sopenharmony_ci goto out_err; 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci } 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci return 0; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ciout_err: 89062306a36Sopenharmony_ci return -1; 89162306a36Sopenharmony_ci} 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci/* 89462306a36Sopenharmony_ci * timerlat_init_hist - initialize a timerlat hist tool with parameters 89562306a36Sopenharmony_ci */ 89662306a36Sopenharmony_cistatic struct osnoise_tool 89762306a36Sopenharmony_ci*timerlat_init_hist(struct timerlat_hist_params *params) 89862306a36Sopenharmony_ci{ 89962306a36Sopenharmony_ci struct osnoise_tool *tool; 90062306a36Sopenharmony_ci int nr_cpus; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci nr_cpus = sysconf(_SC_NPROCESSORS_CONF); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci tool = osnoise_init_tool("timerlat_hist"); 90562306a36Sopenharmony_ci if (!tool) 90662306a36Sopenharmony_ci return NULL; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci tool->data = timerlat_alloc_histogram(nr_cpus, params->entries, params->bucket_size); 90962306a36Sopenharmony_ci if (!tool->data) 91062306a36Sopenharmony_ci goto out_err; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci tool->params = params; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci tep_register_event_handler(tool->trace.tep, -1, "ftrace", "timerlat", 91562306a36Sopenharmony_ci timerlat_hist_handler, tool); 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci return tool; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ciout_err: 92062306a36Sopenharmony_ci osnoise_destroy_tool(tool); 92162306a36Sopenharmony_ci return NULL; 92262306a36Sopenharmony_ci} 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_cistatic int stop_tracing; 92562306a36Sopenharmony_cistatic void stop_hist(int sig) 92662306a36Sopenharmony_ci{ 92762306a36Sopenharmony_ci stop_tracing = 1; 92862306a36Sopenharmony_ci} 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci/* 93162306a36Sopenharmony_ci * timerlat_hist_set_signals - handles the signal to stop the tool 93262306a36Sopenharmony_ci */ 93362306a36Sopenharmony_cistatic void 93462306a36Sopenharmony_citimerlat_hist_set_signals(struct timerlat_hist_params *params) 93562306a36Sopenharmony_ci{ 93662306a36Sopenharmony_ci signal(SIGINT, stop_hist); 93762306a36Sopenharmony_ci if (params->duration) { 93862306a36Sopenharmony_ci signal(SIGALRM, stop_hist); 93962306a36Sopenharmony_ci alarm(params->duration); 94062306a36Sopenharmony_ci } 94162306a36Sopenharmony_ci} 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ciint timerlat_hist_main(int argc, char *argv[]) 94462306a36Sopenharmony_ci{ 94562306a36Sopenharmony_ci struct timerlat_hist_params *params; 94662306a36Sopenharmony_ci struct osnoise_tool *record = NULL; 94762306a36Sopenharmony_ci struct timerlat_u_params params_u; 94862306a36Sopenharmony_ci struct osnoise_tool *tool = NULL; 94962306a36Sopenharmony_ci struct osnoise_tool *aa = NULL; 95062306a36Sopenharmony_ci struct trace_instance *trace; 95162306a36Sopenharmony_ci int dma_latency_fd = -1; 95262306a36Sopenharmony_ci int return_value = 1; 95362306a36Sopenharmony_ci pthread_t timerlat_u; 95462306a36Sopenharmony_ci int retval; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci params = timerlat_hist_parse_args(argc, argv); 95762306a36Sopenharmony_ci if (!params) 95862306a36Sopenharmony_ci exit(1); 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci tool = timerlat_init_hist(params); 96162306a36Sopenharmony_ci if (!tool) { 96262306a36Sopenharmony_ci err_msg("Could not init osnoise hist\n"); 96362306a36Sopenharmony_ci goto out_exit; 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci retval = timerlat_hist_apply_config(tool, params); 96762306a36Sopenharmony_ci if (retval) { 96862306a36Sopenharmony_ci err_msg("Could not apply config\n"); 96962306a36Sopenharmony_ci goto out_free; 97062306a36Sopenharmony_ci } 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci trace = &tool->trace; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci retval = enable_timerlat(trace); 97562306a36Sopenharmony_ci if (retval) { 97662306a36Sopenharmony_ci err_msg("Failed to enable timerlat tracer\n"); 97762306a36Sopenharmony_ci goto out_free; 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci if (params->set_sched) { 98162306a36Sopenharmony_ci retval = set_comm_sched_attr("timerlat/", ¶ms->sched_param); 98262306a36Sopenharmony_ci if (retval) { 98362306a36Sopenharmony_ci err_msg("Failed to set sched parameters\n"); 98462306a36Sopenharmony_ci goto out_free; 98562306a36Sopenharmony_ci } 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci if (params->cgroup && !params->user_hist) { 98962306a36Sopenharmony_ci retval = set_comm_cgroup("timerlat/", params->cgroup_name); 99062306a36Sopenharmony_ci if (!retval) { 99162306a36Sopenharmony_ci err_msg("Failed to move threads to cgroup\n"); 99262306a36Sopenharmony_ci goto out_free; 99362306a36Sopenharmony_ci } 99462306a36Sopenharmony_ci } 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci if (params->dma_latency >= 0) { 99762306a36Sopenharmony_ci dma_latency_fd = set_cpu_dma_latency(params->dma_latency); 99862306a36Sopenharmony_ci if (dma_latency_fd < 0) { 99962306a36Sopenharmony_ci err_msg("Could not set /dev/cpu_dma_latency.\n"); 100062306a36Sopenharmony_ci goto out_free; 100162306a36Sopenharmony_ci } 100262306a36Sopenharmony_ci } 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci if (params->trace_output) { 100562306a36Sopenharmony_ci record = osnoise_init_trace_tool("timerlat"); 100662306a36Sopenharmony_ci if (!record) { 100762306a36Sopenharmony_ci err_msg("Failed to enable the trace instance\n"); 100862306a36Sopenharmony_ci goto out_free; 100962306a36Sopenharmony_ci } 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci if (params->events) { 101262306a36Sopenharmony_ci retval = trace_events_enable(&record->trace, params->events); 101362306a36Sopenharmony_ci if (retval) 101462306a36Sopenharmony_ci goto out_hist; 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci } 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci if (!params->no_aa) { 101962306a36Sopenharmony_ci aa = osnoise_init_tool("timerlat_aa"); 102062306a36Sopenharmony_ci if (!aa) 102162306a36Sopenharmony_ci goto out_hist; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci retval = timerlat_aa_init(aa, params->dump_tasks); 102462306a36Sopenharmony_ci if (retval) { 102562306a36Sopenharmony_ci err_msg("Failed to enable the auto analysis instance\n"); 102662306a36Sopenharmony_ci goto out_hist; 102762306a36Sopenharmony_ci } 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci retval = enable_timerlat(&aa->trace); 103062306a36Sopenharmony_ci if (retval) { 103162306a36Sopenharmony_ci err_msg("Failed to enable timerlat tracer\n"); 103262306a36Sopenharmony_ci goto out_hist; 103362306a36Sopenharmony_ci } 103462306a36Sopenharmony_ci } 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci /* 103762306a36Sopenharmony_ci * Start the tracers here, after having set all instances. 103862306a36Sopenharmony_ci * 103962306a36Sopenharmony_ci * Let the trace instance start first for the case of hitting a stop 104062306a36Sopenharmony_ci * tracing while enabling other instances. The trace instance is the 104162306a36Sopenharmony_ci * one with most valuable information. 104262306a36Sopenharmony_ci */ 104362306a36Sopenharmony_ci if (params->trace_output) 104462306a36Sopenharmony_ci trace_instance_start(&record->trace); 104562306a36Sopenharmony_ci if (!params->no_aa) 104662306a36Sopenharmony_ci trace_instance_start(&aa->trace); 104762306a36Sopenharmony_ci trace_instance_start(trace); 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci tool->start_time = time(NULL); 105062306a36Sopenharmony_ci timerlat_hist_set_signals(params); 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci if (params->user_hist) { 105362306a36Sopenharmony_ci /* rtla asked to stop */ 105462306a36Sopenharmony_ci params_u.should_run = 1; 105562306a36Sopenharmony_ci /* all threads left */ 105662306a36Sopenharmony_ci params_u.stopped_running = 0; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci params_u.set = ¶ms->monitored_cpus; 105962306a36Sopenharmony_ci if (params->set_sched) 106062306a36Sopenharmony_ci params_u.sched_param = ¶ms->sched_param; 106162306a36Sopenharmony_ci else 106262306a36Sopenharmony_ci params_u.sched_param = NULL; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci params_u.cgroup_name = params->cgroup_name; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci retval = pthread_create(&timerlat_u, NULL, timerlat_u_dispatcher, ¶ms_u); 106762306a36Sopenharmony_ci if (retval) 106862306a36Sopenharmony_ci err_msg("Error creating timerlat user-space threads\n"); 106962306a36Sopenharmony_ci } 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci while (!stop_tracing) { 107262306a36Sopenharmony_ci sleep(params->sleep_time); 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci retval = tracefs_iterate_raw_events(trace->tep, 107562306a36Sopenharmony_ci trace->inst, 107662306a36Sopenharmony_ci NULL, 107762306a36Sopenharmony_ci 0, 107862306a36Sopenharmony_ci collect_registered_events, 107962306a36Sopenharmony_ci trace); 108062306a36Sopenharmony_ci if (retval < 0) { 108162306a36Sopenharmony_ci err_msg("Error iterating on events\n"); 108262306a36Sopenharmony_ci goto out_hist; 108362306a36Sopenharmony_ci } 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci if (trace_is_off(&tool->trace, &record->trace)) 108662306a36Sopenharmony_ci break; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci /* is there still any user-threads ? */ 108962306a36Sopenharmony_ci if (params->user_hist) { 109062306a36Sopenharmony_ci if (params_u.stopped_running) { 109162306a36Sopenharmony_ci debug_msg("timerlat user-space threads stopped!\n"); 109262306a36Sopenharmony_ci break; 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci } 109562306a36Sopenharmony_ci } 109662306a36Sopenharmony_ci if (params->user_hist && !params_u.stopped_running) { 109762306a36Sopenharmony_ci params_u.should_run = 0; 109862306a36Sopenharmony_ci sleep(1); 109962306a36Sopenharmony_ci } 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci timerlat_print_stats(params, tool); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci return_value = 0; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci if (trace_is_off(&tool->trace, &record->trace)) { 110662306a36Sopenharmony_ci printf("rtla timerlat hit stop tracing\n"); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci if (!params->no_aa) 110962306a36Sopenharmony_ci timerlat_auto_analysis(params->stop_us, params->stop_total_us); 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci if (params->trace_output) { 111262306a36Sopenharmony_ci printf(" Saving trace to %s\n", params->trace_output); 111362306a36Sopenharmony_ci save_trace_to_file(record->trace.inst, params->trace_output); 111462306a36Sopenharmony_ci } 111562306a36Sopenharmony_ci } 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ciout_hist: 111862306a36Sopenharmony_ci timerlat_aa_destroy(); 111962306a36Sopenharmony_ci if (dma_latency_fd >= 0) 112062306a36Sopenharmony_ci close(dma_latency_fd); 112162306a36Sopenharmony_ci trace_events_destroy(&record->trace, params->events); 112262306a36Sopenharmony_ci params->events = NULL; 112362306a36Sopenharmony_ciout_free: 112462306a36Sopenharmony_ci timerlat_free_histogram(tool->data); 112562306a36Sopenharmony_ci osnoise_destroy_tool(aa); 112662306a36Sopenharmony_ci osnoise_destroy_tool(record); 112762306a36Sopenharmony_ci osnoise_destroy_tool(tool); 112862306a36Sopenharmony_ci free(params); 112962306a36Sopenharmony_ciout_exit: 113062306a36Sopenharmony_ci exit(return_value); 113162306a36Sopenharmony_ci} 1132