1 /* 2 * CTF writing support via babeltrace. 3 * 4 * Copyright (C) 2014, Jiri Olsa <jolsa@redhat.com> 5 * Copyright (C) 2014, Sebastian Andrzej Siewior <bigeasy@linutronix.de> 6 * 7 * Released under the GPL v2. (and only v2, not any later version) 8 */ 9 10 #include <linux/compiler.h> 11 #include <babeltrace/ctf-writer/writer.h> 12 #include <babeltrace/ctf-writer/clock.h> 13 #include <babeltrace/ctf-writer/stream.h> 14 #include <babeltrace/ctf-writer/event.h> 15 #include <babeltrace/ctf-writer/event-types.h> 16 #include <babeltrace/ctf-writer/event-fields.h> 17 #include <babeltrace/ctf/events.h> 18 #include <traceevent/event-parse.h> 19 #include "asm/bug.h" 20 #include "data-convert-bt.h" 21 #include "session.h" 22 #include "util.h" 23 #include "debug.h" 24 #include "tool.h" 25 #include "evlist.h" 26 #include "evsel.h" 27 #include "machine.h" 28 29 #define pr_N(n, fmt, ...) \ 30 eprintf(n, debug_data_convert, fmt, ##__VA_ARGS__) 31 32 #define pr(fmt, ...) pr_N(1, pr_fmt(fmt), ##__VA_ARGS__) 33 #define pr2(fmt, ...) pr_N(2, pr_fmt(fmt), ##__VA_ARGS__) 34 35 #define pr_time2(t, fmt, ...) pr_time_N(2, debug_data_convert, t, pr_fmt(fmt), ##__VA_ARGS__) 36 37 struct evsel_priv { 38 struct bt_ctf_event_class *event_class; 39 }; 40 41 struct ctf_writer { 42 /* writer primitives */ 43 struct bt_ctf_writer *writer; 44 struct bt_ctf_stream *stream; 45 struct bt_ctf_stream_class *stream_class; 46 struct bt_ctf_clock *clock; 47 48 /* data types */ 49 union { 50 struct { 51 struct bt_ctf_field_type *s64; 52 struct bt_ctf_field_type *u64; 53 struct bt_ctf_field_type *s32; 54 struct bt_ctf_field_type *u32; 55 struct bt_ctf_field_type *string; 56 struct bt_ctf_field_type *u64_hex; 57 }; 58 struct bt_ctf_field_type *array[6]; 59 } data; 60 }; 61 62 struct convert { 63 struct perf_tool tool; 64 struct ctf_writer writer; 65 66 u64 events_size; 67 u64 events_count; 68 }; 69 70 static int value_set(struct bt_ctf_field_type *type, 71 struct bt_ctf_event *event, 72 const char *name, u64 val) 73 { 74 struct bt_ctf_field *field; 75 bool sign = bt_ctf_field_type_integer_get_signed(type); 76 int ret; 77 78 field = bt_ctf_field_create(type); 79 if (!field) { 80 pr_err("failed to create a field %s\n", name); 81 return -1; 82 } 83 84 if (sign) { 85 ret = bt_ctf_field_signed_integer_set_value(field, val); 86 if (ret) { 87 pr_err("failed to set field value %s\n", name); 88 goto err; 89 } 90 } else { 91 ret = bt_ctf_field_unsigned_integer_set_value(field, val); 92 if (ret) { 93 pr_err("failed to set field value %s\n", name); 94 goto err; 95 } 96 } 97 98 ret = bt_ctf_event_set_payload(event, name, field); 99 if (ret) { 100 pr_err("failed to set payload %s\n", name); 101 goto err; 102 } 103 104 pr2(" SET [%s = %" PRIu64 "]\n", name, val); 105 106 err: 107 bt_ctf_field_put(field); 108 return ret; 109 } 110 111 #define __FUNC_VALUE_SET(_name, _val_type) \ 112 static __maybe_unused int value_set_##_name(struct ctf_writer *cw, \ 113 struct bt_ctf_event *event, \ 114 const char *name, \ 115 _val_type val) \ 116 { \ 117 struct bt_ctf_field_type *type = cw->data._name; \ 118 return value_set(type, event, name, (u64) val); \ 119 } 120 121 #define FUNC_VALUE_SET(_name) __FUNC_VALUE_SET(_name, _name) 122 123 FUNC_VALUE_SET(s32) 124 FUNC_VALUE_SET(u32) 125 FUNC_VALUE_SET(s64) 126 FUNC_VALUE_SET(u64) 127 __FUNC_VALUE_SET(u64_hex, u64) 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 300 static int add_generic_values(struct ctf_writer *cw, 301 struct bt_ctf_event *event, 302 struct perf_evsel *evsel, 303 struct perf_sample *sample) 304 { 305 u64 type = evsel->attr.sample_type; 306 int ret; 307 308 /* 309 * missing: 310 * PERF_SAMPLE_TIME - not needed as we have it in 311 * ctf event header 312 * PERF_SAMPLE_READ - TODO 313 * PERF_SAMPLE_CALLCHAIN - TODO 314 * PERF_SAMPLE_RAW - tracepoint fields are handled separately 315 * PERF_SAMPLE_BRANCH_STACK - TODO 316 * PERF_SAMPLE_REGS_USER - TODO 317 * PERF_SAMPLE_STACK_USER - TODO 318 */ 319 320 if (type & PERF_SAMPLE_IP) { 321 ret = value_set_u64_hex(cw, event, "perf_ip", sample->ip); 322 if (ret) 323 return -1; 324 } 325 326 if (type & PERF_SAMPLE_TID) { 327 ret = value_set_s32(cw, event, "perf_tid", sample->tid); 328 if (ret) 329 return -1; 330 331 ret = value_set_s32(cw, event, "perf_pid", sample->pid); 332 if (ret) 333 return -1; 334 } 335 336 if ((type & PERF_SAMPLE_ID) || 337 (type & PERF_SAMPLE_IDENTIFIER)) { 338 ret = value_set_u64(cw, event, "perf_id", sample->id); 339 if (ret) 340 return -1; 341 } 342 343 if (type & PERF_SAMPLE_STREAM_ID) { 344 ret = value_set_u64(cw, event, "perf_stream_id", sample->stream_id); 345 if (ret) 346 return -1; 347 } 348 349 if (type & PERF_SAMPLE_CPU) { 350 ret = value_set_u32(cw, event, "perf_cpu", sample->cpu); 351 if (ret) 352 return -1; 353 } 354 355 if (type & PERF_SAMPLE_PERIOD) { 356 ret = value_set_u64(cw, event, "perf_period", sample->period); 357 if (ret) 358 return -1; 359 } 360 361 if (type & PERF_SAMPLE_WEIGHT) { 362 ret = value_set_u64(cw, event, "perf_weight", sample->weight); 363 if (ret) 364 return -1; 365 } 366 367 if (type & PERF_SAMPLE_DATA_SRC) { 368 ret = value_set_u64(cw, event, "perf_data_src", 369 sample->data_src); 370 if (ret) 371 return -1; 372 } 373 374 if (type & PERF_SAMPLE_TRANSACTION) { 375 ret = value_set_u64(cw, event, "perf_transaction", 376 sample->transaction); 377 if (ret) 378 return -1; 379 } 380 381 return 0; 382 } 383 384 static int process_sample_event(struct perf_tool *tool, 385 union perf_event *_event __maybe_unused, 386 struct perf_sample *sample, 387 struct perf_evsel *evsel, 388 struct machine *machine __maybe_unused) 389 { 390 struct convert *c = container_of(tool, struct convert, tool); 391 struct evsel_priv *priv = evsel->priv; 392 struct ctf_writer *cw = &c->writer; 393 struct bt_ctf_event_class *event_class; 394 struct bt_ctf_event *event; 395 int ret; 396 397 if (WARN_ONCE(!priv, "Failed to setup all events.\n")) 398 return 0; 399 400 event_class = priv->event_class; 401 402 /* update stats */ 403 c->events_count++; 404 c->events_size += _event->header.size; 405 406 pr_time2(sample->time, "sample %" PRIu64 "\n", c->events_count); 407 408 event = bt_ctf_event_create(event_class); 409 if (!event) { 410 pr_err("Failed to create an CTF event\n"); 411 return -1; 412 } 413 414 bt_ctf_clock_set_time(cw->clock, sample->time); 415 416 ret = add_generic_values(cw, event, evsel, sample); 417 if (ret) 418 return -1; 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 427 bt_ctf_stream_append_event(cw->stream, event); 428 bt_ctf_event_put(event); 429 return 0; 430 } 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 490 static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel, 491 struct bt_ctf_event_class *event_class) 492 { 493 u64 type = evsel->attr.sample_type; 494 495 /* 496 * missing: 497 * PERF_SAMPLE_TIME - not needed as we have it in 498 * ctf event header 499 * PERF_SAMPLE_READ - TODO 500 * PERF_SAMPLE_CALLCHAIN - TODO 501 * PERF_SAMPLE_RAW - tracepoint fields are handled separately 502 * PERF_SAMPLE_BRANCH_STACK - TODO 503 * PERF_SAMPLE_REGS_USER - TODO 504 * PERF_SAMPLE_STACK_USER - TODO 505 */ 506 507 #define ADD_FIELD(cl, t, n) \ 508 do { \ 509 pr2(" field '%s'\n", n); \ 510 if (bt_ctf_event_class_add_field(cl, t, n)) { \ 511 pr_err("Failed to add field '%s;\n", n); \ 512 return -1; \ 513 } \ 514 } while (0) 515 516 if (type & PERF_SAMPLE_IP) 517 ADD_FIELD(event_class, cw->data.u64_hex, "perf_ip"); 518 519 if (type & PERF_SAMPLE_TID) { 520 ADD_FIELD(event_class, cw->data.s32, "perf_tid"); 521 ADD_FIELD(event_class, cw->data.s32, "perf_pid"); 522 } 523 524 if ((type & PERF_SAMPLE_ID) || 525 (type & PERF_SAMPLE_IDENTIFIER)) 526 ADD_FIELD(event_class, cw->data.u64, "perf_id"); 527 528 if (type & PERF_SAMPLE_STREAM_ID) 529 ADD_FIELD(event_class, cw->data.u64, "perf_stream_id"); 530 531 if (type & PERF_SAMPLE_CPU) 532 ADD_FIELD(event_class, cw->data.u32, "perf_cpu"); 533 534 if (type & PERF_SAMPLE_PERIOD) 535 ADD_FIELD(event_class, cw->data.u64, "perf_period"); 536 537 if (type & PERF_SAMPLE_WEIGHT) 538 ADD_FIELD(event_class, cw->data.u64, "perf_weight"); 539 540 if (type & PERF_SAMPLE_DATA_SRC) 541 ADD_FIELD(event_class, cw->data.u64, "perf_data_src"); 542 543 if (type & PERF_SAMPLE_TRANSACTION) 544 ADD_FIELD(event_class, cw->data.u64, "perf_transaction"); 545 546 #undef ADD_FIELD 547 return 0; 548 } 549 550 static int add_event(struct ctf_writer *cw, struct perf_evsel *evsel) 551 { 552 struct bt_ctf_event_class *event_class; 553 struct evsel_priv *priv; 554 const char *name = perf_evsel__name(evsel); 555 int ret; 556 557 pr("Adding event '%s' (type %d)\n", name, evsel->attr.type); 558 559 event_class = bt_ctf_event_class_create(name); 560 if (!event_class) 561 return -1; 562 563 ret = add_generic_types(cw, evsel, event_class); 564 if (ret) 565 goto err; 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 573 ret = bt_ctf_stream_class_add_event_class(cw->stream_class, event_class); 574 if (ret) { 575 pr("Failed to add event class into stream.\n"); 576 goto err; 577 } 578 579 priv = malloc(sizeof(*priv)); 580 if (!priv) 581 goto err; 582 583 priv->event_class = event_class; 584 evsel->priv = priv; 585 return 0; 586 587 err: 588 bt_ctf_event_class_put(event_class); 589 pr_err("Failed to add event '%s'.\n", name); 590 return -1; 591 } 592 593 static int setup_events(struct ctf_writer *cw, struct perf_session *session) 594 { 595 struct perf_evlist *evlist = session->evlist; 596 struct perf_evsel *evsel; 597 int ret; 598 599 evlist__for_each(evlist, evsel) { 600 ret = add_event(cw, evsel); 601 if (ret) 602 return ret; 603 } 604 return 0; 605 } 606 607 static int ctf_writer__setup_env(struct ctf_writer *cw, 608 struct perf_session *session) 609 { 610 struct perf_header *header = &session->header; 611 struct bt_ctf_writer *writer = cw->writer; 612 613 #define ADD(__n, __v) \ 614 do { \ 615 if (bt_ctf_writer_add_environment_field(writer, __n, __v)) \ 616 return -1; \ 617 } while (0) 618 619 ADD("host", header->env.hostname); 620 ADD("sysname", "Linux"); 621 ADD("release", header->env.os_release); 622 ADD("version", header->env.version); 623 ADD("machine", header->env.arch); 624 ADD("domain", "kernel"); 625 ADD("tracer_name", "perf"); 626 627 #undef ADD 628 return 0; 629 } 630 631 static int ctf_writer__setup_clock(struct ctf_writer *cw) 632 { 633 struct bt_ctf_clock *clock = cw->clock; 634 635 bt_ctf_clock_set_description(clock, "perf clock"); 636 637 #define SET(__n, __v) \ 638 do { \ 639 if (bt_ctf_clock_set_##__n(clock, __v)) \ 640 return -1; \ 641 } while (0) 642 643 SET(frequency, 1000000000); 644 SET(offset_s, 0); 645 SET(offset, 0); 646 SET(precision, 10); 647 SET(is_absolute, 0); 648 649 #undef SET 650 return 0; 651 } 652 653 static struct bt_ctf_field_type *create_int_type(int size, bool sign, bool hex) 654 { 655 struct bt_ctf_field_type *type; 656 657 type = bt_ctf_field_type_integer_create(size); 658 if (!type) 659 return NULL; 660 661 if (sign && 662 bt_ctf_field_type_integer_set_signed(type, 1)) 663 goto err; 664 665 if (hex && 666 bt_ctf_field_type_integer_set_base(type, BT_CTF_INTEGER_BASE_HEXADECIMAL)) 667 goto err; 668 669 pr2("Created type: INTEGER %d-bit %ssigned %s\n", 670 size, sign ? "un" : "", hex ? "hex" : ""); 671 return type; 672 673 err: 674 bt_ctf_field_type_put(type); 675 return NULL; 676 } 677 678 static void ctf_writer__cleanup_data(struct ctf_writer *cw) 679 { 680 unsigned int i; 681 682 for (i = 0; i < ARRAY_SIZE(cw->data.array); i++) 683 bt_ctf_field_type_put(cw->data.array[i]); 684 } 685 686 static int ctf_writer__init_data(struct ctf_writer *cw) 687 { 688 #define CREATE_INT_TYPE(type, size, sign, hex) \ 689 do { \ 690 (type) = create_int_type(size, sign, hex); \ 691 if (!(type)) \ 692 goto err; \ 693 } while (0) 694 695 CREATE_INT_TYPE(cw->data.s64, 64, true, false); 696 CREATE_INT_TYPE(cw->data.u64, 64, false, false); 697 CREATE_INT_TYPE(cw->data.s32, 32, true, false); 698 CREATE_INT_TYPE(cw->data.u32, 32, false, false); 699 CREATE_INT_TYPE(cw->data.u64_hex, 64, false, true); 700 701 cw->data.string = bt_ctf_field_type_string_create(); 702 if (cw->data.string) 703 return 0; 704 705 err: 706 ctf_writer__cleanup_data(cw); 707 pr_err("Failed to create data types.\n"); 708 return -1; 709 } 710 711 static void ctf_writer__cleanup(struct ctf_writer *cw) 712 { 713 ctf_writer__cleanup_data(cw); 714 715 bt_ctf_clock_put(cw->clock); 716 bt_ctf_stream_put(cw->stream); 717 bt_ctf_stream_class_put(cw->stream_class); 718 bt_ctf_writer_put(cw->writer); 719 720 /* and NULL all the pointers */ 721 memset(cw, 0, sizeof(*cw)); 722 } 723 724 static int ctf_writer__init(struct ctf_writer *cw, const char *path) 725 { 726 struct bt_ctf_writer *writer; 727 struct bt_ctf_stream_class *stream_class; 728 struct bt_ctf_stream *stream; 729 struct bt_ctf_clock *clock; 730 731 /* CTF writer */ 732 writer = bt_ctf_writer_create(path); 733 if (!writer) 734 goto err; 735 736 cw->writer = writer; 737 738 /* CTF clock */ 739 clock = bt_ctf_clock_create("perf_clock"); 740 if (!clock) { 741 pr("Failed to create CTF clock.\n"); 742 goto err_cleanup; 743 } 744 745 cw->clock = clock; 746 747 if (ctf_writer__setup_clock(cw)) { 748 pr("Failed to setup CTF clock.\n"); 749 goto err_cleanup; 750 } 751 752 /* CTF stream class */ 753 stream_class = bt_ctf_stream_class_create("perf_stream"); 754 if (!stream_class) { 755 pr("Failed to create CTF stream class.\n"); 756 goto err_cleanup; 757 } 758 759 cw->stream_class = stream_class; 760 761 /* CTF clock stream setup */ 762 if (bt_ctf_stream_class_set_clock(stream_class, clock)) { 763 pr("Failed to assign CTF clock to stream class.\n"); 764 goto err_cleanup; 765 } 766 767 if (ctf_writer__init_data(cw)) 768 goto err_cleanup; 769 770 /* CTF stream instance */ 771 stream = bt_ctf_writer_create_stream(writer, stream_class); 772 if (!stream) { 773 pr("Failed to create CTF stream.\n"); 774 goto err_cleanup; 775 } 776 777 cw->stream = stream; 778 779 /* CTF clock writer setup */ 780 if (bt_ctf_writer_add_clock(writer, clock)) { 781 pr("Failed to assign CTF clock to writer.\n"); 782 goto err_cleanup; 783 } 784 785 return 0; 786 787 err_cleanup: 788 ctf_writer__cleanup(cw); 789 err: 790 pr_err("Failed to setup CTF writer.\n"); 791 return -1; 792 } 793 794 int bt_convert__perf2ctf(const char *input, const char *path, bool force) 795 { 796 struct perf_session *session; 797 struct perf_data_file file = { 798 .path = input, 799 .mode = PERF_DATA_MODE_READ, 800 .force = force, 801 }; 802 struct convert c = { 803 .tool = { 804 .sample = process_sample_event, 805 .mmap = perf_event__process_mmap, 806 .mmap2 = perf_event__process_mmap2, 807 .comm = perf_event__process_comm, 808 .exit = perf_event__process_exit, 809 .fork = perf_event__process_fork, 810 .lost = perf_event__process_lost, 811 .tracing_data = perf_event__process_tracing_data, 812 .build_id = perf_event__process_build_id, 813 .ordered_events = true, 814 .ordering_requires_timestamps = true, 815 }, 816 }; 817 struct ctf_writer *cw = &c.writer; 818 int err = -1; 819 820 /* CTF writer */ 821 if (ctf_writer__init(cw, path)) 822 return -1; 823 824 /* perf.data session */ 825 session = perf_session__new(&file, 0, &c.tool); 826 if (!session) 827 goto free_writer; 828 829 /* CTF writer env/clock setup */ 830 if (ctf_writer__setup_env(cw, session)) 831 goto free_session; 832 833 /* CTF events setup */ 834 if (setup_events(cw, session)) 835 goto free_session; 836 837 err = perf_session__process_events(session); 838 if (!err) 839 err = bt_ctf_stream_flush(cw->stream); 840 841 fprintf(stderr, 842 "[ perf data convert: Converted '%s' into CTF data '%s' ]\n", 843 file.path, path); 844 845 fprintf(stderr, 846 "[ perf data convert: Converted and wrote %.3f MB (%" PRIu64 " samples) ]\n", 847 (double) c.events_size / 1024.0 / 1024.0, 848 c.events_count); 849 850 /* its all good */ 851 free_session: 852 perf_session__delete(session); 853 854 free_writer: 855 ctf_writer__cleanup(cw); 856 return err; 857 } 858