[lttng-dev] libbabeltrace: getting CTF sequence length?
Philippe Proulx
eeppeliteloop at gmail.com
Wed May 21 12:20:47 EDT 2014
On Wed, May 21, 2014 at 7:51 AM, Simon Marchi <simon.marchi at polymtl.ca> wrote:
> On 20 May 2014 23:03, Philippe Proulx <eeppeliteloop at gmail.com> wrote:
>> On Tue, May 20, 2014 at 4:50 PM, Jérémie Galarneau
>> <jeremie.galarneau at efficios.com> wrote:
>>> On Tue, May 20, 2014 at 4:37 PM, Philippe Proulx
>>> <eeppeliteloop at gmail.com> wrote:
>>>> Hello,
>>>>
>>>> I'm using libbabeltrace in C++. I would like to know if there's an
>>>> equivalent of bt_ctf_get_array_len() for sequences. I tried using
>>>> bt_ctf_get_field_list() but the reported count was 10, whereas the
>>>> sequence length was really 6 (as shown by the babeltrace tool),
>>>> leading to a segfault when accessing the 7th element.
>>>>
>>>> Looking at the Python binding, I see that this is used:
>>>>
>>>> container_of(field, struct definition_sequence, p);
>>>>
>>>> followed by bt_sequence_len(). However, struct definition_sequence,
>>>> bt_sequence_len() (and bt_sequence_index()) are not available in
>>>> the API.
>>>>
>>>> So what would be your way to read sequence items? Do you have
>>>> an example using strictly what's available in /usr/include/babeltrace?
>>>>
>>>
>>> bt_ctf_get_field_list can be used to get the number of elements, along
>>> with a pointer to the elements (via the output parameters).
>>>
>>
>> Jérémie,
>>
>> consider this test I just wrote:
>>
>> #include <stdlib.h>
>> #include <stdio.h>
>>
>> #include <babeltrace/babeltrace.h>
>> #include <babeltrace/ctf/events.h>
>> #include <babeltrace/ctf/iterator.h>
>>
>> int main(int argc, char* argv[])
>> {
>> struct bt_context* bt_context;
>> struct bt_ctf_iter* bt_ctf_iter;
>> const char* trace_path = argv[1];
>> struct bt_iter_pos begin_pos;
>> struct bt_ctf_event* bt_event;
>> const struct bt_definition* fields_def;
>> const struct bt_declaration* fields_decl;
>> const struct bt_definition* field_def;
>> const struct bt_declaration* field_decl;
>> unsigned int fields_count, seq_items_count;
>> struct bt_definition const* const* fields_list;
>> struct bt_definition const* const* seq_items_list;
>> int ret;
>> unsigned int x, y;
>> unsigned int pos = 1;
>> int err = 0;
>>
>> bt_context = bt_context_create();
>> bt_context_add_trace(bt_context, trace_path, "ctf",
>> NULL, NULL, NULL);
>>
>> begin_pos.type = BT_SEEK_BEGIN;
>> begin_pos.u.seek_time = 0;
>>
>> bt_ctf_iter = bt_ctf_iter_create(bt_context, &begin_pos, NULL);
>>
>> while (bt_event = bt_ctf_iter_read_event(bt_ctf_iter)) {
>> fields_def = bt_ctf_get_top_level_scope(bt_event, BT_EVENT_FIELDS);
>>
>> if (!fields_def) {
>> goto next_event;
>> }
>>
>> fields_decl = bt_ctf_get_decl_from_def(fields_def);
>>
>> if (bt_ctf_field_type(fields_decl) != CTF_TYPE_STRUCT) {
>> goto next_event;
>> }
>>
>> ret = bt_ctf_get_field_list(bt_event, fields_def, &fields_list,
>> &fields_count);
>>
>> if (ret < 0) {
>> goto next_event;
>> }
>>
>> for (x = 0; x < fields_count; ++x) {
>> field_def = fields_list[x];
>>
>> if (!field_def) {
>> printf("field element error\n");
>> goto end;
>> }
>>
>> field_decl = bt_ctf_get_decl_from_def(field_def);
>>
>> if (bt_ctf_field_type(field_decl) == CTF_TYPE_SEQUENCE) {
>> ret = bt_ctf_get_field_list(bt_event, field_def,
>> &seq_items_list,
>> &seq_items_count);
>>
>> if (ret < 0) {
>> /* I guess this means a count of 0? because
>> * it does happen.
>> */
>> goto next_event;
>> }
>>
>> for (y = 0; y < seq_items_count; ++y) {
>> if (!seq_items_list[y]) {
>> printf("error using seq_items_list[y]\n");
>> err = 1;
>> }
>>
>> if (!bt_ctf_get_index(bt_event, field_def, y)) {
>> printf("error using bt_ctf_get_index()\n");
>> err = 1;
>> }
>>
>> if (err) {
>> printf(" event: %s\n",
>> bt_ctf_event_name(bt_event));
>> printf(" position: %u\n", pos);
>> printf(" field: %s\n",
>> bt_ctf_field_name(field_def));
>> printf(" count: %u\n", seq_items_count);
>> goto end;
>> }
>> }
>> }
>> }
>>
>> next_event:
>> if (bt_iter_next(bt_ctf_get_iter(bt_ctf_iter)) < 0) {
>> break;
>> }
>>
>> ++pos;
>> }
>>
>> end:
>> bt_ctf_iter_destroy(bt_ctf_iter);
>> bt_context_put(bt_context);
>>
>> return 0;
>> }
>>
>> Running it with this trace <http://0x3b.org/bbt/bbt.tgz>, I get this:
>>
>> error using bt_ctf_get_index()
>> event: scsi_dispatch_cmd_start
>> position: 46627
>> field: cmnd
>> count: 10
>>
>> So... the count is 10, and there's stuff in seq_items_list[6] to
>> seq_items_list[9]
>> which is not NULL, yet bt_ctf_get_index() complains at element 6 (not written
>> in the results here, but I know it).
>>
>> Why is the count 10 if only 6 elements are good? The babeltrace tool knows this
>> too:
>>
>> $ babeltrace -i ctf kernel 2>/dev/null | sed -n 46627p
>> [21:40:00.281269992] (+0.000003741) eeppdesk
>> scsi_dispatch_cmd_start: { cpu_id = 0 }, { host_no = 10, channel = 0,
>> id = 0, lun = 0, opcode = 0, cmd_len = 6, data_sglen = 0, prot_sglen =
>> 0, prot_op = 0, _cmnd_length = 6, cmnd = [ [0] = 0x0, [1] = 0x0, [2] =
>> 0x0, [3] = 0x0, [4] = 0x0, [5] = 0x0 ] }
>>
>> See, cmd_len is 6 and we see 6 elements in the cmnd field.
>>
>> My question is still: where do I get this 6 from?
>>
>> Thanks,
>> Phil
>
> Here is what I think happens:
>
> For each sequence definition, BT allocates a field list that only
> grows. If it first encounters an event with this sequence where it
> contains 6 events, it will allocate an array of 6 fields. Then, when
> it encounters an event where the sequence has 10 events, the buffer is
> grown to 10 fields. This happens in bt_sequence_rw, in
> types/sequence.c. If, later, an event with a sequence of 6 elements is
> read, only the first 6 slots of the fields array will be used.
> Therefore, you (or the library) should always refer to the integer
> definition to know the real count of events in the sequence, and NOT
> to the allocated array length.
>
> There is even a nice comment about that in bt_sequence_rw:
>
> /*
> * Yes, large sequences could be _painfully slow_ to parse due
> * to memory allocation for each event read. At least, never
> * shrink the sequence. Note: the sequence GArray len should
> * never be used as indicator of the current sequence length.
> * One should always look at the sequence->len->value._unsigned
> * value for that.
> */
>
> bt_ctf_get_field_list however, returns you the length of the array:
>
> *list = (struct bt_definition const* const*) def_sequence->elems->pdata;
> *count = def_sequence->elems->len;
>
> Changing that to get the actual length of the sequence makes your
> example work (see patch in [1]).
Thanks Simon for investigating this! No more errors with this patch.
Phil
> That would be a bug in babeltrace,
> unless the intent of the bt_ctf_get_field_list is actually to return
> all the allocated fields, but I don't see any reason to do that.
>
> [1] http://paste.ubuntu.com/7497072/
More information about the lttng-dev
mailing list