-
Notifications
You must be signed in to change notification settings - Fork 4
/
trace-blk-hack.c
163 lines (148 loc) · 4.82 KB
/
trace-blk-hack.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/*
* Copyright (C) 2009 Red Hat Inc, Steven Rostedt <[email protected]>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License (not later!)
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, see <http://www.gnu.org/licenses>
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <stdio.h>
#include "trace-cmd.h"
#include "trace-local.h"
static const char blk_event_start[] =
"name: blktrace\n"
"ID: %d\n"
"format:\n"
"\tfield:unsigned short common_type;\toffset:0;\tsize:2;\n"
"\tfield:unsigned char common_flags;\toffset:2;\tsize:1;\n"
"\tfield:unsigned char common_preempt_count;\toffset:3;\tsize:1;\n"
"\tfield:int common_pid;\toffset:4;\tsize:4;\n";
static const char blk_body[] = "\n"
"\tfield:u64 sector;\toffset:16;\tsize:8;\n"
"\tfield:int bytes;\toffset:24;\tsize:4;\n"
"\tfield:int action;\toffset:28;\tsize:4;\n"
"\tfield:int pid;\toffset:32;\tsize:4;\n"
"\tfield:int device;\toffset:36;\tsize:4;\n"
"\tfield:int cpu;\toffset:40;\tsize:4;\n"
"\tfield:short error;\toffset:44;\tsize:2;\n"
"\tfield:short pdu_len;\toffset:46;\tsize:2;\n"
"\tfield:void data;\toffset:48;\tsize:0;\n"
"\n"
"print fmt: \"%%d\", REC->pid\n";
int tracecmd_blk_hack(struct tracecmd_input *handle)
{
struct pevent *pevent;
struct event_format *event;
struct format_field *field;
char buf[4096]; /* way more than enough! */
int id;
int l;
int r;
pevent = tracecmd_get_pevent(handle);
/*
* Unfortunately, the TRACE_BLK has changed a bit.
* We need to test if various events exist to try
* to guess what event id TRACE_BLK would be.
*/
/* It was originally behind the "power" event */
event = pevent_find_event_by_name(pevent, "ftrace", "power");
if (event) {
id = event->id + 1;
goto found;
}
/*
* But the power tracer is now in perf.
* Then it was after kmem_free
*/
event = pevent_find_event_by_name(pevent, "ftrace", "kmem_free");
if (event) {
id = event->id + 1;
goto found;
}
/*
* But that then went away.
* Currently it should be behind the user stack.
*/
event = pevent_find_event_by_name(pevent, "ftrace", "user_stack");
if (event) {
id = event->id + 1;
goto found;
}
/* Give up :( */
return -1;
found:
/*
* Blk events are not exported in the events directory.
* This is a hack to attempt to create a block event
* that we can read.
*
* We'll make a format file to look like this:
*
* name: blktrace
* ID: 13
* format:
* field:unsigned short common_type; offset:0; size:2;
* field:unsigned char common_flags; offset:2; size:1;
* field:unsigned char common_preempt_count; offset:3; size:1;
* field:int common_pid; offset:4; size:4;
* field:int common_lock_depth; offset:8; size:4;
*
* field:u64 sector; offset:16; size:8;
* field:int bytes; offset:32; size:4;
* field:int action; offset:36; size:4;
* field:int pid; offset:40; size:4;
* field:int device; offset:44; size:4;
* field:int cpu; offset:48; size:4;
* field:short error; offset:52; size:2;
* field:short pdu_len; offset:54; size:2;
* field:void data; offset:60; size:0;
*
* print fmt: "%d", REC->pid
*
* Note: the struct blk_io_trace is used directly and
* just the first parts of the struct are not used in order
* to not write over the ftrace data.
*/
/* Make sure the common fields exist */
field = pevent_find_common_field(event, "common_type");
if (!field || field->offset != 0 || field->size != 2)
goto fail;
field = pevent_find_common_field(event, "common_flags");
if (!field || field->offset != 2 || field->size != 1)
goto fail;
field = pevent_find_common_field(event, "common_preempt_count");
if (!field || field->offset != 3 || field->size != 1)
goto fail;
field = pevent_find_common_field(event, "common_pid");
if (!field || field->offset != 4 || field->size != 4)
goto fail;
r = sprintf(buf, blk_event_start, id);
l = r;
/* lock depth is optional */
field = pevent_find_common_field(event, "common_lock_depth");
if (field) {
if (field->offset != 8 || field->size != 4)
return -1;
r = sprintf(buf+l, "\tfield:int common_lock_depth;\toffset:8;\tsize:4;\n");
l += r;
}
r = sprintf(buf+l, blk_body);
/* Parse this event */
l += r;
pevent_parse_event(pevent, buf, l, "ftrace");
return 0;
fail:
return -1;
}