1b1696371SDaniel Bristot de Oliveira // SPDX-License-Identifier: GPL-2.0 2b1696371SDaniel Bristot de Oliveira #define _GNU_SOURCE 3b1696371SDaniel Bristot de Oliveira #include <sys/sendfile.h> 4b1696371SDaniel Bristot de Oliveira #include <tracefs.h> 5b1696371SDaniel Bristot de Oliveira #include <signal.h> 6b1696371SDaniel Bristot de Oliveira #include <stdlib.h> 7b1696371SDaniel Bristot de Oliveira #include <unistd.h> 8b1696371SDaniel Bristot de Oliveira #include <errno.h> 9b1696371SDaniel Bristot de Oliveira 10b1696371SDaniel Bristot de Oliveira #include "trace.h" 11b1696371SDaniel Bristot de Oliveira #include "utils.h" 12b1696371SDaniel Bristot de Oliveira 13b1696371SDaniel Bristot de Oliveira /* 14b1696371SDaniel Bristot de Oliveira * enable_tracer_by_name - enable a tracer on the given instance 15b1696371SDaniel Bristot de Oliveira */ 16b1696371SDaniel Bristot de Oliveira int enable_tracer_by_name(struct tracefs_instance *inst, const char *tracer_name) 17b1696371SDaniel Bristot de Oliveira { 18b1696371SDaniel Bristot de Oliveira enum tracefs_tracers tracer; 19b1696371SDaniel Bristot de Oliveira int retval; 20b1696371SDaniel Bristot de Oliveira 21b1696371SDaniel Bristot de Oliveira tracer = TRACEFS_TRACER_CUSTOM; 22b1696371SDaniel Bristot de Oliveira 231a622909SDaniel Bristot de Oliveira debug_msg("Enabling %s tracer\n", tracer_name); 24b1696371SDaniel Bristot de Oliveira 25b1696371SDaniel Bristot de Oliveira retval = tracefs_tracer_set(inst, tracer, tracer_name); 26b1696371SDaniel Bristot de Oliveira if (retval < 0) { 27b1696371SDaniel Bristot de Oliveira if (errno == ENODEV) 281a622909SDaniel Bristot de Oliveira err_msg("Tracer %s not found!\n", tracer_name); 29b1696371SDaniel Bristot de Oliveira 301a622909SDaniel Bristot de Oliveira err_msg("Failed to enable the %s tracer\n", tracer_name); 31b1696371SDaniel Bristot de Oliveira return -1; 32b1696371SDaniel Bristot de Oliveira } 33b1696371SDaniel Bristot de Oliveira 34b1696371SDaniel Bristot de Oliveira return 0; 35b1696371SDaniel Bristot de Oliveira } 36b1696371SDaniel Bristot de Oliveira 37b1696371SDaniel Bristot de Oliveira /* 38b1696371SDaniel Bristot de Oliveira * disable_tracer - set nop tracer to the insta 39b1696371SDaniel Bristot de Oliveira */ 40b1696371SDaniel Bristot de Oliveira void disable_tracer(struct tracefs_instance *inst) 41b1696371SDaniel Bristot de Oliveira { 42b1696371SDaniel Bristot de Oliveira enum tracefs_tracers t = TRACEFS_TRACER_NOP; 43b1696371SDaniel Bristot de Oliveira int retval; 44b1696371SDaniel Bristot de Oliveira 45b1696371SDaniel Bristot de Oliveira retval = tracefs_tracer_set(inst, t); 46b1696371SDaniel Bristot de Oliveira if (retval < 0) 471a622909SDaniel Bristot de Oliveira err_msg("Oops, error disabling tracer\n"); 48b1696371SDaniel Bristot de Oliveira } 49b1696371SDaniel Bristot de Oliveira 50b1696371SDaniel Bristot de Oliveira /* 51b1696371SDaniel Bristot de Oliveira * create_instance - create a trace instance with *instance_name 52b1696371SDaniel Bristot de Oliveira */ 53b1696371SDaniel Bristot de Oliveira struct tracefs_instance *create_instance(char *instance_name) 54b1696371SDaniel Bristot de Oliveira { 55b1696371SDaniel Bristot de Oliveira return tracefs_instance_create(instance_name); 56b1696371SDaniel Bristot de Oliveira } 57b1696371SDaniel Bristot de Oliveira 58b1696371SDaniel Bristot de Oliveira /* 59b1696371SDaniel Bristot de Oliveira * destroy_instance - remove a trace instance and free the data 60b1696371SDaniel Bristot de Oliveira */ 61b1696371SDaniel Bristot de Oliveira void destroy_instance(struct tracefs_instance *inst) 62b1696371SDaniel Bristot de Oliveira { 63b1696371SDaniel Bristot de Oliveira tracefs_instance_destroy(inst); 64b1696371SDaniel Bristot de Oliveira tracefs_instance_free(inst); 65b1696371SDaniel Bristot de Oliveira } 66b1696371SDaniel Bristot de Oliveira 67b1696371SDaniel Bristot de Oliveira /* 68b1696371SDaniel Bristot de Oliveira * save_trace_to_file - save the trace output of the instance to the file 69b1696371SDaniel Bristot de Oliveira */ 70b1696371SDaniel Bristot de Oliveira int save_trace_to_file(struct tracefs_instance *inst, const char *filename) 71b1696371SDaniel Bristot de Oliveira { 72b1696371SDaniel Bristot de Oliveira const char *file = "trace"; 73b1696371SDaniel Bristot de Oliveira mode_t mode = 0644; 74b1696371SDaniel Bristot de Oliveira char buffer[4096]; 75b1696371SDaniel Bristot de Oliveira int out_fd, in_fd; 76b1696371SDaniel Bristot de Oliveira int retval = -1; 77b1696371SDaniel Bristot de Oliveira 78b1696371SDaniel Bristot de Oliveira in_fd = tracefs_instance_file_open(inst, file, O_RDONLY); 79b1696371SDaniel Bristot de Oliveira if (in_fd < 0) { 80b1696371SDaniel Bristot de Oliveira err_msg("Failed to open trace file\n"); 81b1696371SDaniel Bristot de Oliveira return -1; 82b1696371SDaniel Bristot de Oliveira } 83b1696371SDaniel Bristot de Oliveira 84b1696371SDaniel Bristot de Oliveira out_fd = creat(filename, mode); 85b1696371SDaniel Bristot de Oliveira if (out_fd < 0) { 86b1696371SDaniel Bristot de Oliveira err_msg("Failed to create output file %s\n", filename); 87b1696371SDaniel Bristot de Oliveira goto out_close_in; 88b1696371SDaniel Bristot de Oliveira } 89b1696371SDaniel Bristot de Oliveira 90b1696371SDaniel Bristot de Oliveira do { 91b1696371SDaniel Bristot de Oliveira retval = read(in_fd, buffer, sizeof(buffer)); 92b1696371SDaniel Bristot de Oliveira if (retval <= 0) 93b1696371SDaniel Bristot de Oliveira goto out_close; 94b1696371SDaniel Bristot de Oliveira 95b1696371SDaniel Bristot de Oliveira retval = write(out_fd, buffer, retval); 96b1696371SDaniel Bristot de Oliveira if (retval < 0) 97b1696371SDaniel Bristot de Oliveira goto out_close; 98b1696371SDaniel Bristot de Oliveira } while (retval > 0); 99b1696371SDaniel Bristot de Oliveira 100b1696371SDaniel Bristot de Oliveira retval = 0; 101b1696371SDaniel Bristot de Oliveira out_close: 102b1696371SDaniel Bristot de Oliveira close(out_fd); 103b1696371SDaniel Bristot de Oliveira out_close_in: 104b1696371SDaniel Bristot de Oliveira close(in_fd); 105b1696371SDaniel Bristot de Oliveira return retval; 106b1696371SDaniel Bristot de Oliveira } 107b1696371SDaniel Bristot de Oliveira 108b1696371SDaniel Bristot de Oliveira /* 109b1696371SDaniel Bristot de Oliveira * collect_registered_events - call the existing callback function for the event 110b1696371SDaniel Bristot de Oliveira * 111b1696371SDaniel Bristot de Oliveira * If an event has a registered callback function, call it. 112b1696371SDaniel Bristot de Oliveira * Otherwise, ignore the event. 113b1696371SDaniel Bristot de Oliveira */ 114b1696371SDaniel Bristot de Oliveira int 115b1696371SDaniel Bristot de Oliveira collect_registered_events(struct tep_event *event, struct tep_record *record, 116b1696371SDaniel Bristot de Oliveira int cpu, void *context) 117b1696371SDaniel Bristot de Oliveira { 118b1696371SDaniel Bristot de Oliveira struct trace_instance *trace = context; 119b1696371SDaniel Bristot de Oliveira struct trace_seq *s = trace->seq; 120b1696371SDaniel Bristot de Oliveira 121b1696371SDaniel Bristot de Oliveira if (!event->handler) 122b1696371SDaniel Bristot de Oliveira return 0; 123b1696371SDaniel Bristot de Oliveira 124b1696371SDaniel Bristot de Oliveira event->handler(s, record, event, context); 125b1696371SDaniel Bristot de Oliveira 126b1696371SDaniel Bristot de Oliveira return 0; 127b1696371SDaniel Bristot de Oliveira } 128b1696371SDaniel Bristot de Oliveira 129b1696371SDaniel Bristot de Oliveira /* 130b1696371SDaniel Bristot de Oliveira * trace_instance_destroy - destroy and free a rtla trace instance 131b1696371SDaniel Bristot de Oliveira */ 132b1696371SDaniel Bristot de Oliveira void trace_instance_destroy(struct trace_instance *trace) 133b1696371SDaniel Bristot de Oliveira { 134b1696371SDaniel Bristot de Oliveira if (trace->inst) { 135b1696371SDaniel Bristot de Oliveira disable_tracer(trace->inst); 136b1696371SDaniel Bristot de Oliveira destroy_instance(trace->inst); 137b1696371SDaniel Bristot de Oliveira } 138b1696371SDaniel Bristot de Oliveira 139b1696371SDaniel Bristot de Oliveira if (trace->seq) 140b1696371SDaniel Bristot de Oliveira free(trace->seq); 141b1696371SDaniel Bristot de Oliveira 142b1696371SDaniel Bristot de Oliveira if (trace->tep) 143b1696371SDaniel Bristot de Oliveira tep_free(trace->tep); 144b1696371SDaniel Bristot de Oliveira } 145b1696371SDaniel Bristot de Oliveira 146b1696371SDaniel Bristot de Oliveira /* 147b1696371SDaniel Bristot de Oliveira * trace_instance_init - create an rtla trace instance 148b1696371SDaniel Bristot de Oliveira * 149b1696371SDaniel Bristot de Oliveira * It is more than the tracefs instance, as it contains other 150b1696371SDaniel Bristot de Oliveira * things required for the tracing, such as the local events and 151b1696371SDaniel Bristot de Oliveira * a seq file. 152b1696371SDaniel Bristot de Oliveira * 153b1696371SDaniel Bristot de Oliveira * Note that the trace instance is returned disabled. This allows 154b1696371SDaniel Bristot de Oliveira * the tool to apply some other configs, like setting priority 155b1696371SDaniel Bristot de Oliveira * to the kernel threads, before starting generating trace entries. 156b1696371SDaniel Bristot de Oliveira */ 157b1696371SDaniel Bristot de Oliveira int trace_instance_init(struct trace_instance *trace, char *tool_name) 158b1696371SDaniel Bristot de Oliveira { 159b1696371SDaniel Bristot de Oliveira trace->seq = calloc(1, sizeof(*trace->seq)); 160b1696371SDaniel Bristot de Oliveira if (!trace->seq) 161b1696371SDaniel Bristot de Oliveira goto out_err; 162b1696371SDaniel Bristot de Oliveira 163b1696371SDaniel Bristot de Oliveira trace_seq_init(trace->seq); 164b1696371SDaniel Bristot de Oliveira 165b1696371SDaniel Bristot de Oliveira trace->inst = create_instance(tool_name); 166b1696371SDaniel Bristot de Oliveira if (!trace->inst) 167b1696371SDaniel Bristot de Oliveira goto out_err; 168b1696371SDaniel Bristot de Oliveira 169b1696371SDaniel Bristot de Oliveira trace->tep = tracefs_local_events(NULL); 170b1696371SDaniel Bristot de Oliveira if (!trace->tep) 171b1696371SDaniel Bristot de Oliveira goto out_err; 172b1696371SDaniel Bristot de Oliveira 173b1696371SDaniel Bristot de Oliveira /* 174b1696371SDaniel Bristot de Oliveira * Let the main enable the record after setting some other 175b1696371SDaniel Bristot de Oliveira * things such as the priority of the tracer's threads. 176b1696371SDaniel Bristot de Oliveira */ 177b1696371SDaniel Bristot de Oliveira tracefs_trace_off(trace->inst); 178b1696371SDaniel Bristot de Oliveira 179b1696371SDaniel Bristot de Oliveira return 0; 180b1696371SDaniel Bristot de Oliveira 181b1696371SDaniel Bristot de Oliveira out_err: 182b1696371SDaniel Bristot de Oliveira trace_instance_destroy(trace); 183b1696371SDaniel Bristot de Oliveira return 1; 184b1696371SDaniel Bristot de Oliveira } 185b1696371SDaniel Bristot de Oliveira 186b1696371SDaniel Bristot de Oliveira /* 187b1696371SDaniel Bristot de Oliveira * trace_instance_start - start tracing a given rtla instance 188b1696371SDaniel Bristot de Oliveira */ 189b1696371SDaniel Bristot de Oliveira int trace_instance_start(struct trace_instance *trace) 190b1696371SDaniel Bristot de Oliveira { 191b1696371SDaniel Bristot de Oliveira return tracefs_trace_on(trace->inst); 192b1696371SDaniel Bristot de Oliveira } 193*b5aa0be2SDaniel Bristot de Oliveira 194*b5aa0be2SDaniel Bristot de Oliveira /* 195*b5aa0be2SDaniel Bristot de Oliveira * trace_events_free - free a list of trace events 196*b5aa0be2SDaniel Bristot de Oliveira */ 197*b5aa0be2SDaniel Bristot de Oliveira static void trace_events_free(struct trace_events *events) 198*b5aa0be2SDaniel Bristot de Oliveira { 199*b5aa0be2SDaniel Bristot de Oliveira struct trace_events *tevent = events; 200*b5aa0be2SDaniel Bristot de Oliveira struct trace_events *free_event; 201*b5aa0be2SDaniel Bristot de Oliveira 202*b5aa0be2SDaniel Bristot de Oliveira while (tevent) { 203*b5aa0be2SDaniel Bristot de Oliveira free_event = tevent; 204*b5aa0be2SDaniel Bristot de Oliveira 205*b5aa0be2SDaniel Bristot de Oliveira tevent = tevent->next; 206*b5aa0be2SDaniel Bristot de Oliveira 207*b5aa0be2SDaniel Bristot de Oliveira free(free_event->system); 208*b5aa0be2SDaniel Bristot de Oliveira free(free_event); 209*b5aa0be2SDaniel Bristot de Oliveira } 210*b5aa0be2SDaniel Bristot de Oliveira } 211*b5aa0be2SDaniel Bristot de Oliveira 212*b5aa0be2SDaniel Bristot de Oliveira /* 213*b5aa0be2SDaniel Bristot de Oliveira * trace_event_alloc - alloc and parse a single trace event 214*b5aa0be2SDaniel Bristot de Oliveira */ 215*b5aa0be2SDaniel Bristot de Oliveira struct trace_events *trace_event_alloc(const char *event_string) 216*b5aa0be2SDaniel Bristot de Oliveira { 217*b5aa0be2SDaniel Bristot de Oliveira struct trace_events *tevent; 218*b5aa0be2SDaniel Bristot de Oliveira 219*b5aa0be2SDaniel Bristot de Oliveira tevent = calloc(1, sizeof(*tevent)); 220*b5aa0be2SDaniel Bristot de Oliveira if (!tevent) 221*b5aa0be2SDaniel Bristot de Oliveira return NULL; 222*b5aa0be2SDaniel Bristot de Oliveira 223*b5aa0be2SDaniel Bristot de Oliveira tevent->system = strdup(event_string); 224*b5aa0be2SDaniel Bristot de Oliveira if (!tevent->system) { 225*b5aa0be2SDaniel Bristot de Oliveira free(tevent); 226*b5aa0be2SDaniel Bristot de Oliveira return NULL; 227*b5aa0be2SDaniel Bristot de Oliveira } 228*b5aa0be2SDaniel Bristot de Oliveira 229*b5aa0be2SDaniel Bristot de Oliveira tevent->event = strstr(tevent->system, ":"); 230*b5aa0be2SDaniel Bristot de Oliveira if (tevent->event) { 231*b5aa0be2SDaniel Bristot de Oliveira *tevent->event = '\0'; 232*b5aa0be2SDaniel Bristot de Oliveira tevent->event = &tevent->event[1]; 233*b5aa0be2SDaniel Bristot de Oliveira } 234*b5aa0be2SDaniel Bristot de Oliveira 235*b5aa0be2SDaniel Bristot de Oliveira return tevent; 236*b5aa0be2SDaniel Bristot de Oliveira } 237*b5aa0be2SDaniel Bristot de Oliveira 238*b5aa0be2SDaniel Bristot de Oliveira /* 239*b5aa0be2SDaniel Bristot de Oliveira * trace_events_disable - disable all trace events 240*b5aa0be2SDaniel Bristot de Oliveira */ 241*b5aa0be2SDaniel Bristot de Oliveira void trace_events_disable(struct trace_instance *instance, 242*b5aa0be2SDaniel Bristot de Oliveira struct trace_events *events) 243*b5aa0be2SDaniel Bristot de Oliveira { 244*b5aa0be2SDaniel Bristot de Oliveira struct trace_events *tevent = events; 245*b5aa0be2SDaniel Bristot de Oliveira 246*b5aa0be2SDaniel Bristot de Oliveira if (!events) 247*b5aa0be2SDaniel Bristot de Oliveira return; 248*b5aa0be2SDaniel Bristot de Oliveira 249*b5aa0be2SDaniel Bristot de Oliveira while (tevent) { 250*b5aa0be2SDaniel Bristot de Oliveira debug_msg("Disabling event %s:%s\n", tevent->system, tevent->event ? : "*"); 251*b5aa0be2SDaniel Bristot de Oliveira if (tevent->enabled) 252*b5aa0be2SDaniel Bristot de Oliveira tracefs_event_disable(instance->inst, tevent->system, tevent->event); 253*b5aa0be2SDaniel Bristot de Oliveira 254*b5aa0be2SDaniel Bristot de Oliveira tevent->enabled = 0; 255*b5aa0be2SDaniel Bristot de Oliveira tevent = tevent->next; 256*b5aa0be2SDaniel Bristot de Oliveira } 257*b5aa0be2SDaniel Bristot de Oliveira } 258*b5aa0be2SDaniel Bristot de Oliveira 259*b5aa0be2SDaniel Bristot de Oliveira /* 260*b5aa0be2SDaniel Bristot de Oliveira * trace_events_enable - enable all events 261*b5aa0be2SDaniel Bristot de Oliveira */ 262*b5aa0be2SDaniel Bristot de Oliveira int trace_events_enable(struct trace_instance *instance, 263*b5aa0be2SDaniel Bristot de Oliveira struct trace_events *events) 264*b5aa0be2SDaniel Bristot de Oliveira { 265*b5aa0be2SDaniel Bristot de Oliveira struct trace_events *tevent = events; 266*b5aa0be2SDaniel Bristot de Oliveira int retval; 267*b5aa0be2SDaniel Bristot de Oliveira 268*b5aa0be2SDaniel Bristot de Oliveira while (tevent) { 269*b5aa0be2SDaniel Bristot de Oliveira debug_msg("Enabling event %s:%s\n", tevent->system, tevent->event ? : "*"); 270*b5aa0be2SDaniel Bristot de Oliveira retval = tracefs_event_enable(instance->inst, tevent->system, tevent->event); 271*b5aa0be2SDaniel Bristot de Oliveira if (retval < 0) { 272*b5aa0be2SDaniel Bristot de Oliveira err_msg("Error enabling event %s:%s\n", tevent->system, 273*b5aa0be2SDaniel Bristot de Oliveira tevent->event ? : "*"); 274*b5aa0be2SDaniel Bristot de Oliveira return 1; 275*b5aa0be2SDaniel Bristot de Oliveira } 276*b5aa0be2SDaniel Bristot de Oliveira 277*b5aa0be2SDaniel Bristot de Oliveira 278*b5aa0be2SDaniel Bristot de Oliveira tevent->enabled = 1; 279*b5aa0be2SDaniel Bristot de Oliveira tevent = tevent->next; 280*b5aa0be2SDaniel Bristot de Oliveira } 281*b5aa0be2SDaniel Bristot de Oliveira 282*b5aa0be2SDaniel Bristot de Oliveira return 0; 283*b5aa0be2SDaniel Bristot de Oliveira } 284*b5aa0be2SDaniel Bristot de Oliveira 285*b5aa0be2SDaniel Bristot de Oliveira /* 286*b5aa0be2SDaniel Bristot de Oliveira * trace_events_destroy - disable and free all trace events 287*b5aa0be2SDaniel Bristot de Oliveira */ 288*b5aa0be2SDaniel Bristot de Oliveira void trace_events_destroy(struct trace_instance *instance, 289*b5aa0be2SDaniel Bristot de Oliveira struct trace_events *events) 290*b5aa0be2SDaniel Bristot de Oliveira { 291*b5aa0be2SDaniel Bristot de Oliveira if (!events) 292*b5aa0be2SDaniel Bristot de Oliveira return; 293*b5aa0be2SDaniel Bristot de Oliveira 294*b5aa0be2SDaniel Bristot de Oliveira trace_events_disable(instance, events); 295*b5aa0be2SDaniel Bristot de Oliveira trace_events_free(events); 296*b5aa0be2SDaniel Bristot de Oliveira } 297