linux/tools/perf/util/data-convert-bt.c
<<
>>
Prefs
   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
  37struct evsel_priv {
  38        struct bt_ctf_event_class *event_class;
  39};
  40
  41struct 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
  62struct convert {
  63        struct perf_tool        tool;
  64        struct ctf_writer       writer;
  65
  66        u64                     events_size;
  67        u64                     events_count;
  68};
  69
  70static 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
 106err:
 107        bt_ctf_field_put(field);
 108        return ret;
 109}
 110
 111#define __FUNC_VALUE_SET(_name, _val_type)                              \
 112static __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
 123FUNC_VALUE_SET(s32)
 124FUNC_VALUE_SET(u32)
 125FUNC_VALUE_SET(s64)
 126FUNC_VALUE_SET(u64)
 127__FUNC_VALUE_SET(u64_hex, u64)
 128
 129static struct bt_ctf_field_type*
 130get_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
 156static 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
 258err_put_field:
 259        bt_ctf_field_put(field);
 260        return -1;
 261}
 262
 263static 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
 281static 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
 300static 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
 384static 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
 432static 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
 475static 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
 490static 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
 550static 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
 587err:
 588        bt_ctf_event_class_put(event_class);
 589        pr_err("Failed to add event '%s'.\n", name);
 590        return -1;
 591}
 592
 593static 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
 607static 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)                                                   \
 614do {                                                                    \
 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
 631static 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)                           \
 638do {                                            \
 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
 653static 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
 673err:
 674        bt_ctf_field_type_put(type);
 675        return NULL;
 676}
 677
 678static 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
 686static int ctf_writer__init_data(struct ctf_writer *cw)
 687{
 688#define CREATE_INT_TYPE(type, size, sign, hex)          \
 689do {                                                    \
 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
 705err:
 706        ctf_writer__cleanup_data(cw);
 707        pr_err("Failed to create data types.\n");
 708        return -1;
 709}
 710
 711static 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
 724static 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
 787err_cleanup:
 788        ctf_writer__cleanup(cw);
 789err:
 790        pr_err("Failed to setup CTF writer.\n");
 791        return -1;
 792}
 793
 794int 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 */
 851free_session:
 852        perf_session__delete(session);
 853
 854free_writer:
 855        ctf_writer__cleanup(cw);
 856        return err;
 857}
 858