+guint ltt_tracefile_block_number(LttTracefile *tf)
+{
+ return tf->num_blocks;
+}
+
+
+/* Seek to the first event in a tracefile that has a time equal or greater than
+ * the time passed in parameter.
+ *
+ * If the time parameter is outside the tracefile time span, seek to the first
+ * event or if after, return ERANGE.
+ *
+ * If the time parameter is before the first event, we have to seek specially to
+ * there.
+ *
+ * If the time is after the end of the trace, return ERANGE.
+ *
+ * Do a binary search to find the right block, then a sequential search in the
+ * block to find the event.
+ *
+ * In the special case where the time requested fits inside a block that has no
+ * event corresponding to the requested time, the first event of the next block
+ * will be seeked.
+ *
+ * IMPORTANT NOTE : // FIXME everywhere...
+ *
+ * You MUST NOT do a ltt_tracefile_read right after a ltt_tracefile_seek_time :
+ * you will jump over an event if you do.
+ *
+ * Return value : 0 : no error, the tf->event can be used
+ * ERANGE : time if after the last event of the trace
+ * otherwise : this is an error.
+ *
+ * */
+
+int ltt_tracefile_seek_time(LttTracefile *tf, LttTime time)
+{
+ int ret = 0;
+ int err;
+ unsigned int block_num, high, low;
+
+ /* seek at the beginning of trace */
+ err = map_block(tf, 0); /* First block */
+ if(unlikely(err)) {
+ g_error("Can not map block");
+ goto fail;
+ }
+
+ /* If the time is lower or equal the beginning of the trace,
+ * go to the first event. */
+ if(ltt_time_compare(time, tf->buffer.begin.timestamp) <= 0) {
+ ret = ltt_tracefile_read(tf);
+ if(ret == ERANGE) goto range;
+ else if (ret) goto fail;
+ goto found; /* There is either no event in the trace or the event points
+ to the first event in the trace */
+ }
+
+ err = map_block(tf, tf->num_blocks - 1); /* Last block */
+ if(unlikely(err)) {
+ g_error("Can not map block");
+ goto fail;
+ }
+
+ /* If the time is after the end of the trace, return ERANGE. */
+ if(ltt_time_compare(time, tf->buffer.end.timestamp) > 0) {
+ goto range;
+ }
+
+ /* Binary search the block */
+ high = tf->num_blocks - 1;
+ low = 0;
+
+ while(1) {
+ block_num = ((high-low) / 2) + low;
+
+ err = map_block(tf, block_num);
+ if(unlikely(err)) {
+ g_error("Can not map block");
+ goto fail;
+ }
+ if(high == low) {
+ /* We cannot divide anymore : this is what would happen if the time
+ * requested was exactly between two consecutive buffers'end and start
+ * timestamps. This is also what would happend if we didn't deal with out
+ * of span cases prior in this function. */
+ /* The event is right in the buffer!
+ * (or in the next buffer first event) */
+ while(1) {
+ ret = ltt_tracefile_read(tf);
+ if(ret == ERANGE) goto range; /* ERANGE or EPERM */
+ else if(ret) goto fail;
+
+ if(ltt_time_compare(time, tf->event.event_time) <= 0)
+ goto found;
+ }
+
+ } else if(ltt_time_compare(time, tf->buffer.begin.timestamp) < 0) {
+ /* go to lower part */
+ high = block_num - 1;
+ } else if(ltt_time_compare(time, tf->buffer.end.timestamp) > 0) {
+ /* go to higher part */
+ low = block_num + 1;
+ } else {/* The event is right in the buffer!
+ (or in the next buffer first event) */
+ while(1) {
+ ret = ltt_tracefile_read(tf);
+ if(ret == ERANGE) goto range; /* ERANGE or EPERM */
+ else if(ret) goto fail;
+
+ if(ltt_time_compare(time, tf->event.event_time) <= 0)
+ break;
+ }
+ goto found;
+ }
+ }
+
+found:
+ return 0;
+range:
+ return ERANGE;
+
+ /* Error handling */
+fail:
+ g_error("ltt_tracefile_seek_time failed on tracefile %s",
+ g_quark_to_string(tf->name));
+ return EPERM;
+}
+
+
+int ltt_tracefile_seek_position(LttTracefile *tf, const LttEventPosition *ep) {
+
+ int err;
+
+ if(ep->tracefile != tf) {
+ goto fail;
+ }
+
+ err = map_block(tf, ep->block);
+ if(unlikely(err)) {
+ g_error("Can not map block");
+ goto fail;
+ }
+
+ tf->event.offset = ep->offset;
+
+ /* Put back the event real tsc */
+ tf->event.tsc = ep->tsc;
+ tf->buffer.tsc = ep->tsc;
+
+ err = ltt_tracefile_read_update_event(tf);
+ if(err) goto fail;
+ err = ltt_tracefile_read_op(tf);
+ if(err) goto fail;
+
+ return 0;
+
+fail:
+ g_error("ltt_tracefile_seek_time failed on tracefile %s",
+ g_quark_to_string(tf->name));
+ return 1;
+}
+
+LttTime ltt_interpolate_time_from_tsc(LttTracefile *tf, guint64 tsc)
+{
+ LttTime time;
+
+ if(tsc > tf->trace->start_tsc) {
+ time = ltt_time_from_uint64(
+ (double)(tsc - tf->trace->start_tsc)
+ * (1000000000.0 / tf->trace->freq_scale)
+ / (double)tf->trace->start_freq);
+ time = ltt_time_add(tf->trace->start_time_from_tsc, time);
+ } else {
+ time = ltt_time_from_uint64(
+ (double)(tf->trace->start_tsc - tsc)
+ * (1000000000.0 / tf->trace->freq_scale)
+ / (double)tf->trace->start_freq);
+ time = ltt_time_sub(tf->trace->start_time_from_tsc, time);
+ }
+ return time;
+}
+
+/* Calculate the real event time based on the buffer boundaries */
+LttTime ltt_interpolate_time(LttTracefile *tf, LttEvent *event)