Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/tracing/rtla/src/trace.c
26285 views
1
// SPDX-License-Identifier: GPL-2.0
2
#define _GNU_SOURCE
3
#include <sys/sendfile.h>
4
#include <tracefs.h>
5
#include <signal.h>
6
#include <stdlib.h>
7
#include <unistd.h>
8
#include <errno.h>
9
10
#include "trace.h"
11
#include "utils.h"
12
13
/*
14
* enable_tracer_by_name - enable a tracer on the given instance
15
*/
16
int enable_tracer_by_name(struct tracefs_instance *inst, const char *tracer_name)
17
{
18
enum tracefs_tracers tracer;
19
int retval;
20
21
tracer = TRACEFS_TRACER_CUSTOM;
22
23
debug_msg("Enabling %s tracer\n", tracer_name);
24
25
retval = tracefs_tracer_set(inst, tracer, tracer_name);
26
if (retval < 0) {
27
if (errno == ENODEV)
28
err_msg("Tracer %s not found!\n", tracer_name);
29
30
err_msg("Failed to enable the %s tracer\n", tracer_name);
31
return -1;
32
}
33
34
return 0;
35
}
36
37
/*
38
* disable_tracer - set nop tracer to the insta
39
*/
40
void disable_tracer(struct tracefs_instance *inst)
41
{
42
enum tracefs_tracers t = TRACEFS_TRACER_NOP;
43
int retval;
44
45
retval = tracefs_tracer_set(inst, t);
46
if (retval < 0)
47
err_msg("Oops, error disabling tracer\n");
48
}
49
50
/*
51
* create_instance - create a trace instance with *instance_name
52
*/
53
struct tracefs_instance *create_instance(char *instance_name)
54
{
55
return tracefs_instance_create(instance_name);
56
}
57
58
/*
59
* destroy_instance - remove a trace instance and free the data
60
*/
61
void destroy_instance(struct tracefs_instance *inst)
62
{
63
tracefs_instance_destroy(inst);
64
tracefs_instance_free(inst);
65
}
66
67
/*
68
* save_trace_to_file - save the trace output of the instance to the file
69
*/
70
int save_trace_to_file(struct tracefs_instance *inst, const char *filename)
71
{
72
const char *file = "trace";
73
mode_t mode = 0644;
74
char buffer[4096];
75
int out_fd, in_fd;
76
int retval = -1;
77
78
if (!inst || !filename)
79
return 0;
80
81
in_fd = tracefs_instance_file_open(inst, file, O_RDONLY);
82
if (in_fd < 0) {
83
err_msg("Failed to open trace file\n");
84
return -1;
85
}
86
87
printf(" Saving trace to %s\n", filename);
88
out_fd = creat(filename, mode);
89
if (out_fd < 0) {
90
err_msg("Failed to create output file %s\n", filename);
91
goto out_close_in;
92
}
93
94
do {
95
retval = read(in_fd, buffer, sizeof(buffer));
96
if (retval <= 0)
97
goto out_close;
98
99
retval = write(out_fd, buffer, retval);
100
if (retval < 0)
101
goto out_close;
102
} while (retval > 0);
103
104
retval = 0;
105
out_close:
106
close(out_fd);
107
out_close_in:
108
close(in_fd);
109
return retval;
110
}
111
112
/*
113
* collect_registered_events - call the existing callback function for the event
114
*
115
* If an event has a registered callback function, call it.
116
* Otherwise, ignore the event.
117
*/
118
int
119
collect_registered_events(struct tep_event *event, struct tep_record *record,
120
int cpu, void *context)
121
{
122
struct trace_instance *trace = context;
123
struct trace_seq *s = trace->seq;
124
125
trace->processed_events++;
126
127
if (!event->handler)
128
return 0;
129
130
event->handler(s, record, event, context);
131
132
return 0;
133
}
134
135
/*
136
* collect_missed_events - record number of missed events
137
*
138
* If rtla cannot keep up with events generated by tracer, events are going
139
* to fall out of the ring buffer.
140
* Collect how many events were missed so it can be reported to the user.
141
*/
142
static int
143
collect_missed_events(struct tep_event *event, struct tep_record *record,
144
int cpu, void *context)
145
{
146
struct trace_instance *trace = context;
147
148
if (trace->missed_events == UINT64_MAX)
149
return 0;
150
151
if (record->missed_events > 0)
152
trace->missed_events += record->missed_events;
153
else
154
/* Events missed but no data on how many */
155
trace->missed_events = UINT64_MAX;
156
157
return 0;
158
}
159
160
/*
161
* trace_instance_destroy - destroy and free a rtla trace instance
162
*/
163
void trace_instance_destroy(struct trace_instance *trace)
164
{
165
if (trace->inst) {
166
disable_tracer(trace->inst);
167
destroy_instance(trace->inst);
168
trace->inst = NULL;
169
}
170
171
if (trace->seq) {
172
free(trace->seq);
173
trace->seq = NULL;
174
}
175
176
if (trace->tep) {
177
tep_free(trace->tep);
178
trace->tep = NULL;
179
}
180
}
181
182
/*
183
* trace_instance_init - create an rtla trace instance
184
*
185
* It is more than the tracefs instance, as it contains other
186
* things required for the tracing, such as the local events and
187
* a seq file.
188
*
189
* Note that the trace instance is returned disabled. This allows
190
* the tool to apply some other configs, like setting priority
191
* to the kernel threads, before starting generating trace entries.
192
*/
193
int trace_instance_init(struct trace_instance *trace, char *tool_name)
194
{
195
trace->seq = calloc(1, sizeof(*trace->seq));
196
if (!trace->seq)
197
goto out_err;
198
199
trace_seq_init(trace->seq);
200
201
trace->inst = create_instance(tool_name);
202
if (!trace->inst)
203
goto out_err;
204
205
trace->tep = tracefs_local_events(NULL);
206
if (!trace->tep)
207
goto out_err;
208
209
/*
210
* Let the main enable the record after setting some other
211
* things such as the priority of the tracer's threads.
212
*/
213
tracefs_trace_off(trace->inst);
214
215
/*
216
* Collect the number of events missed due to tracefs buffer
217
* overflow.
218
*/
219
trace->missed_events = 0;
220
tracefs_follow_missed_events(trace->inst,
221
collect_missed_events,
222
trace);
223
224
trace->processed_events = 0;
225
226
return 0;
227
228
out_err:
229
trace_instance_destroy(trace);
230
return 1;
231
}
232
233
/*
234
* trace_instance_start - start tracing a given rtla instance
235
*/
236
int trace_instance_start(struct trace_instance *trace)
237
{
238
return tracefs_trace_on(trace->inst);
239
}
240
241
/*
242
* trace_instance_stop - stop tracing a given rtla instance
243
*/
244
int trace_instance_stop(struct trace_instance *trace)
245
{
246
return tracefs_trace_off(trace->inst);
247
}
248
249
/*
250
* trace_events_free - free a list of trace events
251
*/
252
static void trace_events_free(struct trace_events *events)
253
{
254
struct trace_events *tevent = events;
255
struct trace_events *free_event;
256
257
while (tevent) {
258
free_event = tevent;
259
260
tevent = tevent->next;
261
262
if (free_event->filter)
263
free(free_event->filter);
264
if (free_event->trigger)
265
free(free_event->trigger);
266
free(free_event->system);
267
free(free_event);
268
}
269
}
270
271
/*
272
* trace_event_alloc - alloc and parse a single trace event
273
*/
274
struct trace_events *trace_event_alloc(const char *event_string)
275
{
276
struct trace_events *tevent;
277
278
tevent = calloc(1, sizeof(*tevent));
279
if (!tevent)
280
return NULL;
281
282
tevent->system = strdup(event_string);
283
if (!tevent->system) {
284
free(tevent);
285
return NULL;
286
}
287
288
tevent->event = strstr(tevent->system, ":");
289
if (tevent->event) {
290
*tevent->event = '\0';
291
tevent->event = &tevent->event[1];
292
}
293
294
return tevent;
295
}
296
297
/*
298
* trace_event_add_filter - record an event filter
299
*/
300
int trace_event_add_filter(struct trace_events *event, char *filter)
301
{
302
if (event->filter)
303
free(event->filter);
304
305
event->filter = strdup(filter);
306
if (!event->filter)
307
return 1;
308
309
return 0;
310
}
311
312
/*
313
* trace_event_add_trigger - record an event trigger action
314
*/
315
int trace_event_add_trigger(struct trace_events *event, char *trigger)
316
{
317
if (event->trigger)
318
free(event->trigger);
319
320
event->trigger = strdup(trigger);
321
if (!event->trigger)
322
return 1;
323
324
return 0;
325
}
326
327
/*
328
* trace_event_disable_filter - disable an event filter
329
*/
330
static void trace_event_disable_filter(struct trace_instance *instance,
331
struct trace_events *tevent)
332
{
333
char filter[1024];
334
int retval;
335
336
if (!tevent->filter)
337
return;
338
339
if (!tevent->filter_enabled)
340
return;
341
342
debug_msg("Disabling %s:%s filter %s\n", tevent->system,
343
tevent->event ? : "*", tevent->filter);
344
345
snprintf(filter, 1024, "!%s\n", tevent->filter);
346
347
retval = tracefs_event_file_write(instance->inst, tevent->system,
348
tevent->event, "filter", filter);
349
if (retval < 0)
350
err_msg("Error disabling %s:%s filter %s\n", tevent->system,
351
tevent->event ? : "*", tevent->filter);
352
}
353
354
/*
355
* trace_event_save_hist - save the content of an event hist
356
*
357
* If the trigger is a hist: one, save the content of the hist file.
358
*/
359
static void trace_event_save_hist(struct trace_instance *instance,
360
struct trace_events *tevent)
361
{
362
int retval, index, out_fd;
363
mode_t mode = 0644;
364
char path[1024];
365
char *hist;
366
367
if (!tevent)
368
return;
369
370
/* trigger enables hist */
371
if (!tevent->trigger)
372
return;
373
374
/* is this a hist: trigger? */
375
retval = strncmp(tevent->trigger, "hist:", strlen("hist:"));
376
if (retval)
377
return;
378
379
snprintf(path, 1024, "%s_%s_hist.txt", tevent->system, tevent->event);
380
381
printf(" Saving event %s:%s hist to %s\n", tevent->system, tevent->event, path);
382
383
out_fd = creat(path, mode);
384
if (out_fd < 0) {
385
err_msg(" Failed to create %s output file\n", path);
386
return;
387
}
388
389
hist = tracefs_event_file_read(instance->inst, tevent->system, tevent->event, "hist", 0);
390
if (!hist) {
391
err_msg(" Failed to read %s:%s hist file\n", tevent->system, tevent->event);
392
goto out_close;
393
}
394
395
index = 0;
396
do {
397
index += write(out_fd, &hist[index], strlen(hist) - index);
398
} while (index < strlen(hist));
399
400
free(hist);
401
out_close:
402
close(out_fd);
403
}
404
405
/*
406
* trace_event_disable_trigger - disable an event trigger
407
*/
408
static void trace_event_disable_trigger(struct trace_instance *instance,
409
struct trace_events *tevent)
410
{
411
char trigger[1024];
412
int retval;
413
414
if (!tevent->trigger)
415
return;
416
417
if (!tevent->trigger_enabled)
418
return;
419
420
debug_msg("Disabling %s:%s trigger %s\n", tevent->system,
421
tevent->event ? : "*", tevent->trigger);
422
423
trace_event_save_hist(instance, tevent);
424
425
snprintf(trigger, 1024, "!%s\n", tevent->trigger);
426
427
retval = tracefs_event_file_write(instance->inst, tevent->system,
428
tevent->event, "trigger", trigger);
429
if (retval < 0)
430
err_msg("Error disabling %s:%s trigger %s\n", tevent->system,
431
tevent->event ? : "*", tevent->trigger);
432
}
433
434
/*
435
* trace_events_disable - disable all trace events
436
*/
437
void trace_events_disable(struct trace_instance *instance,
438
struct trace_events *events)
439
{
440
struct trace_events *tevent = events;
441
442
if (!events)
443
return;
444
445
while (tevent) {
446
debug_msg("Disabling event %s:%s\n", tevent->system, tevent->event ? : "*");
447
if (tevent->enabled) {
448
trace_event_disable_filter(instance, tevent);
449
trace_event_disable_trigger(instance, tevent);
450
tracefs_event_disable(instance->inst, tevent->system, tevent->event);
451
}
452
453
tevent->enabled = 0;
454
tevent = tevent->next;
455
}
456
}
457
458
/*
459
* trace_event_enable_filter - enable an event filter associated with an event
460
*/
461
static int trace_event_enable_filter(struct trace_instance *instance,
462
struct trace_events *tevent)
463
{
464
char filter[1024];
465
int retval;
466
467
if (!tevent->filter)
468
return 0;
469
470
if (!tevent->event) {
471
err_msg("Filter %s applies only for single events, not for all %s:* events\n",
472
tevent->filter, tevent->system);
473
return 1;
474
}
475
476
snprintf(filter, 1024, "%s\n", tevent->filter);
477
478
debug_msg("Enabling %s:%s filter %s\n", tevent->system,
479
tevent->event ? : "*", tevent->filter);
480
481
retval = tracefs_event_file_write(instance->inst, tevent->system,
482
tevent->event, "filter", filter);
483
if (retval < 0) {
484
err_msg("Error enabling %s:%s filter %s\n", tevent->system,
485
tevent->event ? : "*", tevent->filter);
486
return 1;
487
}
488
489
tevent->filter_enabled = 1;
490
return 0;
491
}
492
493
/*
494
* trace_event_enable_trigger - enable an event trigger associated with an event
495
*/
496
static int trace_event_enable_trigger(struct trace_instance *instance,
497
struct trace_events *tevent)
498
{
499
char trigger[1024];
500
int retval;
501
502
if (!tevent->trigger)
503
return 0;
504
505
if (!tevent->event) {
506
err_msg("Trigger %s applies only for single events, not for all %s:* events\n",
507
tevent->trigger, tevent->system);
508
return 1;
509
}
510
511
snprintf(trigger, 1024, "%s\n", tevent->trigger);
512
513
debug_msg("Enabling %s:%s trigger %s\n", tevent->system,
514
tevent->event ? : "*", tevent->trigger);
515
516
retval = tracefs_event_file_write(instance->inst, tevent->system,
517
tevent->event, "trigger", trigger);
518
if (retval < 0) {
519
err_msg("Error enabling %s:%s trigger %s\n", tevent->system,
520
tevent->event ? : "*", tevent->trigger);
521
return 1;
522
}
523
524
tevent->trigger_enabled = 1;
525
526
return 0;
527
}
528
529
/*
530
* trace_events_enable - enable all events
531
*/
532
int trace_events_enable(struct trace_instance *instance,
533
struct trace_events *events)
534
{
535
struct trace_events *tevent = events;
536
int retval;
537
538
while (tevent) {
539
debug_msg("Enabling event %s:%s\n", tevent->system, tevent->event ? : "*");
540
retval = tracefs_event_enable(instance->inst, tevent->system, tevent->event);
541
if (retval < 0) {
542
err_msg("Error enabling event %s:%s\n", tevent->system,
543
tevent->event ? : "*");
544
return 1;
545
}
546
547
retval = trace_event_enable_filter(instance, tevent);
548
if (retval)
549
return 1;
550
551
retval = trace_event_enable_trigger(instance, tevent);
552
if (retval)
553
return 1;
554
555
tevent->enabled = 1;
556
tevent = tevent->next;
557
}
558
559
return 0;
560
}
561
562
/*
563
* trace_events_destroy - disable and free all trace events
564
*/
565
void trace_events_destroy(struct trace_instance *instance,
566
struct trace_events *events)
567
{
568
if (!events)
569
return;
570
571
trace_events_disable(instance, events);
572
trace_events_free(events);
573
}
574
575
/*
576
* trace_set_buffer_size - set the per-cpu tracing buffer size.
577
*/
578
int trace_set_buffer_size(struct trace_instance *trace, int size)
579
{
580
int retval;
581
582
debug_msg("Setting trace buffer size to %d Kb\n", size);
583
retval = tracefs_instance_set_buffer_size(trace->inst, size, -1);
584
if (retval)
585
err_msg("Error setting trace buffer size\n");
586
587
return retval;
588
}
589
590