diff options
-rw-r--r-- | tools/perf/util/data-convert-bt.c | 242 |
1 files changed, 242 insertions, 0 deletions
diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 1afd381b2346..c6d62268cc2a 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c | |||
@@ -126,6 +126,177 @@ FUNC_VALUE_SET(s64) | |||
126 | FUNC_VALUE_SET(u64) | 126 | FUNC_VALUE_SET(u64) |
127 | __FUNC_VALUE_SET(u64_hex, u64) | 127 | __FUNC_VALUE_SET(u64_hex, u64) |
128 | 128 | ||
129 | static struct bt_ctf_field_type* | ||
130 | get_tracepoint_field_type(struct ctf_writer *cw, struct format_field *field) | ||
131 | { | ||
132 | unsigned long flags = field->flags; | ||
133 | |||
134 | if (flags & FIELD_IS_STRING) | ||
135 | return cw->data.string; | ||
136 | |||
137 | if (!(flags & FIELD_IS_SIGNED)) { | ||
138 | /* unsigned long are mostly pointers */ | ||
139 | if (flags & FIELD_IS_LONG || flags & FIELD_IS_POINTER) | ||
140 | return cw->data.u64_hex; | ||
141 | } | ||
142 | |||
143 | if (flags & FIELD_IS_SIGNED) { | ||
144 | if (field->size == 8) | ||
145 | return cw->data.s64; | ||
146 | else | ||
147 | return cw->data.s32; | ||
148 | } | ||
149 | |||
150 | if (field->size == 8) | ||
151 | return cw->data.u64; | ||
152 | else | ||
153 | return cw->data.u32; | ||
154 | } | ||
155 | |||
156 | static int add_tracepoint_field_value(struct ctf_writer *cw, | ||
157 | struct bt_ctf_event_class *event_class, | ||
158 | struct bt_ctf_event *event, | ||
159 | struct perf_sample *sample, | ||
160 | struct format_field *fmtf) | ||
161 | { | ||
162 | struct bt_ctf_field_type *type; | ||
163 | struct bt_ctf_field *array_field; | ||
164 | struct bt_ctf_field *field; | ||
165 | const char *name = fmtf->name; | ||
166 | void *data = sample->raw_data; | ||
167 | unsigned long long value_int; | ||
168 | unsigned long flags = fmtf->flags; | ||
169 | unsigned int n_items; | ||
170 | unsigned int i; | ||
171 | unsigned int offset; | ||
172 | unsigned int len; | ||
173 | int ret; | ||
174 | |||
175 | offset = fmtf->offset; | ||
176 | len = fmtf->size; | ||
177 | if (flags & FIELD_IS_STRING) | ||
178 | flags &= ~FIELD_IS_ARRAY; | ||
179 | |||
180 | if (flags & FIELD_IS_DYNAMIC) { | ||
181 | unsigned long long tmp_val; | ||
182 | |||
183 | tmp_val = pevent_read_number(fmtf->event->pevent, | ||
184 | data + offset, len); | ||
185 | offset = tmp_val; | ||
186 | len = offset >> 16; | ||
187 | offset &= 0xffff; | ||
188 | } | ||
189 | |||
190 | if (flags & FIELD_IS_ARRAY) { | ||
191 | |||
192 | type = bt_ctf_event_class_get_field_by_name( | ||
193 | event_class, name); | ||
194 | array_field = bt_ctf_field_create(type); | ||
195 | bt_ctf_field_type_put(type); | ||
196 | if (!array_field) { | ||
197 | pr_err("Failed to create array type %s\n", name); | ||
198 | return -1; | ||
199 | } | ||
200 | |||
201 | len = fmtf->size / fmtf->arraylen; | ||
202 | n_items = fmtf->arraylen; | ||
203 | } else { | ||
204 | n_items = 1; | ||
205 | array_field = NULL; | ||
206 | } | ||
207 | |||
208 | type = get_tracepoint_field_type(cw, fmtf); | ||
209 | |||
210 | for (i = 0; i < n_items; i++) { | ||
211 | if (!(flags & FIELD_IS_STRING)) | ||
212 | value_int = pevent_read_number( | ||
213 | fmtf->event->pevent, | ||
214 | data + offset + i * len, len); | ||
215 | |||
216 | if (flags & FIELD_IS_ARRAY) | ||
217 | field = bt_ctf_field_array_get_field(array_field, i); | ||
218 | else | ||
219 | field = bt_ctf_field_create(type); | ||
220 | |||
221 | if (!field) { | ||
222 | pr_err("failed to create a field %s\n", name); | ||
223 | return -1; | ||
224 | } | ||
225 | |||
226 | if (flags & FIELD_IS_STRING) | ||
227 | ret = bt_ctf_field_string_set_value(field, | ||
228 | data + offset + i * len); | ||
229 | else if (!(flags & FIELD_IS_SIGNED)) | ||
230 | ret = bt_ctf_field_unsigned_integer_set_value( | ||
231 | field, value_int); | ||
232 | else | ||
233 | ret = bt_ctf_field_signed_integer_set_value( | ||
234 | field, value_int); | ||
235 | if (ret) { | ||
236 | pr_err("failed to set file value %s\n", name); | ||
237 | goto err_put_field; | ||
238 | } | ||
239 | if (!(flags & FIELD_IS_ARRAY)) { | ||
240 | ret = bt_ctf_event_set_payload(event, name, field); | ||
241 | if (ret) { | ||
242 | pr_err("failed to set payload %s\n", name); | ||
243 | goto err_put_field; | ||
244 | } | ||
245 | } | ||
246 | bt_ctf_field_put(field); | ||
247 | } | ||
248 | if (flags & FIELD_IS_ARRAY) { | ||
249 | ret = bt_ctf_event_set_payload(event, name, array_field); | ||
250 | if (ret) { | ||
251 | pr_err("Failed add payload array %s\n", name); | ||
252 | return -1; | ||
253 | } | ||
254 | bt_ctf_field_put(array_field); | ||
255 | } | ||
256 | return 0; | ||
257 | |||
258 | err_put_field: | ||
259 | bt_ctf_field_put(field); | ||
260 | return -1; | ||
261 | } | ||
262 | |||
263 | static int add_tracepoint_fields_values(struct ctf_writer *cw, | ||
264 | struct bt_ctf_event_class *event_class, | ||
265 | struct bt_ctf_event *event, | ||
266 | struct format_field *fields, | ||
267 | struct perf_sample *sample) | ||
268 | { | ||
269 | struct format_field *field; | ||
270 | int ret; | ||
271 | |||
272 | for (field = fields; field; field = field->next) { | ||
273 | ret = add_tracepoint_field_value(cw, event_class, event, sample, | ||
274 | field); | ||
275 | if (ret) | ||
276 | return -1; | ||
277 | } | ||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | static int add_tracepoint_values(struct ctf_writer *cw, | ||
282 | struct bt_ctf_event_class *event_class, | ||
283 | struct bt_ctf_event *event, | ||
284 | struct perf_evsel *evsel, | ||
285 | struct perf_sample *sample) | ||
286 | { | ||
287 | struct format_field *common_fields = evsel->tp_format->format.common_fields; | ||
288 | struct format_field *fields = evsel->tp_format->format.fields; | ||
289 | int ret; | ||
290 | |||
291 | ret = add_tracepoint_fields_values(cw, event_class, event, | ||
292 | common_fields, sample); | ||
293 | if (!ret) | ||
294 | ret = add_tracepoint_fields_values(cw, event_class, event, | ||
295 | fields, sample); | ||
296 | |||
297 | return ret; | ||
298 | } | ||
299 | |||
129 | static int add_generic_values(struct ctf_writer *cw, | 300 | static int add_generic_values(struct ctf_writer *cw, |
130 | struct bt_ctf_event *event, | 301 | struct bt_ctf_event *event, |
131 | struct perf_evsel *evsel, | 302 | struct perf_evsel *evsel, |
@@ -246,11 +417,76 @@ static int process_sample_event(struct perf_tool *tool, | |||
246 | if (ret) | 417 | if (ret) |
247 | return -1; | 418 | return -1; |
248 | 419 | ||
420 | if (evsel->attr.type == PERF_TYPE_TRACEPOINT) { | ||
421 | ret = add_tracepoint_values(cw, event_class, event, | ||
422 | evsel, sample); | ||
423 | if (ret) | ||
424 | return -1; | ||
425 | } | ||
426 | |||
249 | bt_ctf_stream_append_event(cw->stream, event); | 427 | bt_ctf_stream_append_event(cw->stream, event); |
250 | bt_ctf_event_put(event); | 428 | bt_ctf_event_put(event); |
251 | return 0; | 429 | return 0; |
252 | } | 430 | } |
253 | 431 | ||
432 | static int add_tracepoint_fields_types(struct ctf_writer *cw, | ||
433 | struct format_field *fields, | ||
434 | struct bt_ctf_event_class *event_class) | ||
435 | { | ||
436 | struct format_field *field; | ||
437 | int ret; | ||
438 | |||
439 | for (field = fields; field; field = field->next) { | ||
440 | struct bt_ctf_field_type *type; | ||
441 | unsigned long flags = field->flags; | ||
442 | |||
443 | pr2(" field '%s'\n", field->name); | ||
444 | |||
445 | type = get_tracepoint_field_type(cw, field); | ||
446 | if (!type) | ||
447 | return -1; | ||
448 | |||
449 | /* | ||
450 | * A string is an array of chars. For this we use the string | ||
451 | * type and don't care that it is an array. What we don't | ||
452 | * support is an array of strings. | ||
453 | */ | ||
454 | if (flags & FIELD_IS_STRING) | ||
455 | flags &= ~FIELD_IS_ARRAY; | ||
456 | |||
457 | if (flags & FIELD_IS_ARRAY) | ||
458 | type = bt_ctf_field_type_array_create(type, field->arraylen); | ||
459 | |||
460 | ret = bt_ctf_event_class_add_field(event_class, type, | ||
461 | field->name); | ||
462 | |||
463 | if (flags & FIELD_IS_ARRAY) | ||
464 | bt_ctf_field_type_put(type); | ||
465 | |||
466 | if (ret) { | ||
467 | pr_err("Failed to add field '%s\n", field->name); | ||
468 | return -1; | ||
469 | } | ||
470 | } | ||
471 | |||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | static int add_tracepoint_types(struct ctf_writer *cw, | ||
476 | struct perf_evsel *evsel, | ||
477 | struct bt_ctf_event_class *class) | ||
478 | { | ||
479 | struct format_field *common_fields = evsel->tp_format->format.common_fields; | ||
480 | struct format_field *fields = evsel->tp_format->format.fields; | ||
481 | int ret; | ||
482 | |||
483 | ret = add_tracepoint_fields_types(cw, common_fields, class); | ||
484 | if (!ret) | ||
485 | ret = add_tracepoint_fields_types(cw, fields, class); | ||
486 | |||
487 | return ret; | ||
488 | } | ||
489 | |||
254 | static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel, | 490 | static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel, |
255 | struct bt_ctf_event_class *event_class) | 491 | struct bt_ctf_event_class *event_class) |
256 | { | 492 | { |
@@ -328,6 +564,12 @@ static int add_event(struct ctf_writer *cw, struct perf_evsel *evsel) | |||
328 | if (ret) | 564 | if (ret) |
329 | goto err; | 565 | goto err; |
330 | 566 | ||
567 | if (evsel->attr.type == PERF_TYPE_TRACEPOINT) { | ||
568 | ret = add_tracepoint_types(cw, evsel, event_class); | ||
569 | if (ret) | ||
570 | goto err; | ||
571 | } | ||
572 | |||
331 | ret = bt_ctf_stream_class_add_event_class(cw->stream_class, event_class); | 573 | ret = bt_ctf_stream_class_add_event_class(cw->stream_class, event_class); |
332 | if (ret) { | 574 | if (ret) { |
333 | pr("Failed to add event class into stream.\n"); | 575 | pr("Failed to add event class into stream.\n"); |