* Julien Desfossez ([email protected]) wrote:
> 
> 
> On 16/08/12 09:30 PM, Mathieu Desnoyers wrote:
> > Inspired from patch by Francis Deslauriers and Julien Desfossez.
> > 
> > Comments are welcome. I left a FIXME as question.
> > 
> > Not tested.
> I tested it, it is working, just need to add the "break" missing I added
> in comments below.

OK, fixed. I pushed the following:

commit f7ed656326285831256061407c2c533c16c50f36
Author: Mathieu Desnoyers <[email protected]>
Date:   Fri Aug 17 00:01:54 2012 -0400

    Add BT_SEEK_LAST type to bt_iter_pos
    
    Inspired from patch by Francis Deslauriers and Julien Desfossez.
    
    Acked-by: Julien Desfossez <[email protected]>
    Signed-off-by: Mathieu Desnoyers <[email protected]>

Thanks!

Mathieu

> 
> > 
> > Not-Signed-off-by: Mathieu Desnoyers <[email protected]>
> > ---
> > diff --git a/include/babeltrace/iterator.h b/include/babeltrace/iterator.h
> > index aa6470e..98504a5 100644
> > --- a/include/babeltrace/iterator.h
> > +++ b/include/babeltrace/iterator.h
> > @@ -40,6 +40,15 @@ struct bt_saved_pos;
> >   *   is expressed in nanoseconds
> >   * - restore is a position saved with bt_iter_get_pos, it is used with
> >   *   BT_SEEK_RESTORE.
> > + *
> > + * Note about BT_SEEK_LAST: if many events happen to be at the last
> > + * timestamp, it is implementation-defined which event will be the last,
> > + * and the order of events with the same timestamp may not be the same
> > + * as normal iteration on the trace. Therefore, it is recommended to
> > + * only use BT_SEEK_LAST to get the timestamp of the last event(s) in
> > + * the trace.
> > + * FIXME: should we name it BT_SEEK_LAST_TIMESTAMP instead, if we ever
> > + * want to keep BT_SEEK_LAST for the last event in iteration order ?
> >   */
> >  struct bt_iter_pos {
> >     enum {
> > @@ -48,6 +57,7 @@ struct bt_iter_pos {
> >             BT_SEEK_CUR,
> >             BT_SEEK_BEGIN,
> >             BT_SEEK_END,
> > +           BT_SEEK_LAST,
> >     } type;
> >     union {
> >             uint64_t seek_time;
> > diff --git a/lib/iterator.c b/lib/iterator.c
> > index 2dbd77c..b305f16 100644
> > --- a/lib/iterator.c
> > +++ b/lib/iterator.c
> > @@ -103,6 +103,10 @@ void bt_iter_free_pos(struct bt_iter_pos *iter_pos)
> >   *
> >   * Return 0 if the seek succeded, EOF if we didn't find any packet
> >   * containing the timestamp, or a positive integer for error.
> > + *
> > + * TODO: this should be turned into a binary search! It is currently
> > + * doing a linear search in the packets. This is a O(n) operation on a
> > + * very frequent code path.
> >   */
> >  static int seek_file_stream_by_timestamp(struct ctf_file_stream *cfs,
> >             uint64_t timestamp)
> > @@ -187,6 +191,148 @@ static int seek_ctf_trace_by_timestamp(struct 
> > ctf_trace *tin,
> >     return found ? 0 : EOF;
> >  }
> >  
> > +/*
> > + * Find timestamp of last event in the stream.
> > + *
> > + * Return value: 0 if OK, positive error value on error, EOF if no
> > + * events were found.
> > + */
> > +static int find_max_timestamp_ctf_file_stream(struct ctf_file_stream *cfs,
> > +           uint64_t *timestamp_end)
> > +{
> > +   int ret, count = 0, i;
> > +   uint64_t timestamp = 0;
> > +   struct ctf_stream_pos *stream_pos;
> > +
> > +   stream_pos = &cfs->pos;
> > +   /*
> > +    * We start by the last packet, and iterate backwards until we
> > +    * either find at least one event, or we reach the first packet
> > +    * (some packets can be empty).
> > +    */
> > +   for (i = stream_pos->packet_real_index->len - 1; i >= 0; i--) {
> > +           stream_pos->packet_seek(&stream_pos->parent, i, SEEK_SET);
> > +           count = 0;
> > +           /* read each event until we reach the end of the stream */
> > +           do {
> > +                   ret = stream_read_event(cfs);
> > +                   if (ret == 0) {
> > +                           count++;
> > +                           timestamp = cfs->parent.real_timestamp;
> > +                   }
> > +           } while (ret == 0);
> > +
> > +           /* Error */
> > +           if (ret > 0)
> > +                   goto end;
> > +           assert(ret == EOF);
> > +           if (count)
> > +                   break;
> > +   }
> > +
> > +   if (count) {
> > +           *timestamp_end = timestamp;
> > +           ret = 0;
> > +   } else {
> > +           /* Return EOF if no events were found */
> > +           ret = EOF;
> > +   }
> > +end:
> > +   return ret;
> > +}
> > +
> > +/*
> > + * Find the stream within a stream class that contains the event with
> > + * the largest timestamp, and save that timestamp.
> > + *
> > + * Return 0 if OK, EOF if no events were found in the streams, or
> > + * positive value on error.
> > + */
> > +static int find_max_timestamp_ctf_stream_class(
> > +           struct ctf_stream_declaration *stream_class,
> > +           struct ctf_file_stream **cfsp,
> > +           uint64_t *max_timestamp)
> > +{
> > +   int ret = EOF, i;
> > +
> > +   for (i = 0; i < stream_class->streams->len; i++) {
> > +           struct ctf_stream_definition *stream;
> > +           struct ctf_file_stream *cfs;
> > +           uint64_t current_max_ts = 0;
> > +
> > +           stream = g_ptr_array_index(stream_class->streams, i);
> > +           if (!stream)
> > +                   continue;
> > +           cfs = container_of(stream, struct ctf_file_stream, parent);
> > +           ret = find_max_timestamp_ctf_file_stream(cfs, &current_max_ts);
> > +           if (ret == EOF)
> > +                   continue;
> > +           if (ret != 0)
> > +                   break;
> > +           if (current_max_ts >= *max_timestamp) {
> > +                   *max_timestamp = current_max_ts;
> > +                   *cfsp = cfs;
> > +           }
> > +   }
> > +   assert(ret >= 0 || ret == EOF);
> > +   return ret;
> > +}
> > +
> > +/*
> > + * seek_last_ctf_trace_collection: seek trace collection to last event.
> > + *
> > + * Return 0 if OK, EOF if no events were found, or positive error value
> > + * on error.
> > + */
> > +static int seek_last_ctf_trace_collection(struct trace_collection *tc,
> > +           struct ctf_file_stream **cfsp)
> > +{
> > +   int i, j, ret;
> > +   int found = 0;
> > +   uint64_t max_timestamp = 0;
> > +
> > +   if (!tc)
> > +           return 1;
> > +
> > +   /* For each trace in the trace_collection */
> > +   for (i = 0; i < tc->array->len; i++) {
> > +           struct ctf_trace *tin;
> > +           struct trace_descriptor *td_read;
> > +
> > +           td_read = g_ptr_array_index(tc->array, i);
> > +           if (!td_read)
> > +                   continue;
> > +           tin = container_of(td_read, struct ctf_trace, parent);
> > +           /* For each stream_class in the trace */
> > +           for (j = 0; j < tin->streams->len; j++) {
> > +                   struct ctf_stream_declaration *stream_class;
> > +
> > +                   stream_class = g_ptr_array_index(tin->streams, j);
> > +                   if (!stream_class)
> > +                           continue;
> > +                   ret = find_max_timestamp_ctf_stream_class(stream_class,
> > +                                   cfsp, &max_timestamp);
> > +                   if (ret > 0)
> > +                           goto end;
> > +                   if (ret == 0)
> > +                           found = 1;
> > +                   assert(ret == EOF || ret == 0);
> > +           }
> > +   }
> > +   /*
> > +    * Now we know in which file stream the last event is located,
> > +    * and we know its timestamp.
> > +    */
> > +   if (!found) {
> > +           ret = EOF;
> > +   } else {
> > +           ret = seek_file_stream_by_timestamp(*cfsp, max_timestamp);
> > +           assert(ret == 0);
> > +   }
> > +end:
> > +   return ret;
> > +}
> > +
> >  int bt_iter_set_pos(struct bt_iter *iter, const struct bt_iter_pos 
> > *iter_pos)
> >  {
> >     struct trace_collection *tc;
> > @@ -332,6 +478,25 @@ int bt_iter_set_pos(struct bt_iter *iter, const struct 
> > bt_iter_pos *iter_pos)
> >                     }
> >             }
> >             break;
> > +   case BT_SEEK_LAST:
> > +   {
> > +           struct ctf_file_stream *cfs;
> > +
> > +           tc = iter->ctx->tc;
> > +           ret = seek_last_ctf_trace_collection(tc, &cfs);
> > +           if (ret != 0)
> > +                   goto error;
> > +           /* remove all streams from the heap */
> > +           heap_free(iter->stream_heap);
> > +           /* Create a new empty heap */
> > +           ret = heap_init(iter->stream_heap, 0, stream_compare);
> > +           if (ret < 0)
> > +                   goto error;
> > +           /* Insert the stream that contains the last event */
> > +           ret = heap_insert(iter->stream_heap, cfs);
> > +           if (ret)
> > +                   goto error;
> break or return missing here.
> > +   }
> >     default:
> >             /* not implemented */
> >             return -EINVAL;

-- 
Mathieu Desnoyers
Operating System Efficiency R&D Consultant
EfficiOS Inc.
http://www.efficios.com

_______________________________________________
lttng-dev mailing list
[email protected]
http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev

Reply via email to