data-convert-bt.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857
  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. #include <linux/compiler.h>
  10. #include <babeltrace/ctf-writer/writer.h>
  11. #include <babeltrace/ctf-writer/clock.h>
  12. #include <babeltrace/ctf-writer/stream.h>
  13. #include <babeltrace/ctf-writer/event.h>
  14. #include <babeltrace/ctf-writer/event-types.h>
  15. #include <babeltrace/ctf-writer/event-fields.h>
  16. #include <babeltrace/ctf/events.h>
  17. #include <traceevent/event-parse.h>
  18. #include "asm/bug.h"
  19. #include "data-convert-bt.h"
  20. #include "session.h"
  21. #include "util.h"
  22. #include "debug.h"
  23. #include "tool.h"
  24. #include "evlist.h"
  25. #include "evsel.h"
  26. #include "machine.h"
  27. #define pr_N(n, fmt, ...) \
  28. eprintf(n, debug_data_convert, fmt, ##__VA_ARGS__)
  29. #define pr(fmt, ...) pr_N(1, pr_fmt(fmt), ##__VA_ARGS__)
  30. #define pr2(fmt, ...) pr_N(2, pr_fmt(fmt), ##__VA_ARGS__)
  31. #define pr_time2(t, fmt, ...) pr_time_N(2, debug_data_convert, t, pr_fmt(fmt), ##__VA_ARGS__)
  32. struct evsel_priv {
  33. struct bt_ctf_event_class *event_class;
  34. };
  35. struct ctf_writer {
  36. /* writer primitives */
  37. struct bt_ctf_writer *writer;
  38. struct bt_ctf_stream *stream;
  39. struct bt_ctf_stream_class *stream_class;
  40. struct bt_ctf_clock *clock;
  41. /* data types */
  42. union {
  43. struct {
  44. struct bt_ctf_field_type *s64;
  45. struct bt_ctf_field_type *u64;
  46. struct bt_ctf_field_type *s32;
  47. struct bt_ctf_field_type *u32;
  48. struct bt_ctf_field_type *string;
  49. struct bt_ctf_field_type *u64_hex;
  50. };
  51. struct bt_ctf_field_type *array[6];
  52. } data;
  53. };
  54. struct convert {
  55. struct perf_tool tool;
  56. struct ctf_writer writer;
  57. u64 events_size;
  58. u64 events_count;
  59. };
  60. static int value_set(struct bt_ctf_field_type *type,
  61. struct bt_ctf_event *event,
  62. const char *name, u64 val)
  63. {
  64. struct bt_ctf_field *field;
  65. bool sign = bt_ctf_field_type_integer_get_signed(type);
  66. int ret;
  67. field = bt_ctf_field_create(type);
  68. if (!field) {
  69. pr_err("failed to create a field %s\n", name);
  70. return -1;
  71. }
  72. if (sign) {
  73. ret = bt_ctf_field_signed_integer_set_value(field, val);
  74. if (ret) {
  75. pr_err("failed to set field value %s\n", name);
  76. goto err;
  77. }
  78. } else {
  79. ret = bt_ctf_field_unsigned_integer_set_value(field, val);
  80. if (ret) {
  81. pr_err("failed to set field value %s\n", name);
  82. goto err;
  83. }
  84. }
  85. ret = bt_ctf_event_set_payload(event, name, field);
  86. if (ret) {
  87. pr_err("failed to set payload %s\n", name);
  88. goto err;
  89. }
  90. pr2(" SET [%s = %" PRIu64 "]\n", name, val);
  91. err:
  92. bt_ctf_field_put(field);
  93. return ret;
  94. }
  95. #define __FUNC_VALUE_SET(_name, _val_type) \
  96. static __maybe_unused int value_set_##_name(struct ctf_writer *cw, \
  97. struct bt_ctf_event *event, \
  98. const char *name, \
  99. _val_type val) \
  100. { \
  101. struct bt_ctf_field_type *type = cw->data._name; \
  102. return value_set(type, event, name, (u64) val); \
  103. }
  104. #define FUNC_VALUE_SET(_name) __FUNC_VALUE_SET(_name, _name)
  105. FUNC_VALUE_SET(s32)
  106. FUNC_VALUE_SET(u32)
  107. FUNC_VALUE_SET(s64)
  108. FUNC_VALUE_SET(u64)
  109. __FUNC_VALUE_SET(u64_hex, u64)
  110. static struct bt_ctf_field_type*
  111. get_tracepoint_field_type(struct ctf_writer *cw, struct format_field *field)
  112. {
  113. unsigned long flags = field->flags;
  114. if (flags & FIELD_IS_STRING)
  115. return cw->data.string;
  116. if (!(flags & FIELD_IS_SIGNED)) {
  117. /* unsigned long are mostly pointers */
  118. if (flags & FIELD_IS_LONG || flags & FIELD_IS_POINTER)
  119. return cw->data.u64_hex;
  120. }
  121. if (flags & FIELD_IS_SIGNED) {
  122. if (field->size == 8)
  123. return cw->data.s64;
  124. else
  125. return cw->data.s32;
  126. }
  127. if (field->size == 8)
  128. return cw->data.u64;
  129. else
  130. return cw->data.u32;
  131. }
  132. static int add_tracepoint_field_value(struct ctf_writer *cw,
  133. struct bt_ctf_event_class *event_class,
  134. struct bt_ctf_event *event,
  135. struct perf_sample *sample,
  136. struct format_field *fmtf)
  137. {
  138. struct bt_ctf_field_type *type;
  139. struct bt_ctf_field *array_field;
  140. struct bt_ctf_field *field;
  141. const char *name = fmtf->name;
  142. void *data = sample->raw_data;
  143. unsigned long long value_int;
  144. unsigned long flags = fmtf->flags;
  145. unsigned int n_items;
  146. unsigned int i;
  147. unsigned int offset;
  148. unsigned int len;
  149. int ret;
  150. offset = fmtf->offset;
  151. len = fmtf->size;
  152. if (flags & FIELD_IS_STRING)
  153. flags &= ~FIELD_IS_ARRAY;
  154. if (flags & FIELD_IS_DYNAMIC) {
  155. unsigned long long tmp_val;
  156. tmp_val = pevent_read_number(fmtf->event->pevent,
  157. data + offset, len);
  158. offset = tmp_val;
  159. len = offset >> 16;
  160. offset &= 0xffff;
  161. }
  162. if (flags & FIELD_IS_ARRAY) {
  163. type = bt_ctf_event_class_get_field_by_name(
  164. event_class, name);
  165. array_field = bt_ctf_field_create(type);
  166. bt_ctf_field_type_put(type);
  167. if (!array_field) {
  168. pr_err("Failed to create array type %s\n", name);
  169. return -1;
  170. }
  171. len = fmtf->size / fmtf->arraylen;
  172. n_items = fmtf->arraylen;
  173. } else {
  174. n_items = 1;
  175. array_field = NULL;
  176. }
  177. type = get_tracepoint_field_type(cw, fmtf);
  178. for (i = 0; i < n_items; i++) {
  179. if (!(flags & FIELD_IS_STRING))
  180. value_int = pevent_read_number(
  181. fmtf->event->pevent,
  182. data + offset + i * len, len);
  183. if (flags & FIELD_IS_ARRAY)
  184. field = bt_ctf_field_array_get_field(array_field, i);
  185. else
  186. field = bt_ctf_field_create(type);
  187. if (!field) {
  188. pr_err("failed to create a field %s\n", name);
  189. return -1;
  190. }
  191. if (flags & FIELD_IS_STRING)
  192. ret = bt_ctf_field_string_set_value(field,
  193. data + offset + i * len);
  194. else if (!(flags & FIELD_IS_SIGNED))
  195. ret = bt_ctf_field_unsigned_integer_set_value(
  196. field, value_int);
  197. else
  198. ret = bt_ctf_field_signed_integer_set_value(
  199. field, value_int);
  200. if (ret) {
  201. pr_err("failed to set file value %s\n", name);
  202. goto err_put_field;
  203. }
  204. if (!(flags & FIELD_IS_ARRAY)) {
  205. ret = bt_ctf_event_set_payload(event, name, field);
  206. if (ret) {
  207. pr_err("failed to set payload %s\n", name);
  208. goto err_put_field;
  209. }
  210. }
  211. bt_ctf_field_put(field);
  212. }
  213. if (flags & FIELD_IS_ARRAY) {
  214. ret = bt_ctf_event_set_payload(event, name, array_field);
  215. if (ret) {
  216. pr_err("Failed add payload array %s\n", name);
  217. return -1;
  218. }
  219. bt_ctf_field_put(array_field);
  220. }
  221. return 0;
  222. err_put_field:
  223. bt_ctf_field_put(field);
  224. return -1;
  225. }
  226. static int add_tracepoint_fields_values(struct ctf_writer *cw,
  227. struct bt_ctf_event_class *event_class,
  228. struct bt_ctf_event *event,
  229. struct format_field *fields,
  230. struct perf_sample *sample)
  231. {
  232. struct format_field *field;
  233. int ret;
  234. for (field = fields; field; field = field->next) {
  235. ret = add_tracepoint_field_value(cw, event_class, event, sample,
  236. field);
  237. if (ret)
  238. return -1;
  239. }
  240. return 0;
  241. }
  242. static int add_tracepoint_values(struct ctf_writer *cw,
  243. struct bt_ctf_event_class *event_class,
  244. struct bt_ctf_event *event,
  245. struct perf_evsel *evsel,
  246. struct perf_sample *sample)
  247. {
  248. struct format_field *common_fields = evsel->tp_format->format.common_fields;
  249. struct format_field *fields = evsel->tp_format->format.fields;
  250. int ret;
  251. ret = add_tracepoint_fields_values(cw, event_class, event,
  252. common_fields, sample);
  253. if (!ret)
  254. ret = add_tracepoint_fields_values(cw, event_class, event,
  255. fields, sample);
  256. return ret;
  257. }
  258. static int add_generic_values(struct ctf_writer *cw,
  259. struct bt_ctf_event *event,
  260. struct perf_evsel *evsel,
  261. struct perf_sample *sample)
  262. {
  263. u64 type = evsel->attr.sample_type;
  264. int ret;
  265. /*
  266. * missing:
  267. * PERF_SAMPLE_TIME - not needed as we have it in
  268. * ctf event header
  269. * PERF_SAMPLE_READ - TODO
  270. * PERF_SAMPLE_CALLCHAIN - TODO
  271. * PERF_SAMPLE_RAW - tracepoint fields are handled separately
  272. * PERF_SAMPLE_BRANCH_STACK - TODO
  273. * PERF_SAMPLE_REGS_USER - TODO
  274. * PERF_SAMPLE_STACK_USER - TODO
  275. */
  276. if (type & PERF_SAMPLE_IP) {
  277. ret = value_set_u64_hex(cw, event, "perf_ip", sample->ip);
  278. if (ret)
  279. return -1;
  280. }
  281. if (type & PERF_SAMPLE_TID) {
  282. ret = value_set_s32(cw, event, "perf_tid", sample->tid);
  283. if (ret)
  284. return -1;
  285. ret = value_set_s32(cw, event, "perf_pid", sample->pid);
  286. if (ret)
  287. return -1;
  288. }
  289. if ((type & PERF_SAMPLE_ID) ||
  290. (type & PERF_SAMPLE_IDENTIFIER)) {
  291. ret = value_set_u64(cw, event, "perf_id", sample->id);
  292. if (ret)
  293. return -1;
  294. }
  295. if (type & PERF_SAMPLE_STREAM_ID) {
  296. ret = value_set_u64(cw, event, "perf_stream_id", sample->stream_id);
  297. if (ret)
  298. return -1;
  299. }
  300. if (type & PERF_SAMPLE_CPU) {
  301. ret = value_set_u32(cw, event, "perf_cpu", sample->cpu);
  302. if (ret)
  303. return -1;
  304. }
  305. if (type & PERF_SAMPLE_PERIOD) {
  306. ret = value_set_u64(cw, event, "perf_period", sample->period);
  307. if (ret)
  308. return -1;
  309. }
  310. if (type & PERF_SAMPLE_WEIGHT) {
  311. ret = value_set_u64(cw, event, "perf_weight", sample->weight);
  312. if (ret)
  313. return -1;
  314. }
  315. if (type & PERF_SAMPLE_DATA_SRC) {
  316. ret = value_set_u64(cw, event, "perf_data_src",
  317. sample->data_src);
  318. if (ret)
  319. return -1;
  320. }
  321. if (type & PERF_SAMPLE_TRANSACTION) {
  322. ret = value_set_u64(cw, event, "perf_transaction",
  323. sample->transaction);
  324. if (ret)
  325. return -1;
  326. }
  327. return 0;
  328. }
  329. static int process_sample_event(struct perf_tool *tool,
  330. union perf_event *_event __maybe_unused,
  331. struct perf_sample *sample,
  332. struct perf_evsel *evsel,
  333. struct machine *machine __maybe_unused)
  334. {
  335. struct convert *c = container_of(tool, struct convert, tool);
  336. struct evsel_priv *priv = evsel->priv;
  337. struct ctf_writer *cw = &c->writer;
  338. struct bt_ctf_event_class *event_class;
  339. struct bt_ctf_event *event;
  340. int ret;
  341. if (WARN_ONCE(!priv, "Failed to setup all events.\n"))
  342. return 0;
  343. event_class = priv->event_class;
  344. /* update stats */
  345. c->events_count++;
  346. c->events_size += _event->header.size;
  347. pr_time2(sample->time, "sample %" PRIu64 "\n", c->events_count);
  348. event = bt_ctf_event_create(event_class);
  349. if (!event) {
  350. pr_err("Failed to create an CTF event\n");
  351. return -1;
  352. }
  353. bt_ctf_clock_set_time(cw->clock, sample->time);
  354. ret = add_generic_values(cw, event, evsel, sample);
  355. if (ret)
  356. return -1;
  357. if (evsel->attr.type == PERF_TYPE_TRACEPOINT) {
  358. ret = add_tracepoint_values(cw, event_class, event,
  359. evsel, sample);
  360. if (ret)
  361. return -1;
  362. }
  363. bt_ctf_stream_append_event(cw->stream, event);
  364. bt_ctf_event_put(event);
  365. return 0;
  366. }
  367. static int add_tracepoint_fields_types(struct ctf_writer *cw,
  368. struct format_field *fields,
  369. struct bt_ctf_event_class *event_class)
  370. {
  371. struct format_field *field;
  372. int ret;
  373. for (field = fields; field; field = field->next) {
  374. struct bt_ctf_field_type *type;
  375. unsigned long flags = field->flags;
  376. pr2(" field '%s'\n", field->name);
  377. type = get_tracepoint_field_type(cw, field);
  378. if (!type)
  379. return -1;
  380. /*
  381. * A string is an array of chars. For this we use the string
  382. * type and don't care that it is an array. What we don't
  383. * support is an array of strings.
  384. */
  385. if (flags & FIELD_IS_STRING)
  386. flags &= ~FIELD_IS_ARRAY;
  387. if (flags & FIELD_IS_ARRAY)
  388. type = bt_ctf_field_type_array_create(type, field->arraylen);
  389. ret = bt_ctf_event_class_add_field(event_class, type,
  390. field->name);
  391. if (flags & FIELD_IS_ARRAY)
  392. bt_ctf_field_type_put(type);
  393. if (ret) {
  394. pr_err("Failed to add field '%s\n", field->name);
  395. return -1;
  396. }
  397. }
  398. return 0;
  399. }
  400. static int add_tracepoint_types(struct ctf_writer *cw,
  401. struct perf_evsel *evsel,
  402. struct bt_ctf_event_class *class)
  403. {
  404. struct format_field *common_fields = evsel->tp_format->format.common_fields;
  405. struct format_field *fields = evsel->tp_format->format.fields;
  406. int ret;
  407. ret = add_tracepoint_fields_types(cw, common_fields, class);
  408. if (!ret)
  409. ret = add_tracepoint_fields_types(cw, fields, class);
  410. return ret;
  411. }
  412. static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel,
  413. struct bt_ctf_event_class *event_class)
  414. {
  415. u64 type = evsel->attr.sample_type;
  416. /*
  417. * missing:
  418. * PERF_SAMPLE_TIME - not needed as we have it in
  419. * ctf event header
  420. * PERF_SAMPLE_READ - TODO
  421. * PERF_SAMPLE_CALLCHAIN - TODO
  422. * PERF_SAMPLE_RAW - tracepoint fields are handled separately
  423. * PERF_SAMPLE_BRANCH_STACK - TODO
  424. * PERF_SAMPLE_REGS_USER - TODO
  425. * PERF_SAMPLE_STACK_USER - TODO
  426. */
  427. #define ADD_FIELD(cl, t, n) \
  428. do { \
  429. pr2(" field '%s'\n", n); \
  430. if (bt_ctf_event_class_add_field(cl, t, n)) { \
  431. pr_err("Failed to add field '%s;\n", n); \
  432. return -1; \
  433. } \
  434. } while (0)
  435. if (type & PERF_SAMPLE_IP)
  436. ADD_FIELD(event_class, cw->data.u64_hex, "perf_ip");
  437. if (type & PERF_SAMPLE_TID) {
  438. ADD_FIELD(event_class, cw->data.s32, "perf_tid");
  439. ADD_FIELD(event_class, cw->data.s32, "perf_pid");
  440. }
  441. if ((type & PERF_SAMPLE_ID) ||
  442. (type & PERF_SAMPLE_IDENTIFIER))
  443. ADD_FIELD(event_class, cw->data.u64, "perf_id");
  444. if (type & PERF_SAMPLE_STREAM_ID)
  445. ADD_FIELD(event_class, cw->data.u64, "perf_stream_id");
  446. if (type & PERF_SAMPLE_CPU)
  447. ADD_FIELD(event_class, cw->data.u32, "perf_cpu");
  448. if (type & PERF_SAMPLE_PERIOD)
  449. ADD_FIELD(event_class, cw->data.u64, "perf_period");
  450. if (type & PERF_SAMPLE_WEIGHT)
  451. ADD_FIELD(event_class, cw->data.u64, "perf_weight");
  452. if (type & PERF_SAMPLE_DATA_SRC)
  453. ADD_FIELD(event_class, cw->data.u64, "perf_data_src");
  454. if (type & PERF_SAMPLE_TRANSACTION)
  455. ADD_FIELD(event_class, cw->data.u64, "perf_transaction");
  456. #undef ADD_FIELD
  457. return 0;
  458. }
  459. static int add_event(struct ctf_writer *cw, struct perf_evsel *evsel)
  460. {
  461. struct bt_ctf_event_class *event_class;
  462. struct evsel_priv *priv;
  463. const char *name = perf_evsel__name(evsel);
  464. int ret;
  465. pr("Adding event '%s' (type %d)\n", name, evsel->attr.type);
  466. event_class = bt_ctf_event_class_create(name);
  467. if (!event_class)
  468. return -1;
  469. ret = add_generic_types(cw, evsel, event_class);
  470. if (ret)
  471. goto err;
  472. if (evsel->attr.type == PERF_TYPE_TRACEPOINT) {
  473. ret = add_tracepoint_types(cw, evsel, event_class);
  474. if (ret)
  475. goto err;
  476. }
  477. ret = bt_ctf_stream_class_add_event_class(cw->stream_class, event_class);
  478. if (ret) {
  479. pr("Failed to add event class into stream.\n");
  480. goto err;
  481. }
  482. priv = malloc(sizeof(*priv));
  483. if (!priv)
  484. goto err;
  485. priv->event_class = event_class;
  486. evsel->priv = priv;
  487. return 0;
  488. err:
  489. bt_ctf_event_class_put(event_class);
  490. pr_err("Failed to add event '%s'.\n", name);
  491. return -1;
  492. }
  493. static int setup_events(struct ctf_writer *cw, struct perf_session *session)
  494. {
  495. struct perf_evlist *evlist = session->evlist;
  496. struct perf_evsel *evsel;
  497. int ret;
  498. evlist__for_each(evlist, evsel) {
  499. ret = add_event(cw, evsel);
  500. if (ret)
  501. return ret;
  502. }
  503. return 0;
  504. }
  505. static int ctf_writer__setup_env(struct ctf_writer *cw,
  506. struct perf_session *session)
  507. {
  508. struct perf_header *header = &session->header;
  509. struct bt_ctf_writer *writer = cw->writer;
  510. #define ADD(__n, __v) \
  511. do { \
  512. if (bt_ctf_writer_add_environment_field(writer, __n, __v)) \
  513. return -1; \
  514. } while (0)
  515. ADD("host", header->env.hostname);
  516. ADD("sysname", "Linux");
  517. ADD("release", header->env.os_release);
  518. ADD("version", header->env.version);
  519. ADD("machine", header->env.arch);
  520. ADD("domain", "kernel");
  521. ADD("tracer_name", "perf");
  522. #undef ADD
  523. return 0;
  524. }
  525. static int ctf_writer__setup_clock(struct ctf_writer *cw)
  526. {
  527. struct bt_ctf_clock *clock = cw->clock;
  528. bt_ctf_clock_set_description(clock, "perf clock");
  529. #define SET(__n, __v) \
  530. do { \
  531. if (bt_ctf_clock_set_##__n(clock, __v)) \
  532. return -1; \
  533. } while (0)
  534. SET(frequency, 1000000000);
  535. SET(offset_s, 0);
  536. SET(offset, 0);
  537. SET(precision, 10);
  538. SET(is_absolute, 0);
  539. #undef SET
  540. return 0;
  541. }
  542. static struct bt_ctf_field_type *create_int_type(int size, bool sign, bool hex)
  543. {
  544. struct bt_ctf_field_type *type;
  545. type = bt_ctf_field_type_integer_create(size);
  546. if (!type)
  547. return NULL;
  548. if (sign &&
  549. bt_ctf_field_type_integer_set_signed(type, 1))
  550. goto err;
  551. if (hex &&
  552. bt_ctf_field_type_integer_set_base(type, BT_CTF_INTEGER_BASE_HEXADECIMAL))
  553. goto err;
  554. pr2("Created type: INTEGER %d-bit %ssigned %s\n",
  555. size, sign ? "un" : "", hex ? "hex" : "");
  556. return type;
  557. err:
  558. bt_ctf_field_type_put(type);
  559. return NULL;
  560. }
  561. static void ctf_writer__cleanup_data(struct ctf_writer *cw)
  562. {
  563. unsigned int i;
  564. for (i = 0; i < ARRAY_SIZE(cw->data.array); i++)
  565. bt_ctf_field_type_put(cw->data.array[i]);
  566. }
  567. static int ctf_writer__init_data(struct ctf_writer *cw)
  568. {
  569. #define CREATE_INT_TYPE(type, size, sign, hex) \
  570. do { \
  571. (type) = create_int_type(size, sign, hex); \
  572. if (!(type)) \
  573. goto err; \
  574. } while (0)
  575. CREATE_INT_TYPE(cw->data.s64, 64, true, false);
  576. CREATE_INT_TYPE(cw->data.u64, 64, false, false);
  577. CREATE_INT_TYPE(cw->data.s32, 32, true, false);
  578. CREATE_INT_TYPE(cw->data.u32, 32, false, false);
  579. CREATE_INT_TYPE(cw->data.u64_hex, 64, false, true);
  580. cw->data.string = bt_ctf_field_type_string_create();
  581. if (cw->data.string)
  582. return 0;
  583. err:
  584. ctf_writer__cleanup_data(cw);
  585. pr_err("Failed to create data types.\n");
  586. return -1;
  587. }
  588. static void ctf_writer__cleanup(struct ctf_writer *cw)
  589. {
  590. ctf_writer__cleanup_data(cw);
  591. bt_ctf_clock_put(cw->clock);
  592. bt_ctf_stream_put(cw->stream);
  593. bt_ctf_stream_class_put(cw->stream_class);
  594. bt_ctf_writer_put(cw->writer);
  595. /* and NULL all the pointers */
  596. memset(cw, 0, sizeof(*cw));
  597. }
  598. static int ctf_writer__init(struct ctf_writer *cw, const char *path)
  599. {
  600. struct bt_ctf_writer *writer;
  601. struct bt_ctf_stream_class *stream_class;
  602. struct bt_ctf_stream *stream;
  603. struct bt_ctf_clock *clock;
  604. /* CTF writer */
  605. writer = bt_ctf_writer_create(path);
  606. if (!writer)
  607. goto err;
  608. cw->writer = writer;
  609. /* CTF clock */
  610. clock = bt_ctf_clock_create("perf_clock");
  611. if (!clock) {
  612. pr("Failed to create CTF clock.\n");
  613. goto err_cleanup;
  614. }
  615. cw->clock = clock;
  616. if (ctf_writer__setup_clock(cw)) {
  617. pr("Failed to setup CTF clock.\n");
  618. goto err_cleanup;
  619. }
  620. /* CTF stream class */
  621. stream_class = bt_ctf_stream_class_create("perf_stream");
  622. if (!stream_class) {
  623. pr("Failed to create CTF stream class.\n");
  624. goto err_cleanup;
  625. }
  626. cw->stream_class = stream_class;
  627. /* CTF clock stream setup */
  628. if (bt_ctf_stream_class_set_clock(stream_class, clock)) {
  629. pr("Failed to assign CTF clock to stream class.\n");
  630. goto err_cleanup;
  631. }
  632. if (ctf_writer__init_data(cw))
  633. goto err_cleanup;
  634. /* CTF stream instance */
  635. stream = bt_ctf_writer_create_stream(writer, stream_class);
  636. if (!stream) {
  637. pr("Failed to create CTF stream.\n");
  638. goto err_cleanup;
  639. }
  640. cw->stream = stream;
  641. /* CTF clock writer setup */
  642. if (bt_ctf_writer_add_clock(writer, clock)) {
  643. pr("Failed to assign CTF clock to writer.\n");
  644. goto err_cleanup;
  645. }
  646. return 0;
  647. err_cleanup:
  648. ctf_writer__cleanup(cw);
  649. err:
  650. pr_err("Failed to setup CTF writer.\n");
  651. return -1;
  652. }
  653. int bt_convert__perf2ctf(const char *input, const char *path, bool force)
  654. {
  655. struct perf_session *session;
  656. struct perf_data_file file = {
  657. .path = input,
  658. .mode = PERF_DATA_MODE_READ,
  659. .force = force,
  660. };
  661. struct convert c = {
  662. .tool = {
  663. .sample = process_sample_event,
  664. .mmap = perf_event__process_mmap,
  665. .mmap2 = perf_event__process_mmap2,
  666. .comm = perf_event__process_comm,
  667. .exit = perf_event__process_exit,
  668. .fork = perf_event__process_fork,
  669. .lost = perf_event__process_lost,
  670. .tracing_data = perf_event__process_tracing_data,
  671. .build_id = perf_event__process_build_id,
  672. .ordered_events = true,
  673. .ordering_requires_timestamps = true,
  674. },
  675. };
  676. struct ctf_writer *cw = &c.writer;
  677. int err = -1;
  678. /* CTF writer */
  679. if (ctf_writer__init(cw, path))
  680. return -1;
  681. /* perf.data session */
  682. session = perf_session__new(&file, 0, &c.tool);
  683. if (!session)
  684. goto free_writer;
  685. /* CTF writer env/clock setup */
  686. if (ctf_writer__setup_env(cw, session))
  687. goto free_session;
  688. /* CTF events setup */
  689. if (setup_events(cw, session))
  690. goto free_session;
  691. err = perf_session__process_events(session);
  692. if (!err)
  693. err = bt_ctf_stream_flush(cw->stream);
  694. fprintf(stderr,
  695. "[ perf data convert: Converted '%s' into CTF data '%s' ]\n",
  696. file.path, path);
  697. fprintf(stderr,
  698. "[ perf data convert: Converted and wrote %.3f MB (%" PRIu64 " samples) ]\n",
  699. (double) c.events_size / 1024.0 / 1024.0,
  700. c.events_count);
  701. /* its all good */
  702. free_session:
  703. perf_session__delete(session);
  704. free_writer:
  705. ctf_writer__cleanup(cw);
  706. return err;
  707. }