|
@@ -352,6 +352,84 @@ static int add_tracepoint_values(struct ctf_writer *cw,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static int
|
|
|
+add_bpf_output_values(struct bt_ctf_event_class *event_class,
|
|
|
+ struct bt_ctf_event *event,
|
|
|
+ struct perf_sample *sample)
|
|
|
+{
|
|
|
+ struct bt_ctf_field_type *len_type, *seq_type;
|
|
|
+ struct bt_ctf_field *len_field, *seq_field;
|
|
|
+ unsigned int raw_size = sample->raw_size;
|
|
|
+ unsigned int nr_elements = raw_size / sizeof(u32);
|
|
|
+ unsigned int i;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (nr_elements * sizeof(u32) != raw_size)
|
|
|
+ pr_warning("Incorrect raw_size (%u) in bpf output event, skip %lu bytes\n",
|
|
|
+ raw_size, nr_elements * sizeof(u32) - raw_size);
|
|
|
+
|
|
|
+ len_type = bt_ctf_event_class_get_field_by_name(event_class, "raw_len");
|
|
|
+ len_field = bt_ctf_field_create(len_type);
|
|
|
+ if (!len_field) {
|
|
|
+ pr_err("failed to create 'raw_len' for bpf output event\n");
|
|
|
+ ret = -1;
|
|
|
+ goto put_len_type;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = bt_ctf_field_unsigned_integer_set_value(len_field, nr_elements);
|
|
|
+ if (ret) {
|
|
|
+ pr_err("failed to set field value for raw_len\n");
|
|
|
+ goto put_len_field;
|
|
|
+ }
|
|
|
+ ret = bt_ctf_event_set_payload(event, "raw_len", len_field);
|
|
|
+ if (ret) {
|
|
|
+ pr_err("failed to set payload to raw_len\n");
|
|
|
+ goto put_len_field;
|
|
|
+ }
|
|
|
+
|
|
|
+ seq_type = bt_ctf_event_class_get_field_by_name(event_class, "raw_data");
|
|
|
+ seq_field = bt_ctf_field_create(seq_type);
|
|
|
+ if (!seq_field) {
|
|
|
+ pr_err("failed to create 'raw_data' for bpf output event\n");
|
|
|
+ ret = -1;
|
|
|
+ goto put_seq_type;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = bt_ctf_field_sequence_set_length(seq_field, len_field);
|
|
|
+ if (ret) {
|
|
|
+ pr_err("failed to set length of 'raw_data'\n");
|
|
|
+ goto put_seq_field;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < nr_elements; i++) {
|
|
|
+ struct bt_ctf_field *elem_field =
|
|
|
+ bt_ctf_field_sequence_get_field(seq_field, i);
|
|
|
+
|
|
|
+ ret = bt_ctf_field_unsigned_integer_set_value(elem_field,
|
|
|
+ ((u32 *)(sample->raw_data))[i]);
|
|
|
+
|
|
|
+ bt_ctf_field_put(elem_field);
|
|
|
+ if (ret) {
|
|
|
+ pr_err("failed to set raw_data[%d]\n", i);
|
|
|
+ goto put_seq_field;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = bt_ctf_event_set_payload(event, "raw_data", seq_field);
|
|
|
+ if (ret)
|
|
|
+ pr_err("failed to set payload for raw_data\n");
|
|
|
+
|
|
|
+put_seq_field:
|
|
|
+ bt_ctf_field_put(seq_field);
|
|
|
+put_seq_type:
|
|
|
+ bt_ctf_field_type_put(seq_type);
|
|
|
+put_len_field:
|
|
|
+ bt_ctf_field_put(len_field);
|
|
|
+put_len_type:
|
|
|
+ bt_ctf_field_type_put(len_type);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
static int add_generic_values(struct ctf_writer *cw,
|
|
|
struct bt_ctf_event *event,
|
|
|
struct perf_evsel *evsel,
|
|
@@ -597,6 +675,12 @@ static int process_sample_event(struct perf_tool *tool,
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
+ if (perf_evsel__is_bpf_output(evsel)) {
|
|
|
+ ret = add_bpf_output_values(event_class, event, sample);
|
|
|
+ if (ret)
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
cs = ctf_stream(cw, get_sample_cpu(cw, sample, evsel));
|
|
|
if (cs) {
|
|
|
if (is_flush_needed(cs))
|
|
@@ -744,6 +828,25 @@ static int add_tracepoint_types(struct ctf_writer *cw,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static int add_bpf_output_types(struct ctf_writer *cw,
|
|
|
+ struct bt_ctf_event_class *class)
|
|
|
+{
|
|
|
+ struct bt_ctf_field_type *len_type = cw->data.u32;
|
|
|
+ struct bt_ctf_field_type *seq_base_type = cw->data.u32_hex;
|
|
|
+ struct bt_ctf_field_type *seq_type;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = bt_ctf_event_class_add_field(class, len_type, "raw_len");
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ seq_type = bt_ctf_field_type_sequence_create(seq_base_type, "raw_len");
|
|
|
+ if (!seq_type)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ return bt_ctf_event_class_add_field(class, seq_type, "raw_data");
|
|
|
+}
|
|
|
+
|
|
|
static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel,
|
|
|
struct bt_ctf_event_class *event_class)
|
|
|
{
|
|
@@ -755,7 +858,8 @@ static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel,
|
|
|
* ctf event header
|
|
|
* PERF_SAMPLE_READ - TODO
|
|
|
* PERF_SAMPLE_CALLCHAIN - TODO
|
|
|
- * PERF_SAMPLE_RAW - tracepoint fields are handled separately
|
|
|
+ * PERF_SAMPLE_RAW - tracepoint fields and BPF output
|
|
|
+ * are handled separately
|
|
|
* PERF_SAMPLE_BRANCH_STACK - TODO
|
|
|
* PERF_SAMPLE_REGS_USER - TODO
|
|
|
* PERF_SAMPLE_STACK_USER - TODO
|
|
@@ -824,6 +928,12 @@ static int add_event(struct ctf_writer *cw, struct perf_evsel *evsel)
|
|
|
goto err;
|
|
|
}
|
|
|
|
|
|
+ if (perf_evsel__is_bpf_output(evsel)) {
|
|
|
+ ret = add_bpf_output_types(cw, event_class);
|
|
|
+ if (ret)
|
|
|
+ goto err;
|
|
|
+ }
|
|
|
+
|
|
|
ret = bt_ctf_stream_class_add_event_class(cw->stream_class, event_class);
|
|
|
if (ret) {
|
|
|
pr("Failed to add event class into stream.\n");
|