----- On Apr 30, 2019, at 12:12 PM, Mathieu Desnoyers mathieu.desnoy...@efficios.com wrote:
> Fix for timestamp_end not including all events within sub-buffer. This > happens if a thread is preempted/interrupted for a long time between > reserve and commit (e.g. in the middle of a packet), which causes the > timestamp used for timestamp_end field of the packet header to be lower > than the timestamp of the last events in the buffer (those following the > event that was preempted/interrupted between reserve and commit). > > The fix involves sampling the timestamp when doing the last space > reservation in a sub-buffer (which necessarily happens before doing the > delivery after its last commit). Save this timestamp temporarily in a > per-sub-buffer control area (we have exclusive access to that area until > we increment the commit counter). > > Then, that timestamp value will be read when delivering the sub-buffer, > whichever event or switch happens to be the last to increment the commit > counter to perform delivery. The timestamp value can be read without > worrying about concurrent access, because at that point sub-buffer > delivery has exclusive access to the sub-buffer. > > This ensures the timestamp_end value is always larger or equal to the > timestamp of the last event, always below or equal the timestamp_begin > of the following packet, and always below or equal the timestamp of the > first event in the following packet. Also: This changes the layout of the ring buffer shared memory area, so we need to bump the LTTNG_UST_ABI version from 7.2 to 8.0, thus requiring locked-step upgrade between liblttng-ust in applications, session daemon, and consumer daemon. This fix therefore cannot be backported to existing stable releases. With the additional: diff --git a/include/lttng/ust-abi.h b/include/lttng/ust-abi.h index 01e9daf4..c1e13085 100644 --- a/include/lttng/ust-abi.h +++ b/include/lttng/ust-abi.h @@ -46,8 +46,8 @@ #define LTTNG_UST_COMM_MAGIC 0xC57C57C5 /* Version for ABI between liblttng-ust, sessiond, consumerd */ -#define LTTNG_UST_ABI_MAJOR_VERSION 7 -#define LTTNG_UST_ABI_MINOR_VERSION 2 +#define LTTNG_UST_ABI_MAJOR_VERSION 8 +#define LTTNG_UST_ABI_MINOR_VERSION 0 enum lttng_ust_instrumentation { LTTNG_UST_TRACEPOINT = 0, > > Fixes: #1183 > Signed-off-by: Mathieu Desnoyers <mathieu.desnoy...@efficios.com> > --- > libringbuffer/frontend_types.h | 14 ++++++++ > libringbuffer/ring_buffer_frontend.c | 62 ++++++++++++++++++++++++++++++++++-- > 2 files changed, 73 insertions(+), 3 deletions(-) > > diff --git a/libringbuffer/frontend_types.h b/libringbuffer/frontend_types.h > index 629abcbd..d0890408 100644 > --- a/libringbuffer/frontend_types.h > +++ b/libringbuffer/frontend_types.h > @@ -202,6 +202,20 @@ struct lttng_ust_lib_ring_buffer { > > DECLARE_SHMP(struct commit_counters_cold, commit_cold); > /* Commit count per sub-buffer */ > + DECLARE_SHMP(uint64_t, ts_end); /* > + * timestamp_end per sub-buffer. > + * Time is sampled by the > + * switch_*_end() callbacks > + * which are the last space > + * reservation performed in the > + * sub-buffer before it can be > + * fully committed and > + * delivered. This time value is > + * then read by the deliver > + * callback, performed by the > + * last commit before the buffer > + * becomes readable. > + */ > long active_readers; /* > * Active readers count > * standard atomic access (shared) > diff --git a/libringbuffer/ring_buffer_frontend.c > b/libringbuffer/ring_buffer_frontend.c > index 9721df16..ce759ff1 100644 > --- a/libringbuffer/ring_buffer_frontend.c > +++ b/libringbuffer/ring_buffer_frontend.c > @@ -194,6 +194,7 @@ void lib_ring_buffer_reset(struct > lttng_ust_lib_ring_buffer > *buf, > for (i = 0; i < chan->backend.num_subbuf; i++) { > struct commit_counters_hot *cc_hot; > struct commit_counters_cold *cc_cold; > + uint64_t *ts_end; > > cc_hot = shmp_index(handle, buf->commit_hot, i); > if (!cc_hot) > @@ -201,9 +202,13 @@ void lib_ring_buffer_reset(struct > lttng_ust_lib_ring_buffer > *buf, > cc_cold = shmp_index(handle, buf->commit_cold, i); > if (!cc_cold) > return; > + ts_end = shmp_index(handle, buf->ts_end, i); > + if (!ts_end) > + return; > v_set(config, &cc_hot->cc, 0); > v_set(config, &cc_hot->seq, 0); > v_set(config, &cc_cold->cc_sb, 0); > + *ts_end = 0; > } > uatomic_set(&buf->consumed, 0); > uatomic_set(&buf->record_disabled, 0); > @@ -368,6 +373,16 @@ int lib_ring_buffer_create(struct > lttng_ust_lib_ring_buffer > *buf, > goto free_commit; > } > > + align_shm(shmobj, __alignof__(uint64_t)); > + set_shmp(buf->ts_end, > + zalloc_shm(shmobj, > + sizeof(uint64_t) * chan->backend.num_subbuf)); > + if (!shmp(handle, buf->ts_end)) { > + ret = -ENOMEM; > + goto free_commit_cold; > + } > + > + > ret = lib_ring_buffer_backend_create(&buf->backend, &chan->backend, > cpu, handle, shmobj); > if (ret) { > @@ -414,6 +429,8 @@ int lib_ring_buffer_create(struct > lttng_ust_lib_ring_buffer > *buf, > > /* Error handling */ > free_init: > + /* ts_end will be freed by shm teardown */ > +free_commit_cold: > /* commit_cold will be freed by shm teardown */ > free_commit: > /* commit_hot will be freed by shm teardown */ > @@ -1795,15 +1812,29 @@ void lib_ring_buffer_switch_old_end(struct > lttng_ust_lib_ring_buffer *buf, > unsigned long oldidx = subbuf_index(offsets->old - 1, chan); > unsigned long commit_count, padding_size, data_size; > struct commit_counters_hot *cc_hot; > + uint64_t *ts_end; > > data_size = subbuf_offset(offsets->old - 1, chan) + 1; > padding_size = chan->backend.subbuf_size - data_size; > subbuffer_set_data_size(config, &buf->backend, oldidx, data_size, > handle); > > + ts_end = shmp_index(handle, buf->ts_end, oldidx); > + if (!ts_end) > + return; > /* > - * Order all writes to buffer before the commit count update that will > - * determine that the subbuffer is full. > + * This is the last space reservation in that sub-buffer before > + * it gets delivered. This provides exclusive access to write to > + * this sub-buffer's ts_end. There are also no concurrent > + * readers of that ts_end because delivery of that sub-buffer is > + * postponed until the commit counter is incremented for the > + * current space reservation. > + */ > + *ts_end = tsc; > + > + /* > + * Order all writes to buffer and store to ts_end before the commit > + * count update that will determine that the subbuffer is full. > */ > cmm_smp_wmb(); > cc_hot = shmp_index(handle, buf->commit_hot, oldidx); > @@ -1874,11 +1905,24 @@ void lib_ring_buffer_switch_new_end(struct > lttng_ust_lib_ring_buffer *buf, > { > const struct lttng_ust_lib_ring_buffer_config *config = > &chan->backend.config; > unsigned long endidx, data_size; > + uint64_t *ts_end; > > endidx = subbuf_index(offsets->end - 1, chan); > data_size = subbuf_offset(offsets->end - 1, chan) + 1; > subbuffer_set_data_size(config, &buf->backend, endidx, data_size, > handle); > + ts_end = shmp_index(handle, buf->ts_end, endidx); > + if (!ts_end) > + return; > + /* > + * This is the last space reservation in that sub-buffer before > + * it gets delivered. This provides exclusive access to write to > + * this sub-buffer's ts_end. There are also no concurrent > + * readers of that ts_end because delivery of that sub-buffer is > + * postponed until the commit counter is incremented for the > + * current space reservation. > + */ > + *ts_end = tsc; > } > > /* > @@ -2445,14 +2489,26 @@ void lib_ring_buffer_check_deliver_slow(const struct > lttng_ust_lib_ring_buffer_c > if (caa_likely(v_cmpxchg(config, &cc_cold->cc_sb, > old_commit_count, old_commit_count + 1) > == old_commit_count)) { > + uint64_t *ts_end; > + > /* > * Start of exclusive subbuffer access. We are > * guaranteed to be the last writer in this subbuffer > * and any other writer trying to access this subbuffer > * in this state is required to drop records. > + * > + * We can read the ts_end for the current sub-buffer > + * which has been saved by the very last space > + * reservation for the current sub-buffer. > + * > + * Order increment of commit counter before reading ts_end. > */ > + cmm_smp_mb(); > + ts_end = shmp_index(handle, buf->ts_end, idx); > + if (!ts_end) > + return; > deliver_count_events(config, buf, idx, handle); > - config->cb.buffer_end(buf, tsc, idx, > + config->cb.buffer_end(buf, *ts_end, idx, > lib_ring_buffer_get_data_size(config, > buf, > idx, > -- > 2.11.0 -- Mathieu Desnoyers EfficiOS Inc. http://www.efficios.com _______________________________________________ lttng-dev mailing list lttng-dev@lists.lttng.org https://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev