* [lttng-dev] [PATCH lttng-tools 1/4] Rename consumer threads and spawn them in daemon
@ 2012-10-12 14:30 David Goulet
2012-10-12 14:30 ` [lttng-dev] [PATCH lttng-tools 2/4] Move add data stream to the data thread David Goulet
` (3 more replies)
0 siblings, 4 replies; 22+ messages in thread
From: David Goulet @ 2012-10-12 14:30 UTC (permalink / raw)
The metadata thread is now created in the lttng-consumerd daemon so all
thread could be controlled inside the daemon.
This is the first step of a consumer thread refactoring which aims at
moving data and metadata stream operations inside a dedicated thread so
the session daemon thread does not block and is more efficient at adding
streams.
The most important concept is that a stream file descriptor MUST be
opened as quickly as we can than passed to the right thread (for UST
since they are already opened by the session daemon for the kernel).
Signed-off-by: David Goulet <dgoulet at efficios.com>
---
src/bin/lttng-consumerd/lttng-consumerd.c | 18 ++++++++++-----
src/common/consumer.c | 34 +++++++++--------------------
src/common/consumer.h | 5 +++--
3 files changed, 26 insertions(+), 31 deletions(-)
diff --git a/src/bin/lttng-consumerd/lttng-consumerd.c b/src/bin/lttng-consumerd/lttng-consumerd.c
index 5952334..946fb02 100644
--- a/src/bin/lttng-consumerd/lttng-consumerd.c
+++ b/src/bin/lttng-consumerd/lttng-consumerd.c
@@ -356,23 +356,31 @@ int main(int argc, char **argv)
}
lttng_consumer_set_error_sock(ctx, ret);
- /* Create the thread to manage the receive of fd */
- ret = pthread_create(&threads[0], NULL, lttng_consumer_thread_receive_fds,
+ /* Create thread to manage the polling/writing of trace metadata */
+ ret = pthread_create(&threads[0], NULL, consumer_thread_metadata_poll,
+ (void *) ctx);
+ if (ret != 0) {
+ perror("pthread_create");
+ goto error;
+ }
+
+ /* Create thread to manage the polling/writing of trace data */
+ ret = pthread_create(&threads[1], NULL, consumer_thread_data_poll,
(void *) ctx);
if (ret != 0) {
perror("pthread_create");
goto error;
}
- /* Create thread to manage the polling/writing of traces */
- ret = pthread_create(&threads[1], NULL, lttng_consumer_thread_poll_fds,
+ /* Create the thread to manage the receive of fd */
+ ret = pthread_create(&threads[2], NULL, consumer_thread_sessiond_poll,
(void *) ctx);
if (ret != 0) {
perror("pthread_create");
goto error;
}
- for (i = 0; i < 2; i++) {
+ for (i = 0; i < 3; i++) {
ret = pthread_join(threads[i], &status);
if (ret != 0) {
perror("pthread_join");
diff --git a/src/common/consumer.c b/src/common/consumer.c
index 242b05b..055de1b 100644
--- a/src/common/consumer.c
+++ b/src/common/consumer.c
@@ -1131,6 +1131,8 @@ void lttng_consumer_destroy(struct lttng_consumer_local_data *ctx)
PERROR("close");
}
utils_close_pipe(ctx->consumer_splice_metadata_pipe);
+ /* This should trigger the metadata thread to exit */
+ close(ctx->consumer_metadata_pipe[1]);
unlink(ctx->consumer_command_sock_path);
free(ctx);
@@ -1756,7 +1758,7 @@ error:
* Thread polls on metadata file descriptor and write them on disk or on the
* network.
*/
-void *lttng_consumer_thread_poll_metadata(void *data)
+void *consumer_thread_metadata_poll(void *data)
{
int ret, i, pollfd;
uint32_t revents, nb_fd;
@@ -1939,7 +1941,7 @@ end:
* This thread polls the fds in the set to consume the data and write
* it to tracefile if necessary.
*/
-void *lttng_consumer_thread_poll_fds(void *data)
+void *consumer_thread_data_poll(void *data)
{
int num_rdy, num_hup, high_prio, ret, i;
struct pollfd *pollfd = NULL;
@@ -1949,19 +1951,9 @@ void *lttng_consumer_thread_poll_fds(void *data)
int nb_fd = 0;
struct lttng_consumer_local_data *ctx = data;
ssize_t len;
- pthread_t metadata_thread;
- void *status;
rcu_register_thread();
- /* Start metadata polling thread */
- ret = pthread_create(&metadata_thread, NULL,
- lttng_consumer_thread_poll_metadata, (void *) ctx);
- if (ret < 0) {
- PERROR("pthread_create metadata thread");
- goto end;
- }
-
local_stream = zmalloc(sizeof(struct lttng_consumer_stream));
while (1) {
@@ -2145,19 +2137,13 @@ end:
/*
* Close the write side of the pipe so epoll_wait() in
- * lttng_consumer_thread_poll_metadata can catch it. The thread is
- * monitoring the read side of the pipe. If we close them both, epoll_wait
- * strangely does not return and could create a endless wait period if the
- * pipe is the only tracked fd in the poll set. The thread will take care
- * of closing the read side.
+ * consumer_thread_metadata_poll can catch it. The thread is monitoring the
+ * read side of the pipe. If we close them both, epoll_wait strangely does
+ * not return and could create a endless wait period if the pipe is the
+ * only tracked fd in the poll set. The thread will take care of closing
+ * the read side.
*/
close(ctx->consumer_metadata_pipe[1]);
- if (ret) {
- ret = pthread_join(metadata_thread, &status);
- if (ret < 0) {
- PERROR("pthread_join metadata thread");
- }
- }
rcu_unregister_thread();
return NULL;
@@ -2167,7 +2153,7 @@ end:
* This thread listens on the consumerd socket and receives the file
* descriptors from the session daemon.
*/
-void *lttng_consumer_thread_receive_fds(void *data)
+void *consumer_thread_sessiond_poll(void *data)
{
int sock, client_socket, ret;
/*
diff --git a/src/common/consumer.h b/src/common/consumer.h
index d0cd8fd..4b225e4 100644
--- a/src/common/consumer.h
+++ b/src/common/consumer.h
@@ -385,8 +385,9 @@ extern int lttng_consumer_get_produced_snapshot(
struct lttng_consumer_local_data *ctx,
struct lttng_consumer_stream *stream,
unsigned long *pos);
-extern void *lttng_consumer_thread_poll_fds(void *data);
-extern void *lttng_consumer_thread_receive_fds(void *data);
+extern void *consumer_thread_metadata_poll(void *data);
+extern void *consumer_thread_data_poll(void *data);
+extern void *consumer_thread_sessiond_poll(void *data);
extern int lttng_consumer_recv_cmd(struct lttng_consumer_local_data *ctx,
int sock, struct pollfd *consumer_sockpoll);
--
1.7.10.4
^ permalink raw reply [flat|nested] 22+ messages in thread
* [lttng-dev] [PATCH lttng-tools 2/4] Move add data stream to the data thread
2012-10-12 14:30 [lttng-dev] [PATCH lttng-tools 1/4] Rename consumer threads and spawn them in daemon David Goulet
@ 2012-10-12 14:30 ` David Goulet
2012-10-13 15:53 ` Mathieu Desnoyers
2012-10-12 14:30 ` [lttng-dev] [PATCH lttng-tools 3/4] Make stream hash tables global to the consumer David Goulet
` (2 subsequent siblings)
3 siblings, 1 reply; 22+ messages in thread
From: David Goulet @ 2012-10-12 14:30 UTC (permalink / raw)
As a second step of refactoring, upon receiving a data stream, we send
it to the data thread that is now in charge of handling it.
Furthermore, in order for this to behave correctly, we have to make the
ustctl actions on the stream upon before passing it to the right thread
(the kernel does not need special actions.). This way, once the sessiond
thread reply back to the session daemon, the stream is sure to be open
and ready for data to be recorded on the application side so we avoid a
race between the application thinking the stream is ready and the stream
thread still scheduled out.
This commit should speed up the add stream process for the session
daemon. There is still some actions to move out of the session daemon
poll thread to gain speed significantly, especially for network
streaming.
Signed-off-by: David Goulet <dgoulet at efficios.com>
---
src/common/consumer.c | 123 +++++++++++---------------
src/common/consumer.h | 1 +
src/common/kernel-consumer/kernel-consumer.c | 24 ++---
src/common/ust-consumer/ust-consumer.c | 40 ++++-----
4 files changed, 78 insertions(+), 110 deletions(-)
diff --git a/src/common/consumer.c b/src/common/consumer.c
index 055de1b..1d2b1f7 100644
--- a/src/common/consumer.c
+++ b/src/common/consumer.c
@@ -89,7 +89,7 @@ static struct lttng_consumer_stream *consumer_find_stream(int key,
return stream;
}
-static void consumer_steal_stream_key(int key, struct lttng_ht *ht)
+void consumer_steal_stream_key(int key, struct lttng_ht *ht)
{
struct lttng_consumer_stream *stream;
@@ -409,6 +409,14 @@ struct lttng_consumer_stream *consumer_allocate_stream(
lttng_ht_node_init_ulong(&stream->waitfd_node, stream->wait_fd);
lttng_ht_node_init_ulong(&stream->node, stream->key);
+ /*
+ * The cpu number is needed before using any ustctl_* actions. Ignored for
+ * the kernel so the value does not matter.
+ */
+ pthread_mutex_lock(&consumer_data.lock);
+ stream->cpu = stream->chan->cpucount++;
+ pthread_mutex_unlock(&consumer_data.lock);
+
DBG3("Allocated stream %s (key %d, shm_fd %d, wait_fd %d, mmap_len %llu,"
" out_fd %d, net_seq_idx %d)", stream->path_name, stream->key,
stream->shm_fd, stream->wait_fd,
@@ -437,28 +445,6 @@ int consumer_add_stream(struct lttng_consumer_stream *stream)
pthread_mutex_lock(&consumer_data.lock);
rcu_read_lock();
- switch (consumer_data.type) {
- case LTTNG_CONSUMER_KERNEL:
- break;
- case LTTNG_CONSUMER32_UST:
- case LTTNG_CONSUMER64_UST:
- stream->cpu = stream->chan->cpucount++;
- ret = lttng_ustconsumer_add_stream(stream);
- if (ret) {
- ret = -EINVAL;
- goto error;
- }
-
- /* Steal stream identifier only for UST */
- consumer_steal_stream_key(stream->key, consumer_data.stream_ht);
- break;
- default:
- ERR("Unknown consumer_data type");
- assert(0);
- ret = -ENOSYS;
- goto error;
- }
-
lttng_ht_add_unique_ulong(consumer_data.stream_ht, &stream->node);
/* Check and cleanup relayd */
@@ -485,7 +471,6 @@ int consumer_add_stream(struct lttng_consumer_stream *stream)
consumer_data.stream_count++;
consumer_data.need_update = 1;
-error:
rcu_read_unlock();
pthread_mutex_unlock(&consumer_data.lock);
@@ -1582,17 +1567,6 @@ void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
DBG3("Consumer delete metadata stream %d", stream->wait_fd);
- if (ht == NULL) {
- /* Means the stream was allocated but not successfully added */
- goto free_stream;
- }
-
- rcu_read_lock();
- iter.iter.node = &stream->waitfd_node.node;
- ret = lttng_ht_del(ht, &iter);
- assert(!ret);
- rcu_read_unlock();
-
pthread_mutex_lock(&consumer_data.lock);
switch (consumer_data.type) {
case LTTNG_CONSUMER_KERNEL:
@@ -1613,6 +1587,18 @@ void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
goto end;
}
+ if (ht == NULL) {
+ pthread_mutex_unlock(&consumer_data.lock);
+ /* Means the stream was allocated but not successfully added */
+ goto free_stream;
+ }
+
+ rcu_read_lock();
+ iter.iter.node = &stream->waitfd_node.node;
+ ret = lttng_ht_del(ht, &iter);
+ assert(!ret);
+ rcu_read_unlock();
+
if (stream->out_fd >= 0) {
ret = close(stream->out_fd);
if (ret) {
@@ -1699,27 +1685,6 @@ static int consumer_add_metadata_stream(struct lttng_consumer_stream *stream,
pthread_mutex_lock(&consumer_data.lock);
- switch (consumer_data.type) {
- case LTTNG_CONSUMER_KERNEL:
- break;
- case LTTNG_CONSUMER32_UST:
- case LTTNG_CONSUMER64_UST:
- ret = lttng_ustconsumer_add_stream(stream);
- if (ret) {
- ret = -EINVAL;
- goto error;
- }
-
- /* Steal stream identifier only for UST */
- consumer_steal_stream_key(stream->wait_fd, ht);
- break;
- default:
- ERR("Unknown consumer_data type");
- assert(0);
- ret = -ENOSYS;
- goto error;
- }
-
/*
* From here, refcounts are updated so be _careful_ when returning an error
* after this point.
@@ -1749,7 +1714,6 @@ static int consumer_add_metadata_stream(struct lttng_consumer_stream *stream,
lttng_ht_add_unique_ulong(ht, &stream->waitfd_node);
rcu_read_unlock();
-error:
pthread_mutex_unlock(&consumer_data.lock);
return ret;
}
@@ -1946,7 +1910,7 @@ void *consumer_thread_data_poll(void *data)
int num_rdy, num_hup, high_prio, ret, i;
struct pollfd *pollfd = NULL;
/* local view of the streams */
- struct lttng_consumer_stream **local_stream = NULL;
+ struct lttng_consumer_stream **local_stream = NULL, *new_stream = NULL;
/* local view of consumer_data.fds_count */
int nb_fd = 0;
struct lttng_consumer_local_data *ctx = data;
@@ -2034,13 +1998,35 @@ void *consumer_thread_data_poll(void *data)
*/
if (pollfd[nb_fd].revents & (POLLIN | POLLPRI)) {
size_t pipe_readlen;
- char tmp;
DBG("consumer_poll_pipe wake up");
/* Consume 1 byte of pipe data */
do {
- pipe_readlen = read(ctx->consumer_poll_pipe[0], &tmp, 1);
+ pipe_readlen = read(ctx->consumer_poll_pipe[0], &new_stream,
+ sizeof(new_stream));
} while (pipe_readlen == -1 && errno == EINTR);
+
+ /*
+ * If the stream is NULL, just ignore it. It's also possible that
+ * the sessiond poll thread changed the consumer_quit state and is
+ * waking us up to test it.
+ */
+ if (new_stream == NULL) {
+ continue;
+ }
+
+ ret = consumer_add_stream(new_stream);
+ if (ret) {
+ ERR("Consumer add stream %d failed. Continuing",
+ new_stream->key);
+ /*
+ * At this point, if the add_stream fails, it is not in the
+ * hash table thus passing the NULL value here.
+ */
+ consumer_del_stream(new_stream, NULL);
+ }
+
+ /* Continue to update the local streams and handle prio ones */
continue;
}
@@ -2260,19 +2246,16 @@ end:
consumer_poll_timeout = LTTNG_CONSUMER_POLL_TIMEOUT;
/*
- * Wake-up the other end by writing a null byte in the pipe
- * (non-blocking). Important note: Because writing into the
- * pipe is non-blocking (and therefore we allow dropping wakeup
- * data, as long as there is wakeup data present in the pipe
- * buffer to wake up the other end), the other end should
- * perform the following sequence for waiting:
- * 1) empty the pipe (reads).
- * 2) perform update operation.
- * 3) wait on the pipe (poll).
+ * Notify the data poll thread to poll back again and test the
+ * consumer_quit state to quit gracefully.
*/
do {
- ret = write(ctx->consumer_poll_pipe[1], "", 1);
+ struct lttng_consumer_stream *null_stream = NULL;
+
+ ret = write(ctx->consumer_poll_pipe[1], &null_stream,
+ sizeof(null_stream));
} while (ret < 0 && errno == EINTR);
+
rcu_unregister_thread();
return NULL;
}
diff --git a/src/common/consumer.h b/src/common/consumer.h
index 4b225e4..8e5891a 100644
--- a/src/common/consumer.h
+++ b/src/common/consumer.h
@@ -362,6 +362,7 @@ struct consumer_relayd_sock_pair *consumer_allocate_relayd_sock_pair(
struct consumer_relayd_sock_pair *consumer_find_relayd(int key);
int consumer_handle_stream_before_relayd(struct lttng_consumer_stream *stream,
size_t data_size);
+void consumer_steal_stream_key(int key, struct lttng_ht *ht);
extern struct lttng_consumer_local_data *lttng_consumer_create(
enum lttng_consumer_type type,
diff --git a/src/common/kernel-consumer/kernel-consumer.c b/src/common/kernel-consumer/kernel-consumer.c
index 13cbe21..444f5e0 100644
--- a/src/common/kernel-consumer/kernel-consumer.c
+++ b/src/common/kernel-consumer/kernel-consumer.c
@@ -235,10 +235,12 @@ int lttng_kconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
consumer_del_stream(new_stream, NULL);
}
} else {
- ret = consumer_add_stream(new_stream);
- if (ret) {
- ERR("Consumer add stream %d failed. Continuing",
- new_stream->key);
+ do {
+ ret = write(ctx->consumer_poll_pipe[1], &new_stream,
+ sizeof(new_stream));
+ } while (ret < 0 && errno == EINTR);
+ if (ret < 0) {
+ PERROR("write data pipe");
consumer_del_stream(new_stream, NULL);
goto end_nosignal;
}
@@ -284,20 +286,6 @@ int lttng_kconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
goto end_nosignal;
}
- /*
- * Wake-up the other end by writing a null byte in the pipe (non-blocking).
- * Important note: Because writing into the pipe is non-blocking (and
- * therefore we allow dropping wakeup data, as long as there is wakeup data
- * present in the pipe buffer to wake up the other end), the other end
- * should perform the following sequence for waiting:
- *
- * 1) empty the pipe (reads).
- * 2) perform update operation.
- * 3) wait on the pipe (poll).
- */
- do {
- ret = write(ctx->consumer_poll_pipe[1], "", 1);
- } while (ret < 0 && errno == EINTR);
end_nosignal:
rcu_read_unlock();
diff --git a/src/common/ust-consumer/ust-consumer.c b/src/common/ust-consumer/ust-consumer.c
index 1170687..4ca4b84 100644
--- a/src/common/ust-consumer/ust-consumer.c
+++ b/src/common/ust-consumer/ust-consumer.c
@@ -224,6 +224,18 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
goto end_nosignal;
}
+ /*
+ * This needs to be done as soon as we can so we don't block the
+ * application too long.
+ */
+ ret = lttng_ustconsumer_add_stream(new_stream);
+ if (ret) {
+ consumer_del_stream(new_stream, NULL);
+ goto end_nosignal;
+ }
+ /* Steal stream identifier to avoid having streams with the same key */
+ consumer_steal_stream_key(new_stream->key, consumer_data.stream_ht);
+
/* The stream is not metadata. Get relayd reference if exists. */
relayd = consumer_find_relayd(msg.u.stream.net_index);
if (relayd != NULL) {
@@ -265,14 +277,12 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
goto end_nosignal;
}
} else {
- ret = consumer_add_stream(new_stream);
- if (ret) {
- ERR("Consumer add stream %d failed. Continuing",
- new_stream->key);
- /*
- * At this point, if the add_stream fails, it is not in the
- * hash table thus passing the NULL value here.
- */
+ do {
+ ret = write(ctx->consumer_poll_pipe[1], &new_stream,
+ sizeof(new_stream));
+ } while (ret < 0 && errno == EINTR);
+ if (ret < 0) {
+ PERROR("write data pipe");
consumer_del_stream(new_stream, NULL);
goto end_nosignal;
}
@@ -334,20 +344,6 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
break;
}
- /*
- * Wake-up the other end by writing a null byte in the pipe (non-blocking).
- * Important note: Because writing into the pipe is non-blocking (and
- * therefore we allow dropping wakeup data, as long as there is wakeup data
- * present in the pipe buffer to wake up the other end), the other end
- * should perform the following sequence for waiting:
- *
- * 1) empty the pipe (reads).
- * 2) perform update operation.
- * 3) wait on the pipe (poll).
- */
- do {
- ret = write(ctx->consumer_poll_pipe[1], "", 1);
- } while (ret < 0 && errno == EINTR);
end_nosignal:
rcu_read_unlock();
--
1.7.10.4
^ permalink raw reply [flat|nested] 22+ messages in thread
* [lttng-dev] [PATCH lttng-tools 3/4] Make stream hash tables global to the consumer
2012-10-12 14:30 [lttng-dev] [PATCH lttng-tools 1/4] Rename consumer threads and spawn them in daemon David Goulet
2012-10-12 14:30 ` [lttng-dev] [PATCH lttng-tools 2/4] Move add data stream to the data thread David Goulet
@ 2012-10-12 14:30 ` David Goulet
2012-10-13 15:56 ` Mathieu Desnoyers
2012-10-12 14:30 ` [lttng-dev] [PATCH lttng-tools 4/4] Change the metadata hash table node David Goulet
2012-10-13 15:41 ` [lttng-dev] [PATCH lttng-tools 1/4] Rename consumer threads and spawn them in daemon Mathieu Desnoyers
3 siblings, 1 reply; 22+ messages in thread
From: David Goulet @ 2012-10-12 14:30 UTC (permalink / raw)
The data stream hash table is now global to the consumer and used in the
data thread. The consumer_data stream_ht is no longer used to track the
data streams but instead will be used (and possibly renamed) by the
session daemon poll thread to keep track of streams on a per session id
basis for the upcoming feature that check traced data availability.
For now, in order to avoid mind bugging problems to access the streams,
both hash table are now defined globally (metadata and data). However,
stream update are still done in a single thread. Don't count on this to
be guaranteed in the next commits.
Signed-off-by: David Goulet <dgoulet at efficios.com>
---
src/common/consumer.c | 91 +++++++++++++++++++++++++-------
src/common/consumer.h | 9 ++--
src/common/ust-consumer/ust-consumer.c | 2 -
3 files changed, 75 insertions(+), 27 deletions(-)
diff --git a/src/common/consumer.c b/src/common/consumer.c
index 1d2b1f7..1fb9960 100644
--- a/src/common/consumer.c
+++ b/src/common/consumer.c
@@ -59,6 +59,17 @@ int consumer_poll_timeout = -1;
volatile int consumer_quit = 0;
/*
+ * The following two hash tables are visible by all threads which are separated
+ * in different source files.
+ *
+ * Global hash table containing respectively metadata and data streams. The
+ * stream element in this ht should only be updated by the metadata poll thread
+ * for the metadata and the data poll thread for the data.
+ */
+struct lttng_ht *metadata_ht = NULL;
+struct lttng_ht *data_ht = NULL;
+
+/*
* Find a stream. The consumer_data.lock must be locked during this
* call.
*/
@@ -433,19 +444,24 @@ end:
/*
* Add a stream to the global list protected by a mutex.
*/
-int consumer_add_stream(struct lttng_consumer_stream *stream)
+static int consumer_add_stream(struct lttng_consumer_stream *stream,
+ struct lttng_ht *ht)
{
int ret = 0;
struct consumer_relayd_sock_pair *relayd;
assert(stream);
+ assert(ht);
DBG3("Adding consumer stream %d", stream->key);
pthread_mutex_lock(&consumer_data.lock);
rcu_read_lock();
- lttng_ht_add_unique_ulong(consumer_data.stream_ht, &stream->node);
+ /* Steal stream identifier to avoid having streams with the same key */
+ consumer_steal_stream_key(stream->key, ht);
+
+ lttng_ht_add_unique_ulong(ht, &stream->node);
/* Check and cleanup relayd */
relayd = consumer_find_relayd(stream->net_seq_idx);
@@ -783,9 +799,9 @@ end:
*
* Returns the number of fds in the structures.
*/
-int consumer_update_poll_array(
+static int consumer_update_poll_array(
struct lttng_consumer_local_data *ctx, struct pollfd **pollfd,
- struct lttng_consumer_stream **local_stream)
+ struct lttng_consumer_stream **local_stream, struct lttng_ht *ht)
{
int i = 0;
struct lttng_ht_iter iter;
@@ -793,8 +809,7 @@ int consumer_update_poll_array(
DBG("Updating poll fd array");
rcu_read_lock();
- cds_lfht_for_each_entry(consumer_data.stream_ht->ht, &iter.iter, stream,
- node.node) {
+ cds_lfht_for_each_entry(ht->ht, &iter.iter, stream, node.node) {
if (stream->state != LTTNG_CONSUMER_ACTIVE_STREAM) {
continue;
}
@@ -1523,6 +1538,33 @@ int lttng_consumer_recv_cmd(struct lttng_consumer_local_data *ctx,
/*
* Iterate over all streams of the hashtable and free them properly.
*
+ * WARNING: *MUST* be used with data stream only.
+ */
+static void destroy_data_stream_ht(struct lttng_ht *ht)
+{
+ int ret;
+ struct lttng_ht_iter iter;
+ struct lttng_consumer_stream *stream;
+
+ if (ht == NULL) {
+ return;
+ }
+
+ rcu_read_lock();
+ cds_lfht_for_each_entry(ht->ht, &iter.iter, stream, node.node) {
+ ret = lttng_ht_del(ht, &iter);
+ assert(!ret);
+
+ call_rcu(&stream->node.head, consumer_free_stream);
+ }
+ rcu_read_unlock();
+
+ lttng_ht_destroy(ht);
+}
+
+/*
+ * Iterate over all streams of the hashtable and free them properly.
+ *
* XXX: Should not be only for metadata stream or else use an other name.
*/
static void destroy_stream_ht(struct lttng_ht *ht)
@@ -1711,6 +1753,9 @@ static int consumer_add_metadata_stream(struct lttng_consumer_stream *stream,
uatomic_dec(&stream->chan->nb_init_streams);
}
+ /* Steal stream identifier to avoid having streams with the same key */
+ consumer_steal_stream_key(stream->key, ht);
+
lttng_ht_add_unique_ulong(ht, &stream->waitfd_node);
rcu_read_unlock();
@@ -1729,7 +1774,6 @@ void *consumer_thread_metadata_poll(void *data)
struct lttng_consumer_stream *stream = NULL;
struct lttng_ht_iter iter;
struct lttng_ht_node_ulong *node;
- struct lttng_ht *metadata_ht = NULL;
struct lttng_poll_event events;
struct lttng_consumer_local_data *ctx = data;
ssize_t len;
@@ -1738,11 +1782,6 @@ void *consumer_thread_metadata_poll(void *data)
DBG("Thread metadata poll started");
- metadata_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
- if (metadata_ht == NULL) {
- goto end;
- }
-
/* Size is set to 1 for the consumer_metadata pipe */
ret = lttng_poll_create(&events, 2, LTTNG_CLOEXEC);
if (ret < 0) {
@@ -1918,6 +1957,11 @@ void *consumer_thread_data_poll(void *data)
rcu_register_thread();
+ data_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
+ if (data_ht == NULL) {
+ goto end;
+ }
+
local_stream = zmalloc(sizeof(struct lttng_consumer_stream));
while (1) {
@@ -1955,7 +1999,8 @@ void *consumer_thread_data_poll(void *data)
pthread_mutex_unlock(&consumer_data.lock);
goto end;
}
- ret = consumer_update_poll_array(ctx, &pollfd, local_stream);
+ ret = consumer_update_poll_array(ctx, &pollfd, local_stream,
+ data_ht);
if (ret < 0) {
ERR("Error in allocating pollfd or local_outfds");
lttng_consumer_send_error(ctx, LTTCOMM_CONSUMERD_POLL_ERROR);
@@ -2015,7 +2060,7 @@ void *consumer_thread_data_poll(void *data)
continue;
}
- ret = consumer_add_stream(new_stream);
+ ret = consumer_add_stream(new_stream, data_ht);
if (ret) {
ERR("Consumer add stream %d failed. Continuing",
new_stream->key);
@@ -2088,22 +2133,19 @@ void *consumer_thread_data_poll(void *data)
if ((pollfd[i].revents & POLLHUP)) {
DBG("Polling fd %d tells it has hung up.", pollfd[i].fd);
if (!local_stream[i]->data_read) {
- consumer_del_stream(local_stream[i],
- consumer_data.stream_ht);
+ consumer_del_stream(local_stream[i], data_ht);
num_hup++;
}
} else if (pollfd[i].revents & POLLERR) {
ERR("Error returned in polling fd %d.", pollfd[i].fd);
if (!local_stream[i]->data_read) {
- consumer_del_stream(local_stream[i],
- consumer_data.stream_ht);
+ consumer_del_stream(local_stream[i], data_ht);
num_hup++;
}
} else if (pollfd[i].revents & POLLNVAL) {
ERR("Polling fd %d tells fd is not open.", pollfd[i].fd);
if (!local_stream[i]->data_read) {
- consumer_del_stream(local_stream[i],
- consumer_data.stream_ht);
+ consumer_del_stream(local_stream[i], data_ht);
num_hup++;
}
}
@@ -2131,6 +2173,10 @@ end:
*/
close(ctx->consumer_metadata_pipe[1]);
+ if (data_ht) {
+ destroy_data_stream_ht(data_ht);
+ }
+
rcu_unregister_thread();
return NULL;
}
@@ -2299,6 +2345,11 @@ void lttng_consumer_init(void)
consumer_data.stream_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
consumer_data.channel_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
consumer_data.relayd_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
+
+ metadata_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
+ assert(metadata_ht);
+ data_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
+ assert(data_ht);
}
/*
diff --git a/src/common/consumer.h b/src/common/consumer.h
index 8e5891a..6bce96d 100644
--- a/src/common/consumer.h
+++ b/src/common/consumer.h
@@ -275,6 +275,10 @@ struct lttng_consumer_global_data {
struct lttng_ht *relayd_ht;
};
+/* Defined in consumer.c and coupled with explanations */
+extern struct lttng_ht *metadata_ht;
+extern struct lttng_ht *data_ht;
+
/*
* Init consumer data structures.
*/
@@ -324,10 +328,6 @@ extern void lttng_consumer_sync_trace_file(
*/
extern int lttng_consumer_poll_socket(struct pollfd *kconsumer_sockpoll);
-extern int consumer_update_poll_array(
- struct lttng_consumer_local_data *ctx, struct pollfd **pollfd,
- struct lttng_consumer_stream **local_consumer_streams);
-
extern struct lttng_consumer_stream *consumer_allocate_stream(
int channel_key, int stream_key,
int shm_fd, int wait_fd,
@@ -340,7 +340,6 @@ extern struct lttng_consumer_stream *consumer_allocate_stream(
int net_index,
int metadata_flag,
int *alloc_ret);
-extern int consumer_add_stream(struct lttng_consumer_stream *stream);
extern void consumer_del_stream(struct lttng_consumer_stream *stream,
struct lttng_ht *ht);
extern void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
diff --git a/src/common/ust-consumer/ust-consumer.c b/src/common/ust-consumer/ust-consumer.c
index 4ca4b84..3b41e55 100644
--- a/src/common/ust-consumer/ust-consumer.c
+++ b/src/common/ust-consumer/ust-consumer.c
@@ -233,8 +233,6 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
consumer_del_stream(new_stream, NULL);
goto end_nosignal;
}
- /* Steal stream identifier to avoid having streams with the same key */
- consumer_steal_stream_key(new_stream->key, consumer_data.stream_ht);
/* The stream is not metadata. Get relayd reference if exists. */
relayd = consumer_find_relayd(msg.u.stream.net_index);
--
1.7.10.4
^ permalink raw reply [flat|nested] 22+ messages in thread
* [lttng-dev] [PATCH lttng-tools 4/4] Change the metadata hash table node
2012-10-12 14:30 [lttng-dev] [PATCH lttng-tools 1/4] Rename consumer threads and spawn them in daemon David Goulet
2012-10-12 14:30 ` [lttng-dev] [PATCH lttng-tools 2/4] Move add data stream to the data thread David Goulet
2012-10-12 14:30 ` [lttng-dev] [PATCH lttng-tools 3/4] Make stream hash tables global to the consumer David Goulet
@ 2012-10-12 14:30 ` David Goulet
2012-10-13 16:00 ` Mathieu Desnoyers
2012-10-13 15:41 ` [lttng-dev] [PATCH lttng-tools 1/4] Rename consumer threads and spawn them in daemon Mathieu Desnoyers
3 siblings, 1 reply; 22+ messages in thread
From: David Goulet @ 2012-10-12 14:30 UTC (permalink / raw)
Remove the use of the "waitfd_node" for metadata and index the "node" by
wait fd during stream allocation only for metadata stream.
This was done so the waitfd node could be used later on for the hash
table indexing stream by session id the traced data check command (soon
to be implemented).
Signed-off-by: David Goulet <dgoulet at efficios.com>
---
src/common/consumer.c | 36 +++++++++++++++++-------------------
1 file changed, 17 insertions(+), 19 deletions(-)
diff --git a/src/common/consumer.c b/src/common/consumer.c
index 1fb9960..0c1a812 100644
--- a/src/common/consumer.c
+++ b/src/common/consumer.c
@@ -172,17 +172,6 @@ void consumer_free_stream(struct rcu_head *head)
free(stream);
}
-static
-void consumer_free_metadata_stream(struct rcu_head *head)
-{
- struct lttng_ht_node_ulong *node =
- caa_container_of(head, struct lttng_ht_node_ulong, head);
- struct lttng_consumer_stream *stream =
- caa_container_of(node, struct lttng_consumer_stream, waitfd_node);
-
- free(stream);
-}
-
/*
* RCU protected relayd socket pair free.
*/
@@ -417,8 +406,17 @@ struct lttng_consumer_stream *consumer_allocate_stream(
stream->metadata_flag = metadata_flag;
strncpy(stream->path_name, path_name, sizeof(stream->path_name));
stream->path_name[sizeof(stream->path_name) - 1] = '\0';
- lttng_ht_node_init_ulong(&stream->waitfd_node, stream->wait_fd);
- lttng_ht_node_init_ulong(&stream->node, stream->key);
+
+ /*
+ * Index differently the metadata node because the thread is using an
+ * internal hash table to match streams in the metadata_ht to the epoll set
+ * file descriptor.
+ */
+ if (metadata_flag) {
+ lttng_ht_node_init_ulong(&stream->node, stream->wait_fd);
+ } else {
+ lttng_ht_node_init_ulong(&stream->node, stream->key);
+ }
/*
* The cpu number is needed before using any ustctl_* actions. Ignored for
@@ -1578,11 +1576,11 @@ static void destroy_stream_ht(struct lttng_ht *ht)
}
rcu_read_lock();
- cds_lfht_for_each_entry(ht->ht, &iter.iter, stream, waitfd_node.node) {
+ cds_lfht_for_each_entry(ht->ht, &iter.iter, stream, node.node) {
ret = lttng_ht_del(ht, &iter);
assert(!ret);
- call_rcu(&stream->waitfd_node.head, consumer_free_metadata_stream);
+ call_rcu(&stream->node.head, consumer_free_stream);
}
rcu_read_unlock();
@@ -1636,7 +1634,7 @@ void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
}
rcu_read_lock();
- iter.iter.node = &stream->waitfd_node.node;
+ iter.iter.node = &stream->node.node;
ret = lttng_ht_del(ht, &iter);
assert(!ret);
rcu_read_unlock();
@@ -1707,7 +1705,7 @@ end:
}
free_stream:
- call_rcu(&stream->waitfd_node.head, consumer_free_metadata_stream);
+ call_rcu(&stream->node.head, consumer_free_stream);
}
/*
@@ -1756,7 +1754,7 @@ static int consumer_add_metadata_stream(struct lttng_consumer_stream *stream,
/* Steal stream identifier to avoid having streams with the same key */
consumer_steal_stream_key(stream->key, ht);
- lttng_ht_add_unique_ulong(ht, &stream->waitfd_node);
+ lttng_ht_add_unique_ulong(ht, &stream->node);
rcu_read_unlock();
pthread_mutex_unlock(&consumer_data.lock);
@@ -1881,7 +1879,7 @@ restart:
assert(node);
stream = caa_container_of(node, struct lttng_consumer_stream,
- waitfd_node);
+ node);
/* Check for error event */
if (revents & (LPOLLERR | LPOLLHUP)) {
--
1.7.10.4
^ permalink raw reply [flat|nested] 22+ messages in thread
* [lttng-dev] [PATCH lttng-tools 1/4] Rename consumer threads and spawn them in daemon
2012-10-12 14:30 [lttng-dev] [PATCH lttng-tools 1/4] Rename consumer threads and spawn them in daemon David Goulet
` (2 preceding siblings ...)
2012-10-12 14:30 ` [lttng-dev] [PATCH lttng-tools 4/4] Change the metadata hash table node David Goulet
@ 2012-10-13 15:41 ` Mathieu Desnoyers
2012-10-15 15:39 ` David Goulet
3 siblings, 1 reply; 22+ messages in thread
From: Mathieu Desnoyers @ 2012-10-13 15:41 UTC (permalink / raw)
* David Goulet (dgoulet at efficios.com) wrote:
> The metadata thread is now created in the lttng-consumerd daemon so all
> thread could be controlled inside the daemon.
>
> This is the first step of a consumer thread refactoring which aims at
> moving data and metadata stream operations inside a dedicated thread so
> the session daemon thread does not block and is more efficient at adding
> streams.
>
> The most important concept is that a stream file descriptor MUST be
> opened as quickly as we can than passed to the right thread (for UST
than -> then
> since they are already opened by the session daemon for the kernel).
>
> Signed-off-by: David Goulet <dgoulet at efficios.com>
> ---
> src/bin/lttng-consumerd/lttng-consumerd.c | 18 ++++++++++-----
> src/common/consumer.c | 34 +++++++++--------------------
> src/common/consumer.h | 5 +++--
> 3 files changed, 26 insertions(+), 31 deletions(-)
>
> diff --git a/src/bin/lttng-consumerd/lttng-consumerd.c b/src/bin/lttng-consumerd/lttng-consumerd.c
> index 5952334..946fb02 100644
> --- a/src/bin/lttng-consumerd/lttng-consumerd.c
> +++ b/src/bin/lttng-consumerd/lttng-consumerd.c
> @@ -356,23 +356,31 @@ int main(int argc, char **argv)
> }
> lttng_consumer_set_error_sock(ctx, ret);
>
> - /* Create the thread to manage the receive of fd */
> - ret = pthread_create(&threads[0], NULL, lttng_consumer_thread_receive_fds,
> + /* Create thread to manage the polling/writing of trace metadata */
> + ret = pthread_create(&threads[0], NULL, consumer_thread_metadata_poll,
> + (void *) ctx);
> + if (ret != 0) {
> + perror("pthread_create");
> + goto error;
> + }
> +
> + /* Create thread to manage the polling/writing of trace data */
> + ret = pthread_create(&threads[1], NULL, consumer_thread_data_poll,
> (void *) ctx);
> if (ret != 0) {
> perror("pthread_create");
> goto error;
> }
>
> - /* Create thread to manage the polling/writing of traces */
> - ret = pthread_create(&threads[1], NULL, lttng_consumer_thread_poll_fds,
> + /* Create the thread to manage the receive of fd */
> + ret = pthread_create(&threads[2], NULL, consumer_thread_sessiond_poll,
> (void *) ctx);
> if (ret != 0) {
> perror("pthread_create");
> goto error;
> }
>
> - for (i = 0; i < 2; i++) {
> + for (i = 0; i < 3; i++) {
> ret = pthread_join(threads[i], &status);
> if (ret != 0) {
> perror("pthread_join");
> diff --git a/src/common/consumer.c b/src/common/consumer.c
> index 242b05b..055de1b 100644
> --- a/src/common/consumer.c
> +++ b/src/common/consumer.c
> @@ -1131,6 +1131,8 @@ void lttng_consumer_destroy(struct lttng_consumer_local_data *ctx)
> PERROR("close");
> }
> utils_close_pipe(ctx->consumer_splice_metadata_pipe);
> + /* This should trigger the metadata thread to exit */
> + close(ctx->consumer_metadata_pipe[1]);
this is adding a close, but did not remove any other remove that might
previously be in place elsewhere.
moreover, the close() return value is not tested.
>
> unlink(ctx->consumer_command_sock_path);
> free(ctx);
> @@ -1756,7 +1758,7 @@ error:
> * Thread polls on metadata file descriptor and write them on disk or on the
> * network.
> */
> -void *lttng_consumer_thread_poll_metadata(void *data)
> +void *consumer_thread_metadata_poll(void *data)
> {
> int ret, i, pollfd;
> uint32_t revents, nb_fd;
> @@ -1939,7 +1941,7 @@ end:
> * This thread polls the fds in the set to consume the data and write
> * it to tracefile if necessary.
> */
> -void *lttng_consumer_thread_poll_fds(void *data)
> +void *consumer_thread_data_poll(void *data)
> {
> int num_rdy, num_hup, high_prio, ret, i;
> struct pollfd *pollfd = NULL;
> @@ -1949,19 +1951,9 @@ void *lttng_consumer_thread_poll_fds(void *data)
> int nb_fd = 0;
> struct lttng_consumer_local_data *ctx = data;
> ssize_t len;
> - pthread_t metadata_thread;
> - void *status;
>
> rcu_register_thread();
>
> - /* Start metadata polling thread */
> - ret = pthread_create(&metadata_thread, NULL,
> - lttng_consumer_thread_poll_metadata, (void *) ctx);
> - if (ret < 0) {
> - PERROR("pthread_create metadata thread");
> - goto end;
> - }
> -
> local_stream = zmalloc(sizeof(struct lttng_consumer_stream));
>
> while (1) {
> @@ -2145,19 +2137,13 @@ end:
>
> /*
> * Close the write side of the pipe so epoll_wait() in
> - * lttng_consumer_thread_poll_metadata can catch it. The thread is
> - * monitoring the read side of the pipe. If we close them both, epoll_wait
> - * strangely does not return and could create a endless wait period if the
> - * pipe is the only tracked fd in the poll set. The thread will take care
> - * of closing the read side.
> + * consumer_thread_metadata_poll can catch it. The thread is monitoring the
> + * read side of the pipe. If we close them both, epoll_wait strangely does
> + * not return and could create a endless wait period if the pipe is the
> + * only tracked fd in the poll set. The thread will take care of closing
> + * the read side.
> */
> close(ctx->consumer_metadata_pipe[1]);
this is the second close on the same FD I'm talking about.
thanks,
Mathieu
> - if (ret) {
> - ret = pthread_join(metadata_thread, &status);
> - if (ret < 0) {
> - PERROR("pthread_join metadata thread");
> - }
> - }
>
> rcu_unregister_thread();
> return NULL;
> @@ -2167,7 +2153,7 @@ end:
> * This thread listens on the consumerd socket and receives the file
> * descriptors from the session daemon.
> */
> -void *lttng_consumer_thread_receive_fds(void *data)
> +void *consumer_thread_sessiond_poll(void *data)
> {
> int sock, client_socket, ret;
> /*
> diff --git a/src/common/consumer.h b/src/common/consumer.h
> index d0cd8fd..4b225e4 100644
> --- a/src/common/consumer.h
> +++ b/src/common/consumer.h
> @@ -385,8 +385,9 @@ extern int lttng_consumer_get_produced_snapshot(
> struct lttng_consumer_local_data *ctx,
> struct lttng_consumer_stream *stream,
> unsigned long *pos);
> -extern void *lttng_consumer_thread_poll_fds(void *data);
> -extern void *lttng_consumer_thread_receive_fds(void *data);
> +extern void *consumer_thread_metadata_poll(void *data);
> +extern void *consumer_thread_data_poll(void *data);
> +extern void *consumer_thread_sessiond_poll(void *data);
> extern int lttng_consumer_recv_cmd(struct lttng_consumer_local_data *ctx,
> int sock, struct pollfd *consumer_sockpoll);
>
> --
> 1.7.10.4
>
>
> _______________________________________________
> lttng-dev mailing list
> lttng-dev at lists.lttng.org
> http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
--
Mathieu Desnoyers
Operating System Efficiency R&D Consultant
EfficiOS Inc.
http://www.efficios.com
^ permalink raw reply [flat|nested] 22+ messages in thread
* [lttng-dev] [PATCH lttng-tools 2/4] Move add data stream to the data thread
2012-10-12 14:30 ` [lttng-dev] [PATCH lttng-tools 2/4] Move add data stream to the data thread David Goulet
@ 2012-10-13 15:53 ` Mathieu Desnoyers
2012-10-15 15:40 ` David Goulet
0 siblings, 1 reply; 22+ messages in thread
From: Mathieu Desnoyers @ 2012-10-13 15:53 UTC (permalink / raw)
* David Goulet (dgoulet at efficios.com) wrote:
> As a second step of refactoring, upon receiving a data stream, we send
> it to the data thread that is now in charge of handling it.
>
> Furthermore, in order for this to behave correctly, we have to make the
> ustctl actions on the stream upon before passing it to the right thread
> (the kernel does not need special actions.). This way, once the sessiond
> thread reply back to the session daemon, the stream is sure to be open
> and ready for data to be recorded on the application side so we avoid a
> race between the application thinking the stream is ready and the stream
> thread still scheduled out.
Normally, as long as we have a reference on the SHM file descriptor, and
we have the wakeup FD, we should be good to fetch the data of buffers
belonging to an application that has already exited, even if it did so
before the ustctl calls are done.
So I'm wondering why you do the ustctl calls in the sessiond thread ? It
seems to complexify the implementation needlessly: we could still do the
ustctl calls and output file open at the same location, the
data/metadata threads.
Thanks,
Mathieu
>
> This commit should speed up the add stream process for the session
> daemon. There is still some actions to move out of the session daemon
> poll thread to gain speed significantly, especially for network
> streaming.
>
> Signed-off-by: David Goulet <dgoulet at efficios.com>
> ---
> src/common/consumer.c | 123 +++++++++++---------------
> src/common/consumer.h | 1 +
> src/common/kernel-consumer/kernel-consumer.c | 24 ++---
> src/common/ust-consumer/ust-consumer.c | 40 ++++-----
> 4 files changed, 78 insertions(+), 110 deletions(-)
>
> diff --git a/src/common/consumer.c b/src/common/consumer.c
> index 055de1b..1d2b1f7 100644
> --- a/src/common/consumer.c
> +++ b/src/common/consumer.c
> @@ -89,7 +89,7 @@ static struct lttng_consumer_stream *consumer_find_stream(int key,
> return stream;
> }
>
> -static void consumer_steal_stream_key(int key, struct lttng_ht *ht)
> +void consumer_steal_stream_key(int key, struct lttng_ht *ht)
> {
> struct lttng_consumer_stream *stream;
>
> @@ -409,6 +409,14 @@ struct lttng_consumer_stream *consumer_allocate_stream(
> lttng_ht_node_init_ulong(&stream->waitfd_node, stream->wait_fd);
> lttng_ht_node_init_ulong(&stream->node, stream->key);
>
> + /*
> + * The cpu number is needed before using any ustctl_* actions. Ignored for
> + * the kernel so the value does not matter.
> + */
> + pthread_mutex_lock(&consumer_data.lock);
> + stream->cpu = stream->chan->cpucount++;
> + pthread_mutex_unlock(&consumer_data.lock);
> +
> DBG3("Allocated stream %s (key %d, shm_fd %d, wait_fd %d, mmap_len %llu,"
> " out_fd %d, net_seq_idx %d)", stream->path_name, stream->key,
> stream->shm_fd, stream->wait_fd,
> @@ -437,28 +445,6 @@ int consumer_add_stream(struct lttng_consumer_stream *stream)
> pthread_mutex_lock(&consumer_data.lock);
> rcu_read_lock();
>
> - switch (consumer_data.type) {
> - case LTTNG_CONSUMER_KERNEL:
> - break;
> - case LTTNG_CONSUMER32_UST:
> - case LTTNG_CONSUMER64_UST:
> - stream->cpu = stream->chan->cpucount++;
> - ret = lttng_ustconsumer_add_stream(stream);
> - if (ret) {
> - ret = -EINVAL;
> - goto error;
> - }
> -
> - /* Steal stream identifier only for UST */
> - consumer_steal_stream_key(stream->key, consumer_data.stream_ht);
> - break;
> - default:
> - ERR("Unknown consumer_data type");
> - assert(0);
> - ret = -ENOSYS;
> - goto error;
> - }
> -
> lttng_ht_add_unique_ulong(consumer_data.stream_ht, &stream->node);
>
> /* Check and cleanup relayd */
> @@ -485,7 +471,6 @@ int consumer_add_stream(struct lttng_consumer_stream *stream)
> consumer_data.stream_count++;
> consumer_data.need_update = 1;
>
> -error:
> rcu_read_unlock();
> pthread_mutex_unlock(&consumer_data.lock);
>
> @@ -1582,17 +1567,6 @@ void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
>
> DBG3("Consumer delete metadata stream %d", stream->wait_fd);
>
> - if (ht == NULL) {
> - /* Means the stream was allocated but not successfully added */
> - goto free_stream;
> - }
> -
> - rcu_read_lock();
> - iter.iter.node = &stream->waitfd_node.node;
> - ret = lttng_ht_del(ht, &iter);
> - assert(!ret);
> - rcu_read_unlock();
> -
> pthread_mutex_lock(&consumer_data.lock);
> switch (consumer_data.type) {
> case LTTNG_CONSUMER_KERNEL:
> @@ -1613,6 +1587,18 @@ void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
> goto end;
> }
>
> + if (ht == NULL) {
> + pthread_mutex_unlock(&consumer_data.lock);
> + /* Means the stream was allocated but not successfully added */
> + goto free_stream;
> + }
> +
> + rcu_read_lock();
> + iter.iter.node = &stream->waitfd_node.node;
> + ret = lttng_ht_del(ht, &iter);
> + assert(!ret);
> + rcu_read_unlock();
> +
> if (stream->out_fd >= 0) {
> ret = close(stream->out_fd);
> if (ret) {
> @@ -1699,27 +1685,6 @@ static int consumer_add_metadata_stream(struct lttng_consumer_stream *stream,
>
> pthread_mutex_lock(&consumer_data.lock);
>
> - switch (consumer_data.type) {
> - case LTTNG_CONSUMER_KERNEL:
> - break;
> - case LTTNG_CONSUMER32_UST:
> - case LTTNG_CONSUMER64_UST:
> - ret = lttng_ustconsumer_add_stream(stream);
> - if (ret) {
> - ret = -EINVAL;
> - goto error;
> - }
> -
> - /* Steal stream identifier only for UST */
> - consumer_steal_stream_key(stream->wait_fd, ht);
> - break;
> - default:
> - ERR("Unknown consumer_data type");
> - assert(0);
> - ret = -ENOSYS;
> - goto error;
> - }
> -
> /*
> * From here, refcounts are updated so be _careful_ when returning an error
> * after this point.
> @@ -1749,7 +1714,6 @@ static int consumer_add_metadata_stream(struct lttng_consumer_stream *stream,
> lttng_ht_add_unique_ulong(ht, &stream->waitfd_node);
> rcu_read_unlock();
>
> -error:
> pthread_mutex_unlock(&consumer_data.lock);
> return ret;
> }
> @@ -1946,7 +1910,7 @@ void *consumer_thread_data_poll(void *data)
> int num_rdy, num_hup, high_prio, ret, i;
> struct pollfd *pollfd = NULL;
> /* local view of the streams */
> - struct lttng_consumer_stream **local_stream = NULL;
> + struct lttng_consumer_stream **local_stream = NULL, *new_stream = NULL;
> /* local view of consumer_data.fds_count */
> int nb_fd = 0;
> struct lttng_consumer_local_data *ctx = data;
> @@ -2034,13 +1998,35 @@ void *consumer_thread_data_poll(void *data)
> */
> if (pollfd[nb_fd].revents & (POLLIN | POLLPRI)) {
> size_t pipe_readlen;
> - char tmp;
>
> DBG("consumer_poll_pipe wake up");
> /* Consume 1 byte of pipe data */
> do {
> - pipe_readlen = read(ctx->consumer_poll_pipe[0], &tmp, 1);
> + pipe_readlen = read(ctx->consumer_poll_pipe[0], &new_stream,
> + sizeof(new_stream));
> } while (pipe_readlen == -1 && errno == EINTR);
> +
> + /*
> + * If the stream is NULL, just ignore it. It's also possible that
> + * the sessiond poll thread changed the consumer_quit state and is
> + * waking us up to test it.
> + */
> + if (new_stream == NULL) {
> + continue;
> + }
> +
> + ret = consumer_add_stream(new_stream);
> + if (ret) {
> + ERR("Consumer add stream %d failed. Continuing",
> + new_stream->key);
> + /*
> + * At this point, if the add_stream fails, it is not in the
> + * hash table thus passing the NULL value here.
> + */
> + consumer_del_stream(new_stream, NULL);
> + }
> +
> + /* Continue to update the local streams and handle prio ones */
> continue;
> }
>
> @@ -2260,19 +2246,16 @@ end:
> consumer_poll_timeout = LTTNG_CONSUMER_POLL_TIMEOUT;
>
> /*
> - * Wake-up the other end by writing a null byte in the pipe
> - * (non-blocking). Important note: Because writing into the
> - * pipe is non-blocking (and therefore we allow dropping wakeup
> - * data, as long as there is wakeup data present in the pipe
> - * buffer to wake up the other end), the other end should
> - * perform the following sequence for waiting:
> - * 1) empty the pipe (reads).
> - * 2) perform update operation.
> - * 3) wait on the pipe (poll).
> + * Notify the data poll thread to poll back again and test the
> + * consumer_quit state to quit gracefully.
> */
> do {
> - ret = write(ctx->consumer_poll_pipe[1], "", 1);
> + struct lttng_consumer_stream *null_stream = NULL;
> +
> + ret = write(ctx->consumer_poll_pipe[1], &null_stream,
> + sizeof(null_stream));
> } while (ret < 0 && errno == EINTR);
> +
> rcu_unregister_thread();
> return NULL;
> }
> diff --git a/src/common/consumer.h b/src/common/consumer.h
> index 4b225e4..8e5891a 100644
> --- a/src/common/consumer.h
> +++ b/src/common/consumer.h
> @@ -362,6 +362,7 @@ struct consumer_relayd_sock_pair *consumer_allocate_relayd_sock_pair(
> struct consumer_relayd_sock_pair *consumer_find_relayd(int key);
> int consumer_handle_stream_before_relayd(struct lttng_consumer_stream *stream,
> size_t data_size);
> +void consumer_steal_stream_key(int key, struct lttng_ht *ht);
>
> extern struct lttng_consumer_local_data *lttng_consumer_create(
> enum lttng_consumer_type type,
> diff --git a/src/common/kernel-consumer/kernel-consumer.c b/src/common/kernel-consumer/kernel-consumer.c
> index 13cbe21..444f5e0 100644
> --- a/src/common/kernel-consumer/kernel-consumer.c
> +++ b/src/common/kernel-consumer/kernel-consumer.c
> @@ -235,10 +235,12 @@ int lttng_kconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
> consumer_del_stream(new_stream, NULL);
> }
> } else {
> - ret = consumer_add_stream(new_stream);
> - if (ret) {
> - ERR("Consumer add stream %d failed. Continuing",
> - new_stream->key);
> + do {
> + ret = write(ctx->consumer_poll_pipe[1], &new_stream,
> + sizeof(new_stream));
> + } while (ret < 0 && errno == EINTR);
> + if (ret < 0) {
> + PERROR("write data pipe");
> consumer_del_stream(new_stream, NULL);
> goto end_nosignal;
> }
> @@ -284,20 +286,6 @@ int lttng_kconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
> goto end_nosignal;
> }
>
> - /*
> - * Wake-up the other end by writing a null byte in the pipe (non-blocking).
> - * Important note: Because writing into the pipe is non-blocking (and
> - * therefore we allow dropping wakeup data, as long as there is wakeup data
> - * present in the pipe buffer to wake up the other end), the other end
> - * should perform the following sequence for waiting:
> - *
> - * 1) empty the pipe (reads).
> - * 2) perform update operation.
> - * 3) wait on the pipe (poll).
> - */
> - do {
> - ret = write(ctx->consumer_poll_pipe[1], "", 1);
> - } while (ret < 0 && errno == EINTR);
> end_nosignal:
> rcu_read_unlock();
>
> diff --git a/src/common/ust-consumer/ust-consumer.c b/src/common/ust-consumer/ust-consumer.c
> index 1170687..4ca4b84 100644
> --- a/src/common/ust-consumer/ust-consumer.c
> +++ b/src/common/ust-consumer/ust-consumer.c
> @@ -224,6 +224,18 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
> goto end_nosignal;
> }
>
> + /*
> + * This needs to be done as soon as we can so we don't block the
> + * application too long.
> + */
> + ret = lttng_ustconsumer_add_stream(new_stream);
> + if (ret) {
> + consumer_del_stream(new_stream, NULL);
> + goto end_nosignal;
> + }
> + /* Steal stream identifier to avoid having streams with the same key */
> + consumer_steal_stream_key(new_stream->key, consumer_data.stream_ht);
> +
> /* The stream is not metadata. Get relayd reference if exists. */
> relayd = consumer_find_relayd(msg.u.stream.net_index);
> if (relayd != NULL) {
> @@ -265,14 +277,12 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
> goto end_nosignal;
> }
> } else {
> - ret = consumer_add_stream(new_stream);
> - if (ret) {
> - ERR("Consumer add stream %d failed. Continuing",
> - new_stream->key);
> - /*
> - * At this point, if the add_stream fails, it is not in the
> - * hash table thus passing the NULL value here.
> - */
> + do {
> + ret = write(ctx->consumer_poll_pipe[1], &new_stream,
> + sizeof(new_stream));
> + } while (ret < 0 && errno == EINTR);
> + if (ret < 0) {
> + PERROR("write data pipe");
> consumer_del_stream(new_stream, NULL);
> goto end_nosignal;
> }
> @@ -334,20 +344,6 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
> break;
> }
>
> - /*
> - * Wake-up the other end by writing a null byte in the pipe (non-blocking).
> - * Important note: Because writing into the pipe is non-blocking (and
> - * therefore we allow dropping wakeup data, as long as there is wakeup data
> - * present in the pipe buffer to wake up the other end), the other end
> - * should perform the following sequence for waiting:
> - *
> - * 1) empty the pipe (reads).
> - * 2) perform update operation.
> - * 3) wait on the pipe (poll).
> - */
> - do {
> - ret = write(ctx->consumer_poll_pipe[1], "", 1);
> - } while (ret < 0 && errno == EINTR);
> end_nosignal:
> rcu_read_unlock();
>
> --
> 1.7.10.4
>
>
> _______________________________________________
> lttng-dev mailing list
> lttng-dev at lists.lttng.org
> http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
--
Mathieu Desnoyers
Operating System Efficiency R&D Consultant
EfficiOS Inc.
http://www.efficios.com
^ permalink raw reply [flat|nested] 22+ messages in thread
* [lttng-dev] [PATCH lttng-tools 3/4] Make stream hash tables global to the consumer
2012-10-12 14:30 ` [lttng-dev] [PATCH lttng-tools 3/4] Make stream hash tables global to the consumer David Goulet
@ 2012-10-13 15:56 ` Mathieu Desnoyers
2012-10-15 15:47 ` David Goulet
0 siblings, 1 reply; 22+ messages in thread
From: Mathieu Desnoyers @ 2012-10-13 15:56 UTC (permalink / raw)
* David Goulet (dgoulet at efficios.com) wrote:
> The data stream hash table is now global to the consumer and used in the
> data thread. The consumer_data stream_ht is no longer used to track the
> data streams but instead will be used (and possibly renamed) by the
> session daemon poll thread to keep track of streams on a per session id
> basis for the upcoming feature that check traced data availability.
>
> For now, in order to avoid mind bugging problems to access the streams,
> both hash table are now defined globally (metadata and data). However,
> stream update are still done in a single thread. Don't count on this to
> be guaranteed in the next commits.
>
> Signed-off-by: David Goulet <dgoulet at efficios.com>
> ---
> src/common/consumer.c | 91 +++++++++++++++++++++++++-------
> src/common/consumer.h | 9 ++--
> src/common/ust-consumer/ust-consumer.c | 2 -
> 3 files changed, 75 insertions(+), 27 deletions(-)
>
> diff --git a/src/common/consumer.c b/src/common/consumer.c
> index 1d2b1f7..1fb9960 100644
> --- a/src/common/consumer.c
> +++ b/src/common/consumer.c
> @@ -59,6 +59,17 @@ int consumer_poll_timeout = -1;
> volatile int consumer_quit = 0;
>
> /*
> + * The following two hash tables are visible by all threads which are separated
> + * in different source files.
> + *
> + * Global hash table containing respectively metadata and data streams. The
> + * stream element in this ht should only be updated by the metadata poll thread
> + * for the metadata and the data poll thread for the data.
> + */
> +struct lttng_ht *metadata_ht = NULL;
> +struct lttng_ht *data_ht = NULL;
> +
> +/*
> * Find a stream. The consumer_data.lock must be locked during this
> * call.
> */
> @@ -433,19 +444,24 @@ end:
> /*
> * Add a stream to the global list protected by a mutex.
> */
> -int consumer_add_stream(struct lttng_consumer_stream *stream)
> +static int consumer_add_stream(struct lttng_consumer_stream *stream,
> + struct lttng_ht *ht)
> {
> int ret = 0;
> struct consumer_relayd_sock_pair *relayd;
>
> assert(stream);
> + assert(ht);
>
> DBG3("Adding consumer stream %d", stream->key);
>
> pthread_mutex_lock(&consumer_data.lock);
> rcu_read_lock();
>
> - lttng_ht_add_unique_ulong(consumer_data.stream_ht, &stream->node);
> + /* Steal stream identifier to avoid having streams with the same key */
> + consumer_steal_stream_key(stream->key, ht);
I don't understand why suddenly this change is needed. Considering what
this patch should be doing (just moving a ht from per-thread to global),
it should not have any behavior impact.
Thanks,
Mathieu
> +
> + lttng_ht_add_unique_ulong(ht, &stream->node);
>
> /* Check and cleanup relayd */
> relayd = consumer_find_relayd(stream->net_seq_idx);
> @@ -783,9 +799,9 @@ end:
> *
> * Returns the number of fds in the structures.
> */
> -int consumer_update_poll_array(
> +static int consumer_update_poll_array(
> struct lttng_consumer_local_data *ctx, struct pollfd **pollfd,
> - struct lttng_consumer_stream **local_stream)
> + struct lttng_consumer_stream **local_stream, struct lttng_ht *ht)
> {
> int i = 0;
> struct lttng_ht_iter iter;
> @@ -793,8 +809,7 @@ int consumer_update_poll_array(
>
> DBG("Updating poll fd array");
> rcu_read_lock();
> - cds_lfht_for_each_entry(consumer_data.stream_ht->ht, &iter.iter, stream,
> - node.node) {
> + cds_lfht_for_each_entry(ht->ht, &iter.iter, stream, node.node) {
> if (stream->state != LTTNG_CONSUMER_ACTIVE_STREAM) {
> continue;
> }
> @@ -1523,6 +1538,33 @@ int lttng_consumer_recv_cmd(struct lttng_consumer_local_data *ctx,
> /*
> * Iterate over all streams of the hashtable and free them properly.
> *
> + * WARNING: *MUST* be used with data stream only.
> + */
> +static void destroy_data_stream_ht(struct lttng_ht *ht)
> +{
> + int ret;
> + struct lttng_ht_iter iter;
> + struct lttng_consumer_stream *stream;
> +
> + if (ht == NULL) {
> + return;
> + }
> +
> + rcu_read_lock();
> + cds_lfht_for_each_entry(ht->ht, &iter.iter, stream, node.node) {
> + ret = lttng_ht_del(ht, &iter);
> + assert(!ret);
> +
> + call_rcu(&stream->node.head, consumer_free_stream);
> + }
> + rcu_read_unlock();
> +
> + lttng_ht_destroy(ht);
> +}
> +
> +/*
> + * Iterate over all streams of the hashtable and free them properly.
> + *
> * XXX: Should not be only for metadata stream or else use an other name.
> */
> static void destroy_stream_ht(struct lttng_ht *ht)
> @@ -1711,6 +1753,9 @@ static int consumer_add_metadata_stream(struct lttng_consumer_stream *stream,
> uatomic_dec(&stream->chan->nb_init_streams);
> }
>
> + /* Steal stream identifier to avoid having streams with the same key */
> + consumer_steal_stream_key(stream->key, ht);
> +
> lttng_ht_add_unique_ulong(ht, &stream->waitfd_node);
> rcu_read_unlock();
>
> @@ -1729,7 +1774,6 @@ void *consumer_thread_metadata_poll(void *data)
> struct lttng_consumer_stream *stream = NULL;
> struct lttng_ht_iter iter;
> struct lttng_ht_node_ulong *node;
> - struct lttng_ht *metadata_ht = NULL;
> struct lttng_poll_event events;
> struct lttng_consumer_local_data *ctx = data;
> ssize_t len;
> @@ -1738,11 +1782,6 @@ void *consumer_thread_metadata_poll(void *data)
>
> DBG("Thread metadata poll started");
>
> - metadata_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
> - if (metadata_ht == NULL) {
> - goto end;
> - }
> -
> /* Size is set to 1 for the consumer_metadata pipe */
> ret = lttng_poll_create(&events, 2, LTTNG_CLOEXEC);
> if (ret < 0) {
> @@ -1918,6 +1957,11 @@ void *consumer_thread_data_poll(void *data)
>
> rcu_register_thread();
>
> + data_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
> + if (data_ht == NULL) {
> + goto end;
> + }
> +
> local_stream = zmalloc(sizeof(struct lttng_consumer_stream));
>
> while (1) {
> @@ -1955,7 +1999,8 @@ void *consumer_thread_data_poll(void *data)
> pthread_mutex_unlock(&consumer_data.lock);
> goto end;
> }
> - ret = consumer_update_poll_array(ctx, &pollfd, local_stream);
> + ret = consumer_update_poll_array(ctx, &pollfd, local_stream,
> + data_ht);
> if (ret < 0) {
> ERR("Error in allocating pollfd or local_outfds");
> lttng_consumer_send_error(ctx, LTTCOMM_CONSUMERD_POLL_ERROR);
> @@ -2015,7 +2060,7 @@ void *consumer_thread_data_poll(void *data)
> continue;
> }
>
> - ret = consumer_add_stream(new_stream);
> + ret = consumer_add_stream(new_stream, data_ht);
> if (ret) {
> ERR("Consumer add stream %d failed. Continuing",
> new_stream->key);
> @@ -2088,22 +2133,19 @@ void *consumer_thread_data_poll(void *data)
> if ((pollfd[i].revents & POLLHUP)) {
> DBG("Polling fd %d tells it has hung up.", pollfd[i].fd);
> if (!local_stream[i]->data_read) {
> - consumer_del_stream(local_stream[i],
> - consumer_data.stream_ht);
> + consumer_del_stream(local_stream[i], data_ht);
> num_hup++;
> }
> } else if (pollfd[i].revents & POLLERR) {
> ERR("Error returned in polling fd %d.", pollfd[i].fd);
> if (!local_stream[i]->data_read) {
> - consumer_del_stream(local_stream[i],
> - consumer_data.stream_ht);
> + consumer_del_stream(local_stream[i], data_ht);
> num_hup++;
> }
> } else if (pollfd[i].revents & POLLNVAL) {
> ERR("Polling fd %d tells fd is not open.", pollfd[i].fd);
> if (!local_stream[i]->data_read) {
> - consumer_del_stream(local_stream[i],
> - consumer_data.stream_ht);
> + consumer_del_stream(local_stream[i], data_ht);
> num_hup++;
> }
> }
> @@ -2131,6 +2173,10 @@ end:
> */
> close(ctx->consumer_metadata_pipe[1]);
>
> + if (data_ht) {
> + destroy_data_stream_ht(data_ht);
> + }
> +
> rcu_unregister_thread();
> return NULL;
> }
> @@ -2299,6 +2345,11 @@ void lttng_consumer_init(void)
> consumer_data.stream_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
> consumer_data.channel_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
> consumer_data.relayd_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
> +
> + metadata_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
> + assert(metadata_ht);
> + data_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
> + assert(data_ht);
> }
>
> /*
> diff --git a/src/common/consumer.h b/src/common/consumer.h
> index 8e5891a..6bce96d 100644
> --- a/src/common/consumer.h
> +++ b/src/common/consumer.h
> @@ -275,6 +275,10 @@ struct lttng_consumer_global_data {
> struct lttng_ht *relayd_ht;
> };
>
> +/* Defined in consumer.c and coupled with explanations */
> +extern struct lttng_ht *metadata_ht;
> +extern struct lttng_ht *data_ht;
> +
> /*
> * Init consumer data structures.
> */
> @@ -324,10 +328,6 @@ extern void lttng_consumer_sync_trace_file(
> */
> extern int lttng_consumer_poll_socket(struct pollfd *kconsumer_sockpoll);
>
> -extern int consumer_update_poll_array(
> - struct lttng_consumer_local_data *ctx, struct pollfd **pollfd,
> - struct lttng_consumer_stream **local_consumer_streams);
> -
> extern struct lttng_consumer_stream *consumer_allocate_stream(
> int channel_key, int stream_key,
> int shm_fd, int wait_fd,
> @@ -340,7 +340,6 @@ extern struct lttng_consumer_stream *consumer_allocate_stream(
> int net_index,
> int metadata_flag,
> int *alloc_ret);
> -extern int consumer_add_stream(struct lttng_consumer_stream *stream);
> extern void consumer_del_stream(struct lttng_consumer_stream *stream,
> struct lttng_ht *ht);
> extern void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
> diff --git a/src/common/ust-consumer/ust-consumer.c b/src/common/ust-consumer/ust-consumer.c
> index 4ca4b84..3b41e55 100644
> --- a/src/common/ust-consumer/ust-consumer.c
> +++ b/src/common/ust-consumer/ust-consumer.c
> @@ -233,8 +233,6 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
> consumer_del_stream(new_stream, NULL);
> goto end_nosignal;
> }
> - /* Steal stream identifier to avoid having streams with the same key */
> - consumer_steal_stream_key(new_stream->key, consumer_data.stream_ht);
>
> /* The stream is not metadata. Get relayd reference if exists. */
> relayd = consumer_find_relayd(msg.u.stream.net_index);
> --
> 1.7.10.4
>
>
> _______________________________________________
> lttng-dev mailing list
> lttng-dev at lists.lttng.org
> http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
--
Mathieu Desnoyers
Operating System Efficiency R&D Consultant
EfficiOS Inc.
http://www.efficios.com
^ permalink raw reply [flat|nested] 22+ messages in thread
* [lttng-dev] [PATCH lttng-tools 4/4] Change the metadata hash table node
2012-10-12 14:30 ` [lttng-dev] [PATCH lttng-tools 4/4] Change the metadata hash table node David Goulet
@ 2012-10-13 16:00 ` Mathieu Desnoyers
2012-10-15 19:22 ` David Goulet
0 siblings, 1 reply; 22+ messages in thread
From: Mathieu Desnoyers @ 2012-10-13 16:00 UTC (permalink / raw)
* David Goulet (dgoulet at efficios.com) wrote:
> Remove the use of the "waitfd_node" for metadata and index the "node" by
> wait fd during stream allocation only for metadata stream.
>
> This was done so the waitfd node could be used later on for the hash
> table indexing stream by session id the traced data check command (soon
> to be implemented).
this last changelog paragraph, being using "was" (past) is confusing me.
Is it what you are now doing (present) or what was there before that you
are changing ?
Thanks,
Mathieu
>
> Signed-off-by: David Goulet <dgoulet at efficios.com>
> ---
> src/common/consumer.c | 36 +++++++++++++++++-------------------
> 1 file changed, 17 insertions(+), 19 deletions(-)
>
> diff --git a/src/common/consumer.c b/src/common/consumer.c
> index 1fb9960..0c1a812 100644
> --- a/src/common/consumer.c
> +++ b/src/common/consumer.c
> @@ -172,17 +172,6 @@ void consumer_free_stream(struct rcu_head *head)
> free(stream);
> }
>
> -static
> -void consumer_free_metadata_stream(struct rcu_head *head)
> -{
> - struct lttng_ht_node_ulong *node =
> - caa_container_of(head, struct lttng_ht_node_ulong, head);
> - struct lttng_consumer_stream *stream =
> - caa_container_of(node, struct lttng_consumer_stream, waitfd_node);
> -
> - free(stream);
> -}
> -
> /*
> * RCU protected relayd socket pair free.
> */
> @@ -417,8 +406,17 @@ struct lttng_consumer_stream *consumer_allocate_stream(
> stream->metadata_flag = metadata_flag;
> strncpy(stream->path_name, path_name, sizeof(stream->path_name));
> stream->path_name[sizeof(stream->path_name) - 1] = '\0';
> - lttng_ht_node_init_ulong(&stream->waitfd_node, stream->wait_fd);
> - lttng_ht_node_init_ulong(&stream->node, stream->key);
> +
> + /*
> + * Index differently the metadata node because the thread is using an
> + * internal hash table to match streams in the metadata_ht to the epoll set
> + * file descriptor.
> + */
> + if (metadata_flag) {
> + lttng_ht_node_init_ulong(&stream->node, stream->wait_fd);
> + } else {
> + lttng_ht_node_init_ulong(&stream->node, stream->key);
> + }
>
> /*
> * The cpu number is needed before using any ustctl_* actions. Ignored for
> @@ -1578,11 +1576,11 @@ static void destroy_stream_ht(struct lttng_ht *ht)
> }
>
> rcu_read_lock();
> - cds_lfht_for_each_entry(ht->ht, &iter.iter, stream, waitfd_node.node) {
> + cds_lfht_for_each_entry(ht->ht, &iter.iter, stream, node.node) {
> ret = lttng_ht_del(ht, &iter);
> assert(!ret);
>
> - call_rcu(&stream->waitfd_node.head, consumer_free_metadata_stream);
> + call_rcu(&stream->node.head, consumer_free_stream);
> }
> rcu_read_unlock();
>
> @@ -1636,7 +1634,7 @@ void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
> }
>
> rcu_read_lock();
> - iter.iter.node = &stream->waitfd_node.node;
> + iter.iter.node = &stream->node.node;
> ret = lttng_ht_del(ht, &iter);
> assert(!ret);
> rcu_read_unlock();
> @@ -1707,7 +1705,7 @@ end:
> }
>
> free_stream:
> - call_rcu(&stream->waitfd_node.head, consumer_free_metadata_stream);
> + call_rcu(&stream->node.head, consumer_free_stream);
> }
>
> /*
> @@ -1756,7 +1754,7 @@ static int consumer_add_metadata_stream(struct lttng_consumer_stream *stream,
> /* Steal stream identifier to avoid having streams with the same key */
> consumer_steal_stream_key(stream->key, ht);
>
> - lttng_ht_add_unique_ulong(ht, &stream->waitfd_node);
> + lttng_ht_add_unique_ulong(ht, &stream->node);
> rcu_read_unlock();
>
> pthread_mutex_unlock(&consumer_data.lock);
> @@ -1881,7 +1879,7 @@ restart:
> assert(node);
>
> stream = caa_container_of(node, struct lttng_consumer_stream,
> - waitfd_node);
> + node);
>
> /* Check for error event */
> if (revents & (LPOLLERR | LPOLLHUP)) {
> --
> 1.7.10.4
>
>
> _______________________________________________
> lttng-dev mailing list
> lttng-dev at lists.lttng.org
> http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
--
Mathieu Desnoyers
Operating System Efficiency R&D Consultant
EfficiOS Inc.
http://www.efficios.com
^ permalink raw reply [flat|nested] 22+ messages in thread
* [lttng-dev] [PATCH lttng-tools 1/4] Rename consumer threads and spawn them in daemon
2012-10-13 15:41 ` [lttng-dev] [PATCH lttng-tools 1/4] Rename consumer threads and spawn them in daemon Mathieu Desnoyers
@ 2012-10-15 15:39 ` David Goulet
2012-10-15 17:28 ` Mathieu Desnoyers
0 siblings, 1 reply; 22+ messages in thread
From: David Goulet @ 2012-10-15 15:39 UTC (permalink / raw)
Mathieu Desnoyers:
> * David Goulet (dgoulet at efficios.com) wrote:
>> The metadata thread is now created in the lttng-consumerd daemon so all
>> thread could be controlled inside the daemon.
>>
>> This is the first step of a consumer thread refactoring which aims at
>> moving data and metadata stream operations inside a dedicated thread so
>> the session daemon thread does not block and is more efficient at adding
>> streams.
>>
>> The most important concept is that a stream file descriptor MUST be
>> opened as quickly as we can than passed to the right thread (for UST
>
> than -> then
>
>> since they are already opened by the session daemon for the kernel).
>>
>> Signed-off-by: David Goulet <dgoulet at efficios.com>
>> ---
>> src/bin/lttng-consumerd/lttng-consumerd.c | 18 ++++++++++-----
>> src/common/consumer.c | 34 +++++++++--------------------
>> src/common/consumer.h | 5 +++--
>> 3 files changed, 26 insertions(+), 31 deletions(-)
>>
>> diff --git a/src/bin/lttng-consumerd/lttng-consumerd.c b/src/bin/lttng-consumerd/lttng-consumerd.c
>> index 5952334..946fb02 100644
>> --- a/src/bin/lttng-consumerd/lttng-consumerd.c
>> +++ b/src/bin/lttng-consumerd/lttng-consumerd.c
>> @@ -356,23 +356,31 @@ int main(int argc, char **argv)
>> }
>> lttng_consumer_set_error_sock(ctx, ret);
>>
>> - /* Create the thread to manage the receive of fd */
>> - ret = pthread_create(&threads[0], NULL, lttng_consumer_thread_receive_fds,
>> + /* Create thread to manage the polling/writing of trace metadata */
>> + ret = pthread_create(&threads[0], NULL, consumer_thread_metadata_poll,
>> + (void *) ctx);
>> + if (ret != 0) {
>> + perror("pthread_create");
>> + goto error;
>> + }
>> +
>> + /* Create thread to manage the polling/writing of trace data */
>> + ret = pthread_create(&threads[1], NULL, consumer_thread_data_poll,
>> (void *) ctx);
>> if (ret != 0) {
>> perror("pthread_create");
>> goto error;
>> }
>>
>> - /* Create thread to manage the polling/writing of traces */
>> - ret = pthread_create(&threads[1], NULL, lttng_consumer_thread_poll_fds,
>> + /* Create the thread to manage the receive of fd */
>> + ret = pthread_create(&threads[2], NULL, consumer_thread_sessiond_poll,
>> (void *) ctx);
>> if (ret != 0) {
>> perror("pthread_create");
>> goto error;
>> }
>>
>> - for (i = 0; i < 2; i++) {
>> + for (i = 0; i < 3; i++) {
>> ret = pthread_join(threads[i], &status);
>> if (ret != 0) {
>> perror("pthread_join");
>> diff --git a/src/common/consumer.c b/src/common/consumer.c
>> index 242b05b..055de1b 100644
>> --- a/src/common/consumer.c
>> +++ b/src/common/consumer.c
>> @@ -1131,6 +1131,8 @@ void lttng_consumer_destroy(struct lttng_consumer_local_data *ctx)
>> PERROR("close");
>> }
>> utils_close_pipe(ctx->consumer_splice_metadata_pipe);
>> + /* This should trigger the metadata thread to exit */
>> + close(ctx->consumer_metadata_pipe[1]);
>
> this is adding a close, but did not remove any other remove that might
> previously be in place elsewhere.
So we got two possible error path which is either the poll thread fails
or the consumer could be destroy by hand even though the threads are
working well.
Actually, this close should check if the value is valid and close it. To
be honest, this is just a shortcut since close(-1) does not fail and
ignoring the close error here since we are in the cleanup path anyway so
we don't necessarily care about the perror message.
Anyhow, we have to handle both error path. An if plus set -1 after close
can be done so not to confuse.
David
>
> moreover, the close() return value is not tested.
>>
>> unlink(ctx->consumer_command_sock_path);
>> free(ctx);
>> @@ -1756,7 +1758,7 @@ error:
>> * Thread polls on metadata file descriptor and write them on disk or on the
>> * network.
>> */
>> -void *lttng_consumer_thread_poll_metadata(void *data)
>> +void *consumer_thread_metadata_poll(void *data)
>> {
>> int ret, i, pollfd;
>> uint32_t revents, nb_fd;
>> @@ -1939,7 +1941,7 @@ end:
>> * This thread polls the fds in the set to consume the data and write
>> * it to tracefile if necessary.
>> */
>> -void *lttng_consumer_thread_poll_fds(void *data)
>> +void *consumer_thread_data_poll(void *data)
>> {
>> int num_rdy, num_hup, high_prio, ret, i;
>> struct pollfd *pollfd = NULL;
>> @@ -1949,19 +1951,9 @@ void *lttng_consumer_thread_poll_fds(void *data)
>> int nb_fd = 0;
>> struct lttng_consumer_local_data *ctx = data;
>> ssize_t len;
>> - pthread_t metadata_thread;
>> - void *status;
>>
>> rcu_register_thread();
>>
>> - /* Start metadata polling thread */
>> - ret = pthread_create(&metadata_thread, NULL,
>> - lttng_consumer_thread_poll_metadata, (void *) ctx);
>> - if (ret < 0) {
>> - PERROR("pthread_create metadata thread");
>> - goto end;
>> - }
>> -
>> local_stream = zmalloc(sizeof(struct lttng_consumer_stream));
>>
>> while (1) {
>> @@ -2145,19 +2137,13 @@ end:
>>
>> /*
>> * Close the write side of the pipe so epoll_wait() in
>> - * lttng_consumer_thread_poll_metadata can catch it. The thread is
>> - * monitoring the read side of the pipe. If we close them both, epoll_wait
>> - * strangely does not return and could create a endless wait period if the
>> - * pipe is the only tracked fd in the poll set. The thread will take care
>> - * of closing the read side.
>> + * consumer_thread_metadata_poll can catch it. The thread is monitoring the
>> + * read side of the pipe. If we close them both, epoll_wait strangely does
>> + * not return and could create a endless wait period if the pipe is the
>> + * only tracked fd in the poll set. The thread will take care of closing
>> + * the read side.
>> */
>> close(ctx->consumer_metadata_pipe[1]);
>
> this is the second close on the same FD I'm talking about.
>
> thanks,
>
> Mathieu
>
>> - if (ret) {
>> - ret = pthread_join(metadata_thread, &status);
>> - if (ret < 0) {
>> - PERROR("pthread_join metadata thread");
>> - }
>> - }
>>
>> rcu_unregister_thread();
>> return NULL;
>> @@ -2167,7 +2153,7 @@ end:
>> * This thread listens on the consumerd socket and receives the file
>> * descriptors from the session daemon.
>> */
>> -void *lttng_consumer_thread_receive_fds(void *data)
>> +void *consumer_thread_sessiond_poll(void *data)
>> {
>> int sock, client_socket, ret;
>> /*
>> diff --git a/src/common/consumer.h b/src/common/consumer.h
>> index d0cd8fd..4b225e4 100644
>> --- a/src/common/consumer.h
>> +++ b/src/common/consumer.h
>> @@ -385,8 +385,9 @@ extern int lttng_consumer_get_produced_snapshot(
>> struct lttng_consumer_local_data *ctx,
>> struct lttng_consumer_stream *stream,
>> unsigned long *pos);
>> -extern void *lttng_consumer_thread_poll_fds(void *data);
>> -extern void *lttng_consumer_thread_receive_fds(void *data);
>> +extern void *consumer_thread_metadata_poll(void *data);
>> +extern void *consumer_thread_data_poll(void *data);
>> +extern void *consumer_thread_sessiond_poll(void *data);
>> extern int lttng_consumer_recv_cmd(struct lttng_consumer_local_data *ctx,
>> int sock, struct pollfd *consumer_sockpoll);
>>
>> --
>> 1.7.10.4
>>
>>
>> _______________________________________________
>> lttng-dev mailing list
>> lttng-dev at lists.lttng.org
>> http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* [lttng-dev] [PATCH lttng-tools 2/4] Move add data stream to the data thread
2012-10-13 15:53 ` Mathieu Desnoyers
@ 2012-10-15 15:40 ` David Goulet
2012-10-15 17:31 ` Mathieu Desnoyers
0 siblings, 1 reply; 22+ messages in thread
From: David Goulet @ 2012-10-15 15:40 UTC (permalink / raw)
Mathieu Desnoyers:
> * David Goulet (dgoulet at efficios.com) wrote:
>> As a second step of refactoring, upon receiving a data stream, we send
>> it to the data thread that is now in charge of handling it.
>>
>> Furthermore, in order for this to behave correctly, we have to make the
>> ustctl actions on the stream upon before passing it to the right thread
>> (the kernel does not need special actions.). This way, once the sessiond
>> thread reply back to the session daemon, the stream is sure to be open
>> and ready for data to be recorded on the application side so we avoid a
>> race between the application thinking the stream is ready and the stream
>> thread still scheduled out.
>
> Normally, as long as we have a reference on the SHM file descriptor, and
> we have the wakeup FD, we should be good to fetch the data of buffers
> belonging to an application that has already exited, even if it did so
> before the ustctl calls are done.
>
> So I'm wondering why you do the ustctl calls in the sessiond thread ? It
> seems to complexify the implementation needlessly: we could still do the
> ustctl calls and output file open at the same location, the
> data/metadata threads.
Hmmm, it was my understanding that does ustctl_* calls were needed
before the trace could be recording thus making them quickly. Wrong?
David
>
> Thanks,
>
> Mathieu
>
>>
>> This commit should speed up the add stream process for the session
>> daemon. There is still some actions to move out of the session daemon
>> poll thread to gain speed significantly, especially for network
>> streaming.
>>
>> Signed-off-by: David Goulet <dgoulet at efficios.com>
>> ---
>> src/common/consumer.c | 123 +++++++++++---------------
>> src/common/consumer.h | 1 +
>> src/common/kernel-consumer/kernel-consumer.c | 24 ++---
>> src/common/ust-consumer/ust-consumer.c | 40 ++++-----
>> 4 files changed, 78 insertions(+), 110 deletions(-)
>>
>> diff --git a/src/common/consumer.c b/src/common/consumer.c
>> index 055de1b..1d2b1f7 100644
>> --- a/src/common/consumer.c
>> +++ b/src/common/consumer.c
>> @@ -89,7 +89,7 @@ static struct lttng_consumer_stream *consumer_find_stream(int key,
>> return stream;
>> }
>>
>> -static void consumer_steal_stream_key(int key, struct lttng_ht *ht)
>> +void consumer_steal_stream_key(int key, struct lttng_ht *ht)
>> {
>> struct lttng_consumer_stream *stream;
>>
>> @@ -409,6 +409,14 @@ struct lttng_consumer_stream *consumer_allocate_stream(
>> lttng_ht_node_init_ulong(&stream->waitfd_node, stream->wait_fd);
>> lttng_ht_node_init_ulong(&stream->node, stream->key);
>>
>> + /*
>> + * The cpu number is needed before using any ustctl_* actions. Ignored for
>> + * the kernel so the value does not matter.
>> + */
>> + pthread_mutex_lock(&consumer_data.lock);
>> + stream->cpu = stream->chan->cpucount++;
>> + pthread_mutex_unlock(&consumer_data.lock);
>> +
>> DBG3("Allocated stream %s (key %d, shm_fd %d, wait_fd %d, mmap_len %llu,"
>> " out_fd %d, net_seq_idx %d)", stream->path_name, stream->key,
>> stream->shm_fd, stream->wait_fd,
>> @@ -437,28 +445,6 @@ int consumer_add_stream(struct lttng_consumer_stream *stream)
>> pthread_mutex_lock(&consumer_data.lock);
>> rcu_read_lock();
>>
>> - switch (consumer_data.type) {
>> - case LTTNG_CONSUMER_KERNEL:
>> - break;
>> - case LTTNG_CONSUMER32_UST:
>> - case LTTNG_CONSUMER64_UST:
>> - stream->cpu = stream->chan->cpucount++;
>> - ret = lttng_ustconsumer_add_stream(stream);
>> - if (ret) {
>> - ret = -EINVAL;
>> - goto error;
>> - }
>> -
>> - /* Steal stream identifier only for UST */
>> - consumer_steal_stream_key(stream->key, consumer_data.stream_ht);
>> - break;
>> - default:
>> - ERR("Unknown consumer_data type");
>> - assert(0);
>> - ret = -ENOSYS;
>> - goto error;
>> - }
>> -
>> lttng_ht_add_unique_ulong(consumer_data.stream_ht, &stream->node);
>>
>> /* Check and cleanup relayd */
>> @@ -485,7 +471,6 @@ int consumer_add_stream(struct lttng_consumer_stream *stream)
>> consumer_data.stream_count++;
>> consumer_data.need_update = 1;
>>
>> -error:
>> rcu_read_unlock();
>> pthread_mutex_unlock(&consumer_data.lock);
>>
>> @@ -1582,17 +1567,6 @@ void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
>>
>> DBG3("Consumer delete metadata stream %d", stream->wait_fd);
>>
>> - if (ht == NULL) {
>> - /* Means the stream was allocated but not successfully added */
>> - goto free_stream;
>> - }
>> -
>> - rcu_read_lock();
>> - iter.iter.node = &stream->waitfd_node.node;
>> - ret = lttng_ht_del(ht, &iter);
>> - assert(!ret);
>> - rcu_read_unlock();
>> -
>> pthread_mutex_lock(&consumer_data.lock);
>> switch (consumer_data.type) {
>> case LTTNG_CONSUMER_KERNEL:
>> @@ -1613,6 +1587,18 @@ void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
>> goto end;
>> }
>>
>> + if (ht == NULL) {
>> + pthread_mutex_unlock(&consumer_data.lock);
>> + /* Means the stream was allocated but not successfully added */
>> + goto free_stream;
>> + }
>> +
>> + rcu_read_lock();
>> + iter.iter.node = &stream->waitfd_node.node;
>> + ret = lttng_ht_del(ht, &iter);
>> + assert(!ret);
>> + rcu_read_unlock();
>> +
>> if (stream->out_fd >= 0) {
>> ret = close(stream->out_fd);
>> if (ret) {
>> @@ -1699,27 +1685,6 @@ static int consumer_add_metadata_stream(struct lttng_consumer_stream *stream,
>>
>> pthread_mutex_lock(&consumer_data.lock);
>>
>> - switch (consumer_data.type) {
>> - case LTTNG_CONSUMER_KERNEL:
>> - break;
>> - case LTTNG_CONSUMER32_UST:
>> - case LTTNG_CONSUMER64_UST:
>> - ret = lttng_ustconsumer_add_stream(stream);
>> - if (ret) {
>> - ret = -EINVAL;
>> - goto error;
>> - }
>> -
>> - /* Steal stream identifier only for UST */
>> - consumer_steal_stream_key(stream->wait_fd, ht);
>> - break;
>> - default:
>> - ERR("Unknown consumer_data type");
>> - assert(0);
>> - ret = -ENOSYS;
>> - goto error;
>> - }
>> -
>> /*
>> * From here, refcounts are updated so be _careful_ when returning an error
>> * after this point.
>> @@ -1749,7 +1714,6 @@ static int consumer_add_metadata_stream(struct lttng_consumer_stream *stream,
>> lttng_ht_add_unique_ulong(ht, &stream->waitfd_node);
>> rcu_read_unlock();
>>
>> -error:
>> pthread_mutex_unlock(&consumer_data.lock);
>> return ret;
>> }
>> @@ -1946,7 +1910,7 @@ void *consumer_thread_data_poll(void *data)
>> int num_rdy, num_hup, high_prio, ret, i;
>> struct pollfd *pollfd = NULL;
>> /* local view of the streams */
>> - struct lttng_consumer_stream **local_stream = NULL;
>> + struct lttng_consumer_stream **local_stream = NULL, *new_stream = NULL;
>> /* local view of consumer_data.fds_count */
>> int nb_fd = 0;
>> struct lttng_consumer_local_data *ctx = data;
>> @@ -2034,13 +1998,35 @@ void *consumer_thread_data_poll(void *data)
>> */
>> if (pollfd[nb_fd].revents & (POLLIN | POLLPRI)) {
>> size_t pipe_readlen;
>> - char tmp;
>>
>> DBG("consumer_poll_pipe wake up");
>> /* Consume 1 byte of pipe data */
>> do {
>> - pipe_readlen = read(ctx->consumer_poll_pipe[0], &tmp, 1);
>> + pipe_readlen = read(ctx->consumer_poll_pipe[0], &new_stream,
>> + sizeof(new_stream));
>> } while (pipe_readlen == -1 && errno == EINTR);
>> +
>> + /*
>> + * If the stream is NULL, just ignore it. It's also possible that
>> + * the sessiond poll thread changed the consumer_quit state and is
>> + * waking us up to test it.
>> + */
>> + if (new_stream == NULL) {
>> + continue;
>> + }
>> +
>> + ret = consumer_add_stream(new_stream);
>> + if (ret) {
>> + ERR("Consumer add stream %d failed. Continuing",
>> + new_stream->key);
>> + /*
>> + * At this point, if the add_stream fails, it is not in the
>> + * hash table thus passing the NULL value here.
>> + */
>> + consumer_del_stream(new_stream, NULL);
>> + }
>> +
>> + /* Continue to update the local streams and handle prio ones */
>> continue;
>> }
>>
>> @@ -2260,19 +2246,16 @@ end:
>> consumer_poll_timeout = LTTNG_CONSUMER_POLL_TIMEOUT;
>>
>> /*
>> - * Wake-up the other end by writing a null byte in the pipe
>> - * (non-blocking). Important note: Because writing into the
>> - * pipe is non-blocking (and therefore we allow dropping wakeup
>> - * data, as long as there is wakeup data present in the pipe
>> - * buffer to wake up the other end), the other end should
>> - * perform the following sequence for waiting:
>> - * 1) empty the pipe (reads).
>> - * 2) perform update operation.
>> - * 3) wait on the pipe (poll).
>> + * Notify the data poll thread to poll back again and test the
>> + * consumer_quit state to quit gracefully.
>> */
>> do {
>> - ret = write(ctx->consumer_poll_pipe[1], "", 1);
>> + struct lttng_consumer_stream *null_stream = NULL;
>> +
>> + ret = write(ctx->consumer_poll_pipe[1], &null_stream,
>> + sizeof(null_stream));
>> } while (ret < 0 && errno == EINTR);
>> +
>> rcu_unregister_thread();
>> return NULL;
>> }
>> diff --git a/src/common/consumer.h b/src/common/consumer.h
>> index 4b225e4..8e5891a 100644
>> --- a/src/common/consumer.h
>> +++ b/src/common/consumer.h
>> @@ -362,6 +362,7 @@ struct consumer_relayd_sock_pair *consumer_allocate_relayd_sock_pair(
>> struct consumer_relayd_sock_pair *consumer_find_relayd(int key);
>> int consumer_handle_stream_before_relayd(struct lttng_consumer_stream *stream,
>> size_t data_size);
>> +void consumer_steal_stream_key(int key, struct lttng_ht *ht);
>>
>> extern struct lttng_consumer_local_data *lttng_consumer_create(
>> enum lttng_consumer_type type,
>> diff --git a/src/common/kernel-consumer/kernel-consumer.c b/src/common/kernel-consumer/kernel-consumer.c
>> index 13cbe21..444f5e0 100644
>> --- a/src/common/kernel-consumer/kernel-consumer.c
>> +++ b/src/common/kernel-consumer/kernel-consumer.c
>> @@ -235,10 +235,12 @@ int lttng_kconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
>> consumer_del_stream(new_stream, NULL);
>> }
>> } else {
>> - ret = consumer_add_stream(new_stream);
>> - if (ret) {
>> - ERR("Consumer add stream %d failed. Continuing",
>> - new_stream->key);
>> + do {
>> + ret = write(ctx->consumer_poll_pipe[1], &new_stream,
>> + sizeof(new_stream));
>> + } while (ret < 0 && errno == EINTR);
>> + if (ret < 0) {
>> + PERROR("write data pipe");
>> consumer_del_stream(new_stream, NULL);
>> goto end_nosignal;
>> }
>> @@ -284,20 +286,6 @@ int lttng_kconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
>> goto end_nosignal;
>> }
>>
>> - /*
>> - * Wake-up the other end by writing a null byte in the pipe (non-blocking).
>> - * Important note: Because writing into the pipe is non-blocking (and
>> - * therefore we allow dropping wakeup data, as long as there is wakeup data
>> - * present in the pipe buffer to wake up the other end), the other end
>> - * should perform the following sequence for waiting:
>> - *
>> - * 1) empty the pipe (reads).
>> - * 2) perform update operation.
>> - * 3) wait on the pipe (poll).
>> - */
>> - do {
>> - ret = write(ctx->consumer_poll_pipe[1], "", 1);
>> - } while (ret < 0 && errno == EINTR);
>> end_nosignal:
>> rcu_read_unlock();
>>
>> diff --git a/src/common/ust-consumer/ust-consumer.c b/src/common/ust-consumer/ust-consumer.c
>> index 1170687..4ca4b84 100644
>> --- a/src/common/ust-consumer/ust-consumer.c
>> +++ b/src/common/ust-consumer/ust-consumer.c
>> @@ -224,6 +224,18 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
>> goto end_nosignal;
>> }
>>
>> + /*
>> + * This needs to be done as soon as we can so we don't block the
>> + * application too long.
>> + */
>> + ret = lttng_ustconsumer_add_stream(new_stream);
>> + if (ret) {
>> + consumer_del_stream(new_stream, NULL);
>> + goto end_nosignal;
>> + }
>> + /* Steal stream identifier to avoid having streams with the same key */
>> + consumer_steal_stream_key(new_stream->key, consumer_data.stream_ht);
>> +
>> /* The stream is not metadata. Get relayd reference if exists. */
>> relayd = consumer_find_relayd(msg.u.stream.net_index);
>> if (relayd != NULL) {
>> @@ -265,14 +277,12 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
>> goto end_nosignal;
>> }
>> } else {
>> - ret = consumer_add_stream(new_stream);
>> - if (ret) {
>> - ERR("Consumer add stream %d failed. Continuing",
>> - new_stream->key);
>> - /*
>> - * At this point, if the add_stream fails, it is not in the
>> - * hash table thus passing the NULL value here.
>> - */
>> + do {
>> + ret = write(ctx->consumer_poll_pipe[1], &new_stream,
>> + sizeof(new_stream));
>> + } while (ret < 0 && errno == EINTR);
>> + if (ret < 0) {
>> + PERROR("write data pipe");
>> consumer_del_stream(new_stream, NULL);
>> goto end_nosignal;
>> }
>> @@ -334,20 +344,6 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
>> break;
>> }
>>
>> - /*
>> - * Wake-up the other end by writing a null byte in the pipe (non-blocking).
>> - * Important note: Because writing into the pipe is non-blocking (and
>> - * therefore we allow dropping wakeup data, as long as there is wakeup data
>> - * present in the pipe buffer to wake up the other end), the other end
>> - * should perform the following sequence for waiting:
>> - *
>> - * 1) empty the pipe (reads).
>> - * 2) perform update operation.
>> - * 3) wait on the pipe (poll).
>> - */
>> - do {
>> - ret = write(ctx->consumer_poll_pipe[1], "", 1);
>> - } while (ret < 0 && errno == EINTR);
>> end_nosignal:
>> rcu_read_unlock();
>>
>> --
>> 1.7.10.4
>>
>>
>> _______________________________________________
>> lttng-dev mailing list
>> lttng-dev at lists.lttng.org
>> http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* [lttng-dev] [PATCH lttng-tools 3/4] Make stream hash tables global to the consumer
2012-10-13 15:56 ` Mathieu Desnoyers
@ 2012-10-15 15:47 ` David Goulet
2012-10-15 17:57 ` Mathieu Desnoyers
0 siblings, 1 reply; 22+ messages in thread
From: David Goulet @ 2012-10-15 15:47 UTC (permalink / raw)
Mathieu Desnoyers:
> * David Goulet (dgoulet at efficios.com) wrote:
>> The data stream hash table is now global to the consumer and used in the
>> data thread. The consumer_data stream_ht is no longer used to track the
>> data streams but instead will be used (and possibly renamed) by the
>> session daemon poll thread to keep track of streams on a per session id
>> basis for the upcoming feature that check traced data availability.
>>
>> For now, in order to avoid mind bugging problems to access the streams,
>> both hash table are now defined globally (metadata and data). However,
>> stream update are still done in a single thread. Don't count on this to
>> be guaranteed in the next commits.
>>
>> Signed-off-by: David Goulet <dgoulet at efficios.com>
>> ---
>> src/common/consumer.c | 91 +++++++++++++++++++++++++-------
>> src/common/consumer.h | 9 ++--
>> src/common/ust-consumer/ust-consumer.c | 2 -
>> 3 files changed, 75 insertions(+), 27 deletions(-)
>>
>> diff --git a/src/common/consumer.c b/src/common/consumer.c
>> index 1d2b1f7..1fb9960 100644
>> --- a/src/common/consumer.c
>> +++ b/src/common/consumer.c
>> @@ -59,6 +59,17 @@ int consumer_poll_timeout = -1;
>> volatile int consumer_quit = 0;
>>
>> /*
>> + * The following two hash tables are visible by all threads which are separated
>> + * in different source files.
>> + *
>> + * Global hash table containing respectively metadata and data streams. The
>> + * stream element in this ht should only be updated by the metadata poll thread
>> + * for the metadata and the data poll thread for the data.
>> + */
>> +struct lttng_ht *metadata_ht = NULL;
>> +struct lttng_ht *data_ht = NULL;
>> +
>> +/*
>> * Find a stream. The consumer_data.lock must be locked during this
>> * call.
>> */
>> @@ -433,19 +444,24 @@ end:
>> /*
>> * Add a stream to the global list protected by a mutex.
>> */
>> -int consumer_add_stream(struct lttng_consumer_stream *stream)
>> +static int consumer_add_stream(struct lttng_consumer_stream *stream,
>> + struct lttng_ht *ht)
>> {
>> int ret = 0;
>> struct consumer_relayd_sock_pair *relayd;
>>
>> assert(stream);
>> + assert(ht);
>>
>> DBG3("Adding consumer stream %d", stream->key);
>>
>> pthread_mutex_lock(&consumer_data.lock);
>> rcu_read_lock();
>>
>> - lttng_ht_add_unique_ulong(consumer_data.stream_ht, &stream->node);
>> + /* Steal stream identifier to avoid having streams with the same key */
>> + consumer_steal_stream_key(stream->key, ht);
>
> I don't understand why suddenly this change is needed. Considering what
> this patch should be doing (just moving a ht from per-thread to global),
> it should not have any behavior impact.
We move the steal stream key from the sessiond thread to the add_stream
function call since we do not use the consumer_data hash table anymore
(stream_ht) and uses per thread hashtable (global for now though).
If you look below, you'll see that the steal stream key call is removed
(using the consumer data stream_ht).
This commit makes sure that both consumer_add_stream and
add_metadata_stream steal the stream key if needed.
Thanks
David
>
> Thanks,
>
> Mathieu
>
>> +
>> + lttng_ht_add_unique_ulong(ht, &stream->node);
>>
>> /* Check and cleanup relayd */
>> relayd = consumer_find_relayd(stream->net_seq_idx);
>> @@ -783,9 +799,9 @@ end:
>> *
>> * Returns the number of fds in the structures.
>> */
>> -int consumer_update_poll_array(
>> +static int consumer_update_poll_array(
>> struct lttng_consumer_local_data *ctx, struct pollfd **pollfd,
>> - struct lttng_consumer_stream **local_stream)
>> + struct lttng_consumer_stream **local_stream, struct lttng_ht *ht)
>> {
>> int i = 0;
>> struct lttng_ht_iter iter;
>> @@ -793,8 +809,7 @@ int consumer_update_poll_array(
>>
>> DBG("Updating poll fd array");
>> rcu_read_lock();
>> - cds_lfht_for_each_entry(consumer_data.stream_ht->ht, &iter.iter, stream,
>> - node.node) {
>> + cds_lfht_for_each_entry(ht->ht, &iter.iter, stream, node.node) {
>> if (stream->state != LTTNG_CONSUMER_ACTIVE_STREAM) {
>> continue;
>> }
>> @@ -1523,6 +1538,33 @@ int lttng_consumer_recv_cmd(struct lttng_consumer_local_data *ctx,
>> /*
>> * Iterate over all streams of the hashtable and free them properly.
>> *
>> + * WARNING: *MUST* be used with data stream only.
>> + */
>> +static void destroy_data_stream_ht(struct lttng_ht *ht)
>> +{
>> + int ret;
>> + struct lttng_ht_iter iter;
>> + struct lttng_consumer_stream *stream;
>> +
>> + if (ht == NULL) {
>> + return;
>> + }
>> +
>> + rcu_read_lock();
>> + cds_lfht_for_each_entry(ht->ht, &iter.iter, stream, node.node) {
>> + ret = lttng_ht_del(ht, &iter);
>> + assert(!ret);
>> +
>> + call_rcu(&stream->node.head, consumer_free_stream);
>> + }
>> + rcu_read_unlock();
>> +
>> + lttng_ht_destroy(ht);
>> +}
>> +
>> +/*
>> + * Iterate over all streams of the hashtable and free them properly.
>> + *
>> * XXX: Should not be only for metadata stream or else use an other name.
>> */
>> static void destroy_stream_ht(struct lttng_ht *ht)
>> @@ -1711,6 +1753,9 @@ static int consumer_add_metadata_stream(struct lttng_consumer_stream *stream,
>> uatomic_dec(&stream->chan->nb_init_streams);
>> }
>>
>> + /* Steal stream identifier to avoid having streams with the same key */
>> + consumer_steal_stream_key(stream->key, ht);
>> +
>> lttng_ht_add_unique_ulong(ht, &stream->waitfd_node);
>> rcu_read_unlock();
>>
>> @@ -1729,7 +1774,6 @@ void *consumer_thread_metadata_poll(void *data)
>> struct lttng_consumer_stream *stream = NULL;
>> struct lttng_ht_iter iter;
>> struct lttng_ht_node_ulong *node;
>> - struct lttng_ht *metadata_ht = NULL;
>> struct lttng_poll_event events;
>> struct lttng_consumer_local_data *ctx = data;
>> ssize_t len;
>> @@ -1738,11 +1782,6 @@ void *consumer_thread_metadata_poll(void *data)
>>
>> DBG("Thread metadata poll started");
>>
>> - metadata_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
>> - if (metadata_ht == NULL) {
>> - goto end;
>> - }
>> -
>> /* Size is set to 1 for the consumer_metadata pipe */
>> ret = lttng_poll_create(&events, 2, LTTNG_CLOEXEC);
>> if (ret < 0) {
>> @@ -1918,6 +1957,11 @@ void *consumer_thread_data_poll(void *data)
>>
>> rcu_register_thread();
>>
>> + data_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
>> + if (data_ht == NULL) {
>> + goto end;
>> + }
>> +
>> local_stream = zmalloc(sizeof(struct lttng_consumer_stream));
>>
>> while (1) {
>> @@ -1955,7 +1999,8 @@ void *consumer_thread_data_poll(void *data)
>> pthread_mutex_unlock(&consumer_data.lock);
>> goto end;
>> }
>> - ret = consumer_update_poll_array(ctx, &pollfd, local_stream);
>> + ret = consumer_update_poll_array(ctx, &pollfd, local_stream,
>> + data_ht);
>> if (ret < 0) {
>> ERR("Error in allocating pollfd or local_outfds");
>> lttng_consumer_send_error(ctx, LTTCOMM_CONSUMERD_POLL_ERROR);
>> @@ -2015,7 +2060,7 @@ void *consumer_thread_data_poll(void *data)
>> continue;
>> }
>>
>> - ret = consumer_add_stream(new_stream);
>> + ret = consumer_add_stream(new_stream, data_ht);
>> if (ret) {
>> ERR("Consumer add stream %d failed. Continuing",
>> new_stream->key);
>> @@ -2088,22 +2133,19 @@ void *consumer_thread_data_poll(void *data)
>> if ((pollfd[i].revents & POLLHUP)) {
>> DBG("Polling fd %d tells it has hung up.", pollfd[i].fd);
>> if (!local_stream[i]->data_read) {
>> - consumer_del_stream(local_stream[i],
>> - consumer_data.stream_ht);
>> + consumer_del_stream(local_stream[i], data_ht);
>> num_hup++;
>> }
>> } else if (pollfd[i].revents & POLLERR) {
>> ERR("Error returned in polling fd %d.", pollfd[i].fd);
>> if (!local_stream[i]->data_read) {
>> - consumer_del_stream(local_stream[i],
>> - consumer_data.stream_ht);
>> + consumer_del_stream(local_stream[i], data_ht);
>> num_hup++;
>> }
>> } else if (pollfd[i].revents & POLLNVAL) {
>> ERR("Polling fd %d tells fd is not open.", pollfd[i].fd);
>> if (!local_stream[i]->data_read) {
>> - consumer_del_stream(local_stream[i],
>> - consumer_data.stream_ht);
>> + consumer_del_stream(local_stream[i], data_ht);
>> num_hup++;
>> }
>> }
>> @@ -2131,6 +2173,10 @@ end:
>> */
>> close(ctx->consumer_metadata_pipe[1]);
>>
>> + if (data_ht) {
>> + destroy_data_stream_ht(data_ht);
>> + }
>> +
>> rcu_unregister_thread();
>> return NULL;
>> }
>> @@ -2299,6 +2345,11 @@ void lttng_consumer_init(void)
>> consumer_data.stream_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
>> consumer_data.channel_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
>> consumer_data.relayd_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
>> +
>> + metadata_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
>> + assert(metadata_ht);
>> + data_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
>> + assert(data_ht);
>> }
>>
>> /*
>> diff --git a/src/common/consumer.h b/src/common/consumer.h
>> index 8e5891a..6bce96d 100644
>> --- a/src/common/consumer.h
>> +++ b/src/common/consumer.h
>> @@ -275,6 +275,10 @@ struct lttng_consumer_global_data {
>> struct lttng_ht *relayd_ht;
>> };
>>
>> +/* Defined in consumer.c and coupled with explanations */
>> +extern struct lttng_ht *metadata_ht;
>> +extern struct lttng_ht *data_ht;
>> +
>> /*
>> * Init consumer data structures.
>> */
>> @@ -324,10 +328,6 @@ extern void lttng_consumer_sync_trace_file(
>> */
>> extern int lttng_consumer_poll_socket(struct pollfd *kconsumer_sockpoll);
>>
>> -extern int consumer_update_poll_array(
>> - struct lttng_consumer_local_data *ctx, struct pollfd **pollfd,
>> - struct lttng_consumer_stream **local_consumer_streams);
>> -
>> extern struct lttng_consumer_stream *consumer_allocate_stream(
>> int channel_key, int stream_key,
>> int shm_fd, int wait_fd,
>> @@ -340,7 +340,6 @@ extern struct lttng_consumer_stream *consumer_allocate_stream(
>> int net_index,
>> int metadata_flag,
>> int *alloc_ret);
>> -extern int consumer_add_stream(struct lttng_consumer_stream *stream);
>> extern void consumer_del_stream(struct lttng_consumer_stream *stream,
>> struct lttng_ht *ht);
>> extern void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
>> diff --git a/src/common/ust-consumer/ust-consumer.c b/src/common/ust-consumer/ust-consumer.c
>> index 4ca4b84..3b41e55 100644
>> --- a/src/common/ust-consumer/ust-consumer.c
>> +++ b/src/common/ust-consumer/ust-consumer.c
>> @@ -233,8 +233,6 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
>> consumer_del_stream(new_stream, NULL);
>> goto end_nosignal;
>> }
>> - /* Steal stream identifier to avoid having streams with the same key */
>> - consumer_steal_stream_key(new_stream->key, consumer_data.stream_ht);
>>
>> /* The stream is not metadata. Get relayd reference if exists. */
>> relayd = consumer_find_relayd(msg.u.stream.net_index);
>> --
>> 1.7.10.4
>>
>>
>> _______________________________________________
>> lttng-dev mailing list
>> lttng-dev at lists.lttng.org
>> http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* [lttng-dev] [PATCH lttng-tools 1/4] Rename consumer threads and spawn them in daemon
2012-10-15 15:39 ` David Goulet
@ 2012-10-15 17:28 ` Mathieu Desnoyers
2012-10-15 17:37 ` David Goulet
0 siblings, 1 reply; 22+ messages in thread
From: Mathieu Desnoyers @ 2012-10-15 17:28 UTC (permalink / raw)
* David Goulet (dgoulet at efficios.com) wrote:
>
>
> Mathieu Desnoyers:
> > * David Goulet (dgoulet at efficios.com) wrote:
> >> The metadata thread is now created in the lttng-consumerd daemon so all
> >> thread could be controlled inside the daemon.
> >>
> >> This is the first step of a consumer thread refactoring which aims at
> >> moving data and metadata stream operations inside a dedicated thread so
> >> the session daemon thread does not block and is more efficient at adding
> >> streams.
> >>
> >> The most important concept is that a stream file descriptor MUST be
> >> opened as quickly as we can than passed to the right thread (for UST
> >
> > than -> then
> >
> >> since they are already opened by the session daemon for the kernel).
> >>
> >> Signed-off-by: David Goulet <dgoulet at efficios.com>
> >> ---
> >> src/bin/lttng-consumerd/lttng-consumerd.c | 18 ++++++++++-----
> >> src/common/consumer.c | 34 +++++++++--------------------
> >> src/common/consumer.h | 5 +++--
> >> 3 files changed, 26 insertions(+), 31 deletions(-)
> >>
> >> diff --git a/src/bin/lttng-consumerd/lttng-consumerd.c b/src/bin/lttng-consumerd/lttng-consumerd.c
> >> index 5952334..946fb02 100644
> >> --- a/src/bin/lttng-consumerd/lttng-consumerd.c
> >> +++ b/src/bin/lttng-consumerd/lttng-consumerd.c
> >> @@ -356,23 +356,31 @@ int main(int argc, char **argv)
> >> }
> >> lttng_consumer_set_error_sock(ctx, ret);
> >>
> >> - /* Create the thread to manage the receive of fd */
> >> - ret = pthread_create(&threads[0], NULL, lttng_consumer_thread_receive_fds,
> >> + /* Create thread to manage the polling/writing of trace metadata */
> >> + ret = pthread_create(&threads[0], NULL, consumer_thread_metadata_poll,
> >> + (void *) ctx);
> >> + if (ret != 0) {
> >> + perror("pthread_create");
> >> + goto error;
> >> + }
> >> +
> >> + /* Create thread to manage the polling/writing of trace data */
> >> + ret = pthread_create(&threads[1], NULL, consumer_thread_data_poll,
> >> (void *) ctx);
> >> if (ret != 0) {
> >> perror("pthread_create");
> >> goto error;
> >> }
> >>
> >> - /* Create thread to manage the polling/writing of traces */
> >> - ret = pthread_create(&threads[1], NULL, lttng_consumer_thread_poll_fds,
> >> + /* Create the thread to manage the receive of fd */
> >> + ret = pthread_create(&threads[2], NULL, consumer_thread_sessiond_poll,
> >> (void *) ctx);
> >> if (ret != 0) {
> >> perror("pthread_create");
> >> goto error;
> >> }
> >>
> >> - for (i = 0; i < 2; i++) {
> >> + for (i = 0; i < 3; i++) {
> >> ret = pthread_join(threads[i], &status);
> >> if (ret != 0) {
> >> perror("pthread_join");
> >> diff --git a/src/common/consumer.c b/src/common/consumer.c
> >> index 242b05b..055de1b 100644
> >> --- a/src/common/consumer.c
> >> +++ b/src/common/consumer.c
> >> @@ -1131,6 +1131,8 @@ void lttng_consumer_destroy(struct lttng_consumer_local_data *ctx)
> >> PERROR("close");
> >> }
> >> utils_close_pipe(ctx->consumer_splice_metadata_pipe);
> >> + /* This should trigger the metadata thread to exit */
> >> + close(ctx->consumer_metadata_pipe[1]);
> >
> > this is adding a close, but did not remove any other remove that might
> > previously be in place elsewhere.
>
> So we got two possible error path which is either the poll thread fails
> or the consumer could be destroy by hand even though the threads are
> working well.
>
> Actually, this close should check if the value is valid and close it. To
> be honest, this is just a shortcut since close(-1) does not fail and
> ignoring the close error here since we are in the cleanup path anyway so
> we don't necessarily care about the perror message.
>
> Anyhow, we have to handle both error path. An if plus set -1 after close
> can be done so not to confuse.
if two threads can concurrently perform close on the same fd value, how
can you prove there are no possible races ?
Mathieu
>
> David
>
> >
> > moreover, the close() return value is not tested.
> >>
> >> unlink(ctx->consumer_command_sock_path);
> >> free(ctx);
> >> @@ -1756,7 +1758,7 @@ error:
> >> * Thread polls on metadata file descriptor and write them on disk or on the
> >> * network.
> >> */
> >> -void *lttng_consumer_thread_poll_metadata(void *data)
> >> +void *consumer_thread_metadata_poll(void *data)
> >> {
> >> int ret, i, pollfd;
> >> uint32_t revents, nb_fd;
> >> @@ -1939,7 +1941,7 @@ end:
> >> * This thread polls the fds in the set to consume the data and write
> >> * it to tracefile if necessary.
> >> */
> >> -void *lttng_consumer_thread_poll_fds(void *data)
> >> +void *consumer_thread_data_poll(void *data)
> >> {
> >> int num_rdy, num_hup, high_prio, ret, i;
> >> struct pollfd *pollfd = NULL;
> >> @@ -1949,19 +1951,9 @@ void *lttng_consumer_thread_poll_fds(void *data)
> >> int nb_fd = 0;
> >> struct lttng_consumer_local_data *ctx = data;
> >> ssize_t len;
> >> - pthread_t metadata_thread;
> >> - void *status;
> >>
> >> rcu_register_thread();
> >>
> >> - /* Start metadata polling thread */
> >> - ret = pthread_create(&metadata_thread, NULL,
> >> - lttng_consumer_thread_poll_metadata, (void *) ctx);
> >> - if (ret < 0) {
> >> - PERROR("pthread_create metadata thread");
> >> - goto end;
> >> - }
> >> -
> >> local_stream = zmalloc(sizeof(struct lttng_consumer_stream));
> >>
> >> while (1) {
> >> @@ -2145,19 +2137,13 @@ end:
> >>
> >> /*
> >> * Close the write side of the pipe so epoll_wait() in
> >> - * lttng_consumer_thread_poll_metadata can catch it. The thread is
> >> - * monitoring the read side of the pipe. If we close them both, epoll_wait
> >> - * strangely does not return and could create a endless wait period if the
> >> - * pipe is the only tracked fd in the poll set. The thread will take care
> >> - * of closing the read side.
> >> + * consumer_thread_metadata_poll can catch it. The thread is monitoring the
> >> + * read side of the pipe. If we close them both, epoll_wait strangely does
> >> + * not return and could create a endless wait period if the pipe is the
> >> + * only tracked fd in the poll set. The thread will take care of closing
> >> + * the read side.
> >> */
> >> close(ctx->consumer_metadata_pipe[1]);
> >
> > this is the second close on the same FD I'm talking about.
> >
> > thanks,
> >
> > Mathieu
> >
> >> - if (ret) {
> >> - ret = pthread_join(metadata_thread, &status);
> >> - if (ret < 0) {
> >> - PERROR("pthread_join metadata thread");
> >> - }
> >> - }
> >>
> >> rcu_unregister_thread();
> >> return NULL;
> >> @@ -2167,7 +2153,7 @@ end:
> >> * This thread listens on the consumerd socket and receives the file
> >> * descriptors from the session daemon.
> >> */
> >> -void *lttng_consumer_thread_receive_fds(void *data)
> >> +void *consumer_thread_sessiond_poll(void *data)
> >> {
> >> int sock, client_socket, ret;
> >> /*
> >> diff --git a/src/common/consumer.h b/src/common/consumer.h
> >> index d0cd8fd..4b225e4 100644
> >> --- a/src/common/consumer.h
> >> +++ b/src/common/consumer.h
> >> @@ -385,8 +385,9 @@ extern int lttng_consumer_get_produced_snapshot(
> >> struct lttng_consumer_local_data *ctx,
> >> struct lttng_consumer_stream *stream,
> >> unsigned long *pos);
> >> -extern void *lttng_consumer_thread_poll_fds(void *data);
> >> -extern void *lttng_consumer_thread_receive_fds(void *data);
> >> +extern void *consumer_thread_metadata_poll(void *data);
> >> +extern void *consumer_thread_data_poll(void *data);
> >> +extern void *consumer_thread_sessiond_poll(void *data);
> >> extern int lttng_consumer_recv_cmd(struct lttng_consumer_local_data *ctx,
> >> int sock, struct pollfd *consumer_sockpoll);
> >>
> >> --
> >> 1.7.10.4
> >>
> >>
> >> _______________________________________________
> >> lttng-dev mailing list
> >> lttng-dev at lists.lttng.org
> >> http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
> >
--
Mathieu Desnoyers
Operating System Efficiency R&D Consultant
EfficiOS Inc.
http://www.efficios.com
^ permalink raw reply [flat|nested] 22+ messages in thread
* [lttng-dev] [PATCH lttng-tools 2/4] Move add data stream to the data thread
2012-10-15 15:40 ` David Goulet
@ 2012-10-15 17:31 ` Mathieu Desnoyers
2012-10-15 17:40 ` David Goulet
0 siblings, 1 reply; 22+ messages in thread
From: Mathieu Desnoyers @ 2012-10-15 17:31 UTC (permalink / raw)
* David Goulet (dgoulet at efficios.com) wrote:
>
>
> Mathieu Desnoyers:
> > * David Goulet (dgoulet at efficios.com) wrote:
> >> As a second step of refactoring, upon receiving a data stream, we send
> >> it to the data thread that is now in charge of handling it.
> >>
> >> Furthermore, in order for this to behave correctly, we have to make the
> >> ustctl actions on the stream upon before passing it to the right thread
> >> (the kernel does not need special actions.). This way, once the sessiond
> >> thread reply back to the session daemon, the stream is sure to be open
> >> and ready for data to be recorded on the application side so we avoid a
> >> race between the application thinking the stream is ready and the stream
> >> thread still scheduled out.
> >
> > Normally, as long as we have a reference on the SHM file descriptor, and
> > we have the wakeup FD, we should be good to fetch the data of buffers
> > belonging to an application that has already exited, even if it did so
> > before the ustctl calls are done.
> >
> > So I'm wondering why you do the ustctl calls in the sessiond thread ? It
> > seems to complexify the implementation needlessly: we could still do the
> > ustctl calls and output file open at the same location, the
> > data/metadata threads.
>
> Hmmm, it was my understanding that does
does -> those
> ustctl_* calls were needed
> before the trace could be recording thus making them quickly. Wrong?
Can you rephrase your question ? I don't understand.
Thanks,
Mathieu
>
> David
>
> >
> > Thanks,
> >
> > Mathieu
> >
> >>
> >> This commit should speed up the add stream process for the session
> >> daemon. There is still some actions to move out of the session daemon
> >> poll thread to gain speed significantly, especially for network
> >> streaming.
> >>
> >> Signed-off-by: David Goulet <dgoulet at efficios.com>
> >> ---
> >> src/common/consumer.c | 123 +++++++++++---------------
> >> src/common/consumer.h | 1 +
> >> src/common/kernel-consumer/kernel-consumer.c | 24 ++---
> >> src/common/ust-consumer/ust-consumer.c | 40 ++++-----
> >> 4 files changed, 78 insertions(+), 110 deletions(-)
> >>
> >> diff --git a/src/common/consumer.c b/src/common/consumer.c
> >> index 055de1b..1d2b1f7 100644
> >> --- a/src/common/consumer.c
> >> +++ b/src/common/consumer.c
> >> @@ -89,7 +89,7 @@ static struct lttng_consumer_stream *consumer_find_stream(int key,
> >> return stream;
> >> }
> >>
> >> -static void consumer_steal_stream_key(int key, struct lttng_ht *ht)
> >> +void consumer_steal_stream_key(int key, struct lttng_ht *ht)
> >> {
> >> struct lttng_consumer_stream *stream;
> >>
> >> @@ -409,6 +409,14 @@ struct lttng_consumer_stream *consumer_allocate_stream(
> >> lttng_ht_node_init_ulong(&stream->waitfd_node, stream->wait_fd);
> >> lttng_ht_node_init_ulong(&stream->node, stream->key);
> >>
> >> + /*
> >> + * The cpu number is needed before using any ustctl_* actions. Ignored for
> >> + * the kernel so the value does not matter.
> >> + */
> >> + pthread_mutex_lock(&consumer_data.lock);
> >> + stream->cpu = stream->chan->cpucount++;
> >> + pthread_mutex_unlock(&consumer_data.lock);
> >> +
> >> DBG3("Allocated stream %s (key %d, shm_fd %d, wait_fd %d, mmap_len %llu,"
> >> " out_fd %d, net_seq_idx %d)", stream->path_name, stream->key,
> >> stream->shm_fd, stream->wait_fd,
> >> @@ -437,28 +445,6 @@ int consumer_add_stream(struct lttng_consumer_stream *stream)
> >> pthread_mutex_lock(&consumer_data.lock);
> >> rcu_read_lock();
> >>
> >> - switch (consumer_data.type) {
> >> - case LTTNG_CONSUMER_KERNEL:
> >> - break;
> >> - case LTTNG_CONSUMER32_UST:
> >> - case LTTNG_CONSUMER64_UST:
> >> - stream->cpu = stream->chan->cpucount++;
> >> - ret = lttng_ustconsumer_add_stream(stream);
> >> - if (ret) {
> >> - ret = -EINVAL;
> >> - goto error;
> >> - }
> >> -
> >> - /* Steal stream identifier only for UST */
> >> - consumer_steal_stream_key(stream->key, consumer_data.stream_ht);
> >> - break;
> >> - default:
> >> - ERR("Unknown consumer_data type");
> >> - assert(0);
> >> - ret = -ENOSYS;
> >> - goto error;
> >> - }
> >> -
> >> lttng_ht_add_unique_ulong(consumer_data.stream_ht, &stream->node);
> >>
> >> /* Check and cleanup relayd */
> >> @@ -485,7 +471,6 @@ int consumer_add_stream(struct lttng_consumer_stream *stream)
> >> consumer_data.stream_count++;
> >> consumer_data.need_update = 1;
> >>
> >> -error:
> >> rcu_read_unlock();
> >> pthread_mutex_unlock(&consumer_data.lock);
> >>
> >> @@ -1582,17 +1567,6 @@ void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
> >>
> >> DBG3("Consumer delete metadata stream %d", stream->wait_fd);
> >>
> >> - if (ht == NULL) {
> >> - /* Means the stream was allocated but not successfully added */
> >> - goto free_stream;
> >> - }
> >> -
> >> - rcu_read_lock();
> >> - iter.iter.node = &stream->waitfd_node.node;
> >> - ret = lttng_ht_del(ht, &iter);
> >> - assert(!ret);
> >> - rcu_read_unlock();
> >> -
> >> pthread_mutex_lock(&consumer_data.lock);
> >> switch (consumer_data.type) {
> >> case LTTNG_CONSUMER_KERNEL:
> >> @@ -1613,6 +1587,18 @@ void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
> >> goto end;
> >> }
> >>
> >> + if (ht == NULL) {
> >> + pthread_mutex_unlock(&consumer_data.lock);
> >> + /* Means the stream was allocated but not successfully added */
> >> + goto free_stream;
> >> + }
> >> +
> >> + rcu_read_lock();
> >> + iter.iter.node = &stream->waitfd_node.node;
> >> + ret = lttng_ht_del(ht, &iter);
> >> + assert(!ret);
> >> + rcu_read_unlock();
> >> +
> >> if (stream->out_fd >= 0) {
> >> ret = close(stream->out_fd);
> >> if (ret) {
> >> @@ -1699,27 +1685,6 @@ static int consumer_add_metadata_stream(struct lttng_consumer_stream *stream,
> >>
> >> pthread_mutex_lock(&consumer_data.lock);
> >>
> >> - switch (consumer_data.type) {
> >> - case LTTNG_CONSUMER_KERNEL:
> >> - break;
> >> - case LTTNG_CONSUMER32_UST:
> >> - case LTTNG_CONSUMER64_UST:
> >> - ret = lttng_ustconsumer_add_stream(stream);
> >> - if (ret) {
> >> - ret = -EINVAL;
> >> - goto error;
> >> - }
> >> -
> >> - /* Steal stream identifier only for UST */
> >> - consumer_steal_stream_key(stream->wait_fd, ht);
> >> - break;
> >> - default:
> >> - ERR("Unknown consumer_data type");
> >> - assert(0);
> >> - ret = -ENOSYS;
> >> - goto error;
> >> - }
> >> -
> >> /*
> >> * From here, refcounts are updated so be _careful_ when returning an error
> >> * after this point.
> >> @@ -1749,7 +1714,6 @@ static int consumer_add_metadata_stream(struct lttng_consumer_stream *stream,
> >> lttng_ht_add_unique_ulong(ht, &stream->waitfd_node);
> >> rcu_read_unlock();
> >>
> >> -error:
> >> pthread_mutex_unlock(&consumer_data.lock);
> >> return ret;
> >> }
> >> @@ -1946,7 +1910,7 @@ void *consumer_thread_data_poll(void *data)
> >> int num_rdy, num_hup, high_prio, ret, i;
> >> struct pollfd *pollfd = NULL;
> >> /* local view of the streams */
> >> - struct lttng_consumer_stream **local_stream = NULL;
> >> + struct lttng_consumer_stream **local_stream = NULL, *new_stream = NULL;
> >> /* local view of consumer_data.fds_count */
> >> int nb_fd = 0;
> >> struct lttng_consumer_local_data *ctx = data;
> >> @@ -2034,13 +1998,35 @@ void *consumer_thread_data_poll(void *data)
> >> */
> >> if (pollfd[nb_fd].revents & (POLLIN | POLLPRI)) {
> >> size_t pipe_readlen;
> >> - char tmp;
> >>
> >> DBG("consumer_poll_pipe wake up");
> >> /* Consume 1 byte of pipe data */
> >> do {
> >> - pipe_readlen = read(ctx->consumer_poll_pipe[0], &tmp, 1);
> >> + pipe_readlen = read(ctx->consumer_poll_pipe[0], &new_stream,
> >> + sizeof(new_stream));
> >> } while (pipe_readlen == -1 && errno == EINTR);
> >> +
> >> + /*
> >> + * If the stream is NULL, just ignore it. It's also possible that
> >> + * the sessiond poll thread changed the consumer_quit state and is
> >> + * waking us up to test it.
> >> + */
> >> + if (new_stream == NULL) {
> >> + continue;
> >> + }
> >> +
> >> + ret = consumer_add_stream(new_stream);
> >> + if (ret) {
> >> + ERR("Consumer add stream %d failed. Continuing",
> >> + new_stream->key);
> >> + /*
> >> + * At this point, if the add_stream fails, it is not in the
> >> + * hash table thus passing the NULL value here.
> >> + */
> >> + consumer_del_stream(new_stream, NULL);
> >> + }
> >> +
> >> + /* Continue to update the local streams and handle prio ones */
> >> continue;
> >> }
> >>
> >> @@ -2260,19 +2246,16 @@ end:
> >> consumer_poll_timeout = LTTNG_CONSUMER_POLL_TIMEOUT;
> >>
> >> /*
> >> - * Wake-up the other end by writing a null byte in the pipe
> >> - * (non-blocking). Important note: Because writing into the
> >> - * pipe is non-blocking (and therefore we allow dropping wakeup
> >> - * data, as long as there is wakeup data present in the pipe
> >> - * buffer to wake up the other end), the other end should
> >> - * perform the following sequence for waiting:
> >> - * 1) empty the pipe (reads).
> >> - * 2) perform update operation.
> >> - * 3) wait on the pipe (poll).
> >> + * Notify the data poll thread to poll back again and test the
> >> + * consumer_quit state to quit gracefully.
> >> */
> >> do {
> >> - ret = write(ctx->consumer_poll_pipe[1], "", 1);
> >> + struct lttng_consumer_stream *null_stream = NULL;
> >> +
> >> + ret = write(ctx->consumer_poll_pipe[1], &null_stream,
> >> + sizeof(null_stream));
> >> } while (ret < 0 && errno == EINTR);
> >> +
> >> rcu_unregister_thread();
> >> return NULL;
> >> }
> >> diff --git a/src/common/consumer.h b/src/common/consumer.h
> >> index 4b225e4..8e5891a 100644
> >> --- a/src/common/consumer.h
> >> +++ b/src/common/consumer.h
> >> @@ -362,6 +362,7 @@ struct consumer_relayd_sock_pair *consumer_allocate_relayd_sock_pair(
> >> struct consumer_relayd_sock_pair *consumer_find_relayd(int key);
> >> int consumer_handle_stream_before_relayd(struct lttng_consumer_stream *stream,
> >> size_t data_size);
> >> +void consumer_steal_stream_key(int key, struct lttng_ht *ht);
> >>
> >> extern struct lttng_consumer_local_data *lttng_consumer_create(
> >> enum lttng_consumer_type type,
> >> diff --git a/src/common/kernel-consumer/kernel-consumer.c b/src/common/kernel-consumer/kernel-consumer.c
> >> index 13cbe21..444f5e0 100644
> >> --- a/src/common/kernel-consumer/kernel-consumer.c
> >> +++ b/src/common/kernel-consumer/kernel-consumer.c
> >> @@ -235,10 +235,12 @@ int lttng_kconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
> >> consumer_del_stream(new_stream, NULL);
> >> }
> >> } else {
> >> - ret = consumer_add_stream(new_stream);
> >> - if (ret) {
> >> - ERR("Consumer add stream %d failed. Continuing",
> >> - new_stream->key);
> >> + do {
> >> + ret = write(ctx->consumer_poll_pipe[1], &new_stream,
> >> + sizeof(new_stream));
> >> + } while (ret < 0 && errno == EINTR);
> >> + if (ret < 0) {
> >> + PERROR("write data pipe");
> >> consumer_del_stream(new_stream, NULL);
> >> goto end_nosignal;
> >> }
> >> @@ -284,20 +286,6 @@ int lttng_kconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
> >> goto end_nosignal;
> >> }
> >>
> >> - /*
> >> - * Wake-up the other end by writing a null byte in the pipe (non-blocking).
> >> - * Important note: Because writing into the pipe is non-blocking (and
> >> - * therefore we allow dropping wakeup data, as long as there is wakeup data
> >> - * present in the pipe buffer to wake up the other end), the other end
> >> - * should perform the following sequence for waiting:
> >> - *
> >> - * 1) empty the pipe (reads).
> >> - * 2) perform update operation.
> >> - * 3) wait on the pipe (poll).
> >> - */
> >> - do {
> >> - ret = write(ctx->consumer_poll_pipe[1], "", 1);
> >> - } while (ret < 0 && errno == EINTR);
> >> end_nosignal:
> >> rcu_read_unlock();
> >>
> >> diff --git a/src/common/ust-consumer/ust-consumer.c b/src/common/ust-consumer/ust-consumer.c
> >> index 1170687..4ca4b84 100644
> >> --- a/src/common/ust-consumer/ust-consumer.c
> >> +++ b/src/common/ust-consumer/ust-consumer.c
> >> @@ -224,6 +224,18 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
> >> goto end_nosignal;
> >> }
> >>
> >> + /*
> >> + * This needs to be done as soon as we can so we don't block the
> >> + * application too long.
> >> + */
> >> + ret = lttng_ustconsumer_add_stream(new_stream);
> >> + if (ret) {
> >> + consumer_del_stream(new_stream, NULL);
> >> + goto end_nosignal;
> >> + }
> >> + /* Steal stream identifier to avoid having streams with the same key */
> >> + consumer_steal_stream_key(new_stream->key, consumer_data.stream_ht);
> >> +
> >> /* The stream is not metadata. Get relayd reference if exists. */
> >> relayd = consumer_find_relayd(msg.u.stream.net_index);
> >> if (relayd != NULL) {
> >> @@ -265,14 +277,12 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
> >> goto end_nosignal;
> >> }
> >> } else {
> >> - ret = consumer_add_stream(new_stream);
> >> - if (ret) {
> >> - ERR("Consumer add stream %d failed. Continuing",
> >> - new_stream->key);
> >> - /*
> >> - * At this point, if the add_stream fails, it is not in the
> >> - * hash table thus passing the NULL value here.
> >> - */
> >> + do {
> >> + ret = write(ctx->consumer_poll_pipe[1], &new_stream,
> >> + sizeof(new_stream));
> >> + } while (ret < 0 && errno == EINTR);
> >> + if (ret < 0) {
> >> + PERROR("write data pipe");
> >> consumer_del_stream(new_stream, NULL);
> >> goto end_nosignal;
> >> }
> >> @@ -334,20 +344,6 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
> >> break;
> >> }
> >>
> >> - /*
> >> - * Wake-up the other end by writing a null byte in the pipe (non-blocking).
> >> - * Important note: Because writing into the pipe is non-blocking (and
> >> - * therefore we allow dropping wakeup data, as long as there is wakeup data
> >> - * present in the pipe buffer to wake up the other end), the other end
> >> - * should perform the following sequence for waiting:
> >> - *
> >> - * 1) empty the pipe (reads).
> >> - * 2) perform update operation.
> >> - * 3) wait on the pipe (poll).
> >> - */
> >> - do {
> >> - ret = write(ctx->consumer_poll_pipe[1], "", 1);
> >> - } while (ret < 0 && errno == EINTR);
> >> end_nosignal:
> >> rcu_read_unlock();
> >>
> >> --
> >> 1.7.10.4
> >>
> >>
> >> _______________________________________________
> >> lttng-dev mailing list
> >> lttng-dev at lists.lttng.org
> >> http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
> >
--
Mathieu Desnoyers
Operating System Efficiency R&D Consultant
EfficiOS Inc.
http://www.efficios.com
^ permalink raw reply [flat|nested] 22+ messages in thread
* [lttng-dev] [PATCH lttng-tools 1/4] Rename consumer threads and spawn them in daemon
2012-10-15 17:28 ` Mathieu Desnoyers
@ 2012-10-15 17:37 ` David Goulet
2012-10-15 17:39 ` Mathieu Desnoyers
0 siblings, 1 reply; 22+ messages in thread
From: David Goulet @ 2012-10-15 17:37 UTC (permalink / raw)
Mathieu Desnoyers:
>>>> diff --git a/src/common/consumer.c b/src/common/consumer.c
>>>> index 242b05b..055de1b 100644
>>>> --- a/src/common/consumer.c
>>>> +++ b/src/common/consumer.c
>>>> @@ -1131,6 +1131,8 @@ void lttng_consumer_destroy(struct lttng_consumer_local_data *ctx)
>>>> PERROR("close");
>>>> }
>>>> utils_close_pipe(ctx->consumer_splice_metadata_pipe);
>>>> + /* This should trigger the metadata thread to exit */
>>>> + close(ctx->consumer_metadata_pipe[1]);
>>>
>>> this is adding a close, but did not remove any other remove that might
>>> previously be in place elsewhere.
>>
>> So we got two possible error path which is either the poll thread fails
>> or the consumer could be destroy by hand even though the threads are
>> working well.
>>
>> Actually, this close should check if the value is valid and close it. To
>> be honest, this is just a shortcut since close(-1) does not fail and
>> ignoring the close error here since we are in the cleanup path anyway so
>> we don't necessarily care about the perror message.
>>
>> Anyhow, we have to handle both error path. An if plus set -1 after close
>> can be done so not to confuse.
>
> if two threads can concurrently perform close on the same fd value, how
> can you prove there are no possible races ?
Nothing to prove, the race is possible. The point I was trying to
explain is that it does not matter actually since we are in a cleanup
code path.
Anyway, let's remove it since the data thread, when dying, will close
the metadata pipe anyway.
This will avoid more discussion for this small detail :).
David
>
> Mathieu
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* [lttng-dev] [PATCH lttng-tools 1/4] Rename consumer threads and spawn them in daemon
2012-10-15 17:37 ` David Goulet
@ 2012-10-15 17:39 ` Mathieu Desnoyers
2012-10-15 17:42 ` David Goulet
0 siblings, 1 reply; 22+ messages in thread
From: Mathieu Desnoyers @ 2012-10-15 17:39 UTC (permalink / raw)
* David Goulet (dgoulet at efficios.com) wrote:
>
>
> Mathieu Desnoyers:
> >>>> diff --git a/src/common/consumer.c b/src/common/consumer.c
> >>>> index 242b05b..055de1b 100644
> >>>> --- a/src/common/consumer.c
> >>>> +++ b/src/common/consumer.c
> >>>> @@ -1131,6 +1131,8 @@ void lttng_consumer_destroy(struct lttng_consumer_local_data *ctx)
> >>>> PERROR("close");
> >>>> }
> >>>> utils_close_pipe(ctx->consumer_splice_metadata_pipe);
> >>>> + /* This should trigger the metadata thread to exit */
> >>>> + close(ctx->consumer_metadata_pipe[1]);
> >>>
> >>> this is adding a close, but did not remove any other remove that might
> >>> previously be in place elsewhere.
> >>
> >> So we got two possible error path which is either the poll thread fails
> >> or the consumer could be destroy by hand even though the threads are
> >> working well.
> >>
> >> Actually, this close should check if the value is valid and close it. To
> >> be honest, this is just a shortcut since close(-1) does not fail and
> >> ignoring the close error here since we are in the cleanup path anyway so
> >> we don't necessarily care about the perror message.
> >>
> >> Anyhow, we have to handle both error path. An if plus set -1 after close
> >> can be done so not to confuse.
> >
> > if two threads can concurrently perform close on the same fd value, how
> > can you prove there are no possible races ?
>
> Nothing to prove, the race is possible. The point I was trying to
> explain is that it does not matter actually since we are in a cleanup
> code path.
what happens if we close FD 0, 1, 2 or another FD, due to this race ?
what happens if our code evolve to restart threads after errors, and we
leave this race in place, so it becomes hard to reproduce that in some
occasions we are closing random file descriptors ?
> Anyway, let's remove it since the data thread, when dying, will close
> the metadata pipe anyway.
my point exactly :)
>
> This will avoid more discussion for this small detail :).
The devil is in the details, as someone famous said before me.
Thanks,
Mathieu
>
> David
>
> >
> > Mathieu
> >
--
Mathieu Desnoyers
Operating System Efficiency R&D Consultant
EfficiOS Inc.
http://www.efficios.com
^ permalink raw reply [flat|nested] 22+ messages in thread
* [lttng-dev] [PATCH lttng-tools 2/4] Move add data stream to the data thread
2012-10-15 17:31 ` Mathieu Desnoyers
@ 2012-10-15 17:40 ` David Goulet
2012-10-15 17:42 ` Mathieu Desnoyers
0 siblings, 1 reply; 22+ messages in thread
From: David Goulet @ 2012-10-15 17:40 UTC (permalink / raw)
Mathieu Desnoyers:
> * David Goulet (dgoulet at efficios.com) wrote:
>>
>>
>> Mathieu Desnoyers:
>>> * David Goulet (dgoulet at efficios.com) wrote:
>>>> As a second step of refactoring, upon receiving a data stream, we send
>>>> it to the data thread that is now in charge of handling it.
>>>>
>>>> Furthermore, in order for this to behave correctly, we have to make the
>>>> ustctl actions on the stream upon before passing it to the right thread
>>>> (the kernel does not need special actions.). This way, once the sessiond
>>>> thread reply back to the session daemon, the stream is sure to be open
>>>> and ready for data to be recorded on the application side so we avoid a
>>>> race between the application thinking the stream is ready and the stream
>>>> thread still scheduled out.
>>>
>>> Normally, as long as we have a reference on the SHM file descriptor, and
>>> we have the wakeup FD, we should be good to fetch the data of buffers
>>> belonging to an application that has already exited, even if it did so
>>> before the ustctl calls are done.
>>>
>>> So I'm wondering why you do the ustctl calls in the sessiond thread ? It
>>> seems to complexify the implementation needlessly: we could still do the
>>> ustctl calls and output file open at the same location, the
>>> data/metadata threads.
>>
>> Hmmm, it was my understanding that does
>
> does -> those
>
>> ustctl_* calls were needed
>> before the trace could be recording thus making them quickly. Wrong?
>
> Can you rephrase your question ? I don't understand.
>
My understanding was that _those_ ustctl calls need to be done before
the tracer could start recording data. This is why they were moved to
the session daemon thread.
Am I wrong here? When receiving an UST stream< on the consumer side, is
the SHM reference already acquired?
David
> Thanks,
>
> Mathieu
>
>>
>> David
>>
>>>
>>> Thanks,
>>>
>>> Mathieu
>>>
>>>>
>>>> This commit should speed up the add stream process for the session
>>>> daemon. There is still some actions to move out of the session daemon
>>>> poll thread to gain speed significantly, especially for network
>>>> streaming.
>>>>
>>>> Signed-off-by: David Goulet <dgoulet at efficios.com>
>>>> ---
>>>> src/common/consumer.c | 123 +++++++++++---------------
>>>> src/common/consumer.h | 1 +
>>>> src/common/kernel-consumer/kernel-consumer.c | 24 ++---
>>>> src/common/ust-consumer/ust-consumer.c | 40 ++++-----
>>>> 4 files changed, 78 insertions(+), 110 deletions(-)
>>>>
>>>> diff --git a/src/common/consumer.c b/src/common/consumer.c
>>>> index 055de1b..1d2b1f7 100644
>>>> --- a/src/common/consumer.c
>>>> +++ b/src/common/consumer.c
>>>> @@ -89,7 +89,7 @@ static struct lttng_consumer_stream *consumer_find_stream(int key,
>>>> return stream;
>>>> }
>>>>
>>>> -static void consumer_steal_stream_key(int key, struct lttng_ht *ht)
>>>> +void consumer_steal_stream_key(int key, struct lttng_ht *ht)
>>>> {
>>>> struct lttng_consumer_stream *stream;
>>>>
>>>> @@ -409,6 +409,14 @@ struct lttng_consumer_stream *consumer_allocate_stream(
>>>> lttng_ht_node_init_ulong(&stream->waitfd_node, stream->wait_fd);
>>>> lttng_ht_node_init_ulong(&stream->node, stream->key);
>>>>
>>>> + /*
>>>> + * The cpu number is needed before using any ustctl_* actions. Ignored for
>>>> + * the kernel so the value does not matter.
>>>> + */
>>>> + pthread_mutex_lock(&consumer_data.lock);
>>>> + stream->cpu = stream->chan->cpucount++;
>>>> + pthread_mutex_unlock(&consumer_data.lock);
>>>> +
>>>> DBG3("Allocated stream %s (key %d, shm_fd %d, wait_fd %d, mmap_len %llu,"
>>>> " out_fd %d, net_seq_idx %d)", stream->path_name, stream->key,
>>>> stream->shm_fd, stream->wait_fd,
>>>> @@ -437,28 +445,6 @@ int consumer_add_stream(struct lttng_consumer_stream *stream)
>>>> pthread_mutex_lock(&consumer_data.lock);
>>>> rcu_read_lock();
>>>>
>>>> - switch (consumer_data.type) {
>>>> - case LTTNG_CONSUMER_KERNEL:
>>>> - break;
>>>> - case LTTNG_CONSUMER32_UST:
>>>> - case LTTNG_CONSUMER64_UST:
>>>> - stream->cpu = stream->chan->cpucount++;
>>>> - ret = lttng_ustconsumer_add_stream(stream);
>>>> - if (ret) {
>>>> - ret = -EINVAL;
>>>> - goto error;
>>>> - }
>>>> -
>>>> - /* Steal stream identifier only for UST */
>>>> - consumer_steal_stream_key(stream->key, consumer_data.stream_ht);
>>>> - break;
>>>> - default:
>>>> - ERR("Unknown consumer_data type");
>>>> - assert(0);
>>>> - ret = -ENOSYS;
>>>> - goto error;
>>>> - }
>>>> -
>>>> lttng_ht_add_unique_ulong(consumer_data.stream_ht, &stream->node);
>>>>
>>>> /* Check and cleanup relayd */
>>>> @@ -485,7 +471,6 @@ int consumer_add_stream(struct lttng_consumer_stream *stream)
>>>> consumer_data.stream_count++;
>>>> consumer_data.need_update = 1;
>>>>
>>>> -error:
>>>> rcu_read_unlock();
>>>> pthread_mutex_unlock(&consumer_data.lock);
>>>>
>>>> @@ -1582,17 +1567,6 @@ void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
>>>>
>>>> DBG3("Consumer delete metadata stream %d", stream->wait_fd);
>>>>
>>>> - if (ht == NULL) {
>>>> - /* Means the stream was allocated but not successfully added */
>>>> - goto free_stream;
>>>> - }
>>>> -
>>>> - rcu_read_lock();
>>>> - iter.iter.node = &stream->waitfd_node.node;
>>>> - ret = lttng_ht_del(ht, &iter);
>>>> - assert(!ret);
>>>> - rcu_read_unlock();
>>>> -
>>>> pthread_mutex_lock(&consumer_data.lock);
>>>> switch (consumer_data.type) {
>>>> case LTTNG_CONSUMER_KERNEL:
>>>> @@ -1613,6 +1587,18 @@ void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
>>>> goto end;
>>>> }
>>>>
>>>> + if (ht == NULL) {
>>>> + pthread_mutex_unlock(&consumer_data.lock);
>>>> + /* Means the stream was allocated but not successfully added */
>>>> + goto free_stream;
>>>> + }
>>>> +
>>>> + rcu_read_lock();
>>>> + iter.iter.node = &stream->waitfd_node.node;
>>>> + ret = lttng_ht_del(ht, &iter);
>>>> + assert(!ret);
>>>> + rcu_read_unlock();
>>>> +
>>>> if (stream->out_fd >= 0) {
>>>> ret = close(stream->out_fd);
>>>> if (ret) {
>>>> @@ -1699,27 +1685,6 @@ static int consumer_add_metadata_stream(struct lttng_consumer_stream *stream,
>>>>
>>>> pthread_mutex_lock(&consumer_data.lock);
>>>>
>>>> - switch (consumer_data.type) {
>>>> - case LTTNG_CONSUMER_KERNEL:
>>>> - break;
>>>> - case LTTNG_CONSUMER32_UST:
>>>> - case LTTNG_CONSUMER64_UST:
>>>> - ret = lttng_ustconsumer_add_stream(stream);
>>>> - if (ret) {
>>>> - ret = -EINVAL;
>>>> - goto error;
>>>> - }
>>>> -
>>>> - /* Steal stream identifier only for UST */
>>>> - consumer_steal_stream_key(stream->wait_fd, ht);
>>>> - break;
>>>> - default:
>>>> - ERR("Unknown consumer_data type");
>>>> - assert(0);
>>>> - ret = -ENOSYS;
>>>> - goto error;
>>>> - }
>>>> -
>>>> /*
>>>> * From here, refcounts are updated so be _careful_ when returning an error
>>>> * after this point.
>>>> @@ -1749,7 +1714,6 @@ static int consumer_add_metadata_stream(struct lttng_consumer_stream *stream,
>>>> lttng_ht_add_unique_ulong(ht, &stream->waitfd_node);
>>>> rcu_read_unlock();
>>>>
>>>> -error:
>>>> pthread_mutex_unlock(&consumer_data.lock);
>>>> return ret;
>>>> }
>>>> @@ -1946,7 +1910,7 @@ void *consumer_thread_data_poll(void *data)
>>>> int num_rdy, num_hup, high_prio, ret, i;
>>>> struct pollfd *pollfd = NULL;
>>>> /* local view of the streams */
>>>> - struct lttng_consumer_stream **local_stream = NULL;
>>>> + struct lttng_consumer_stream **local_stream = NULL, *new_stream = NULL;
>>>> /* local view of consumer_data.fds_count */
>>>> int nb_fd = 0;
>>>> struct lttng_consumer_local_data *ctx = data;
>>>> @@ -2034,13 +1998,35 @@ void *consumer_thread_data_poll(void *data)
>>>> */
>>>> if (pollfd[nb_fd].revents & (POLLIN | POLLPRI)) {
>>>> size_t pipe_readlen;
>>>> - char tmp;
>>>>
>>>> DBG("consumer_poll_pipe wake up");
>>>> /* Consume 1 byte of pipe data */
>>>> do {
>>>> - pipe_readlen = read(ctx->consumer_poll_pipe[0], &tmp, 1);
>>>> + pipe_readlen = read(ctx->consumer_poll_pipe[0], &new_stream,
>>>> + sizeof(new_stream));
>>>> } while (pipe_readlen == -1 && errno == EINTR);
>>>> +
>>>> + /*
>>>> + * If the stream is NULL, just ignore it. It's also possible that
>>>> + * the sessiond poll thread changed the consumer_quit state and is
>>>> + * waking us up to test it.
>>>> + */
>>>> + if (new_stream == NULL) {
>>>> + continue;
>>>> + }
>>>> +
>>>> + ret = consumer_add_stream(new_stream);
>>>> + if (ret) {
>>>> + ERR("Consumer add stream %d failed. Continuing",
>>>> + new_stream->key);
>>>> + /*
>>>> + * At this point, if the add_stream fails, it is not in the
>>>> + * hash table thus passing the NULL value here.
>>>> + */
>>>> + consumer_del_stream(new_stream, NULL);
>>>> + }
>>>> +
>>>> + /* Continue to update the local streams and handle prio ones */
>>>> continue;
>>>> }
>>>>
>>>> @@ -2260,19 +2246,16 @@ end:
>>>> consumer_poll_timeout = LTTNG_CONSUMER_POLL_TIMEOUT;
>>>>
>>>> /*
>>>> - * Wake-up the other end by writing a null byte in the pipe
>>>> - * (non-blocking). Important note: Because writing into the
>>>> - * pipe is non-blocking (and therefore we allow dropping wakeup
>>>> - * data, as long as there is wakeup data present in the pipe
>>>> - * buffer to wake up the other end), the other end should
>>>> - * perform the following sequence for waiting:
>>>> - * 1) empty the pipe (reads).
>>>> - * 2) perform update operation.
>>>> - * 3) wait on the pipe (poll).
>>>> + * Notify the data poll thread to poll back again and test the
>>>> + * consumer_quit state to quit gracefully.
>>>> */
>>>> do {
>>>> - ret = write(ctx->consumer_poll_pipe[1], "", 1);
>>>> + struct lttng_consumer_stream *null_stream = NULL;
>>>> +
>>>> + ret = write(ctx->consumer_poll_pipe[1], &null_stream,
>>>> + sizeof(null_stream));
>>>> } while (ret < 0 && errno == EINTR);
>>>> +
>>>> rcu_unregister_thread();
>>>> return NULL;
>>>> }
>>>> diff --git a/src/common/consumer.h b/src/common/consumer.h
>>>> index 4b225e4..8e5891a 100644
>>>> --- a/src/common/consumer.h
>>>> +++ b/src/common/consumer.h
>>>> @@ -362,6 +362,7 @@ struct consumer_relayd_sock_pair *consumer_allocate_relayd_sock_pair(
>>>> struct consumer_relayd_sock_pair *consumer_find_relayd(int key);
>>>> int consumer_handle_stream_before_relayd(struct lttng_consumer_stream *stream,
>>>> size_t data_size);
>>>> +void consumer_steal_stream_key(int key, struct lttng_ht *ht);
>>>>
>>>> extern struct lttng_consumer_local_data *lttng_consumer_create(
>>>> enum lttng_consumer_type type,
>>>> diff --git a/src/common/kernel-consumer/kernel-consumer.c b/src/common/kernel-consumer/kernel-consumer.c
>>>> index 13cbe21..444f5e0 100644
>>>> --- a/src/common/kernel-consumer/kernel-consumer.c
>>>> +++ b/src/common/kernel-consumer/kernel-consumer.c
>>>> @@ -235,10 +235,12 @@ int lttng_kconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
>>>> consumer_del_stream(new_stream, NULL);
>>>> }
>>>> } else {
>>>> - ret = consumer_add_stream(new_stream);
>>>> - if (ret) {
>>>> - ERR("Consumer add stream %d failed. Continuing",
>>>> - new_stream->key);
>>>> + do {
>>>> + ret = write(ctx->consumer_poll_pipe[1], &new_stream,
>>>> + sizeof(new_stream));
>>>> + } while (ret < 0 && errno == EINTR);
>>>> + if (ret < 0) {
>>>> + PERROR("write data pipe");
>>>> consumer_del_stream(new_stream, NULL);
>>>> goto end_nosignal;
>>>> }
>>>> @@ -284,20 +286,6 @@ int lttng_kconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
>>>> goto end_nosignal;
>>>> }
>>>>
>>>> - /*
>>>> - * Wake-up the other end by writing a null byte in the pipe (non-blocking).
>>>> - * Important note: Because writing into the pipe is non-blocking (and
>>>> - * therefore we allow dropping wakeup data, as long as there is wakeup data
>>>> - * present in the pipe buffer to wake up the other end), the other end
>>>> - * should perform the following sequence for waiting:
>>>> - *
>>>> - * 1) empty the pipe (reads).
>>>> - * 2) perform update operation.
>>>> - * 3) wait on the pipe (poll).
>>>> - */
>>>> - do {
>>>> - ret = write(ctx->consumer_poll_pipe[1], "", 1);
>>>> - } while (ret < 0 && errno == EINTR);
>>>> end_nosignal:
>>>> rcu_read_unlock();
>>>>
>>>> diff --git a/src/common/ust-consumer/ust-consumer.c b/src/common/ust-consumer/ust-consumer.c
>>>> index 1170687..4ca4b84 100644
>>>> --- a/src/common/ust-consumer/ust-consumer.c
>>>> +++ b/src/common/ust-consumer/ust-consumer.c
>>>> @@ -224,6 +224,18 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
>>>> goto end_nosignal;
>>>> }
>>>>
>>>> + /*
>>>> + * This needs to be done as soon as we can so we don't block the
>>>> + * application too long.
>>>> + */
>>>> + ret = lttng_ustconsumer_add_stream(new_stream);
>>>> + if (ret) {
>>>> + consumer_del_stream(new_stream, NULL);
>>>> + goto end_nosignal;
>>>> + }
>>>> + /* Steal stream identifier to avoid having streams with the same key */
>>>> + consumer_steal_stream_key(new_stream->key, consumer_data.stream_ht);
>>>> +
>>>> /* The stream is not metadata. Get relayd reference if exists. */
>>>> relayd = consumer_find_relayd(msg.u.stream.net_index);
>>>> if (relayd != NULL) {
>>>> @@ -265,14 +277,12 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
>>>> goto end_nosignal;
>>>> }
>>>> } else {
>>>> - ret = consumer_add_stream(new_stream);
>>>> - if (ret) {
>>>> - ERR("Consumer add stream %d failed. Continuing",
>>>> - new_stream->key);
>>>> - /*
>>>> - * At this point, if the add_stream fails, it is not in the
>>>> - * hash table thus passing the NULL value here.
>>>> - */
>>>> + do {
>>>> + ret = write(ctx->consumer_poll_pipe[1], &new_stream,
>>>> + sizeof(new_stream));
>>>> + } while (ret < 0 && errno == EINTR);
>>>> + if (ret < 0) {
>>>> + PERROR("write data pipe");
>>>> consumer_del_stream(new_stream, NULL);
>>>> goto end_nosignal;
>>>> }
>>>> @@ -334,20 +344,6 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
>>>> break;
>>>> }
>>>>
>>>> - /*
>>>> - * Wake-up the other end by writing a null byte in the pipe (non-blocking).
>>>> - * Important note: Because writing into the pipe is non-blocking (and
>>>> - * therefore we allow dropping wakeup data, as long as there is wakeup data
>>>> - * present in the pipe buffer to wake up the other end), the other end
>>>> - * should perform the following sequence for waiting:
>>>> - *
>>>> - * 1) empty the pipe (reads).
>>>> - * 2) perform update operation.
>>>> - * 3) wait on the pipe (poll).
>>>> - */
>>>> - do {
>>>> - ret = write(ctx->consumer_poll_pipe[1], "", 1);
>>>> - } while (ret < 0 && errno == EINTR);
>>>> end_nosignal:
>>>> rcu_read_unlock();
>>>>
>>>> --
>>>> 1.7.10.4
>>>>
>>>>
>>>> _______________________________________________
>>>> lttng-dev mailing list
>>>> lttng-dev at lists.lttng.org
>>>> http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
>>>
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* [lttng-dev] [PATCH lttng-tools 2/4] Move add data stream to the data thread
2012-10-15 17:40 ` David Goulet
@ 2012-10-15 17:42 ` Mathieu Desnoyers
2012-10-15 17:45 ` David Goulet
0 siblings, 1 reply; 22+ messages in thread
From: Mathieu Desnoyers @ 2012-10-15 17:42 UTC (permalink / raw)
* David Goulet (dgoulet at efficios.com) wrote:
>
>
> Mathieu Desnoyers:
> > * David Goulet (dgoulet at efficios.com) wrote:
> >>
> >>
> >> Mathieu Desnoyers:
> >>> * David Goulet (dgoulet at efficios.com) wrote:
> >>>> As a second step of refactoring, upon receiving a data stream, we send
> >>>> it to the data thread that is now in charge of handling it.
> >>>>
> >>>> Furthermore, in order for this to behave correctly, we have to make the
> >>>> ustctl actions on the stream upon before passing it to the right thread
> >>>> (the kernel does not need special actions.). This way, once the sessiond
> >>>> thread reply back to the session daemon, the stream is sure to be open
> >>>> and ready for data to be recorded on the application side so we avoid a
> >>>> race between the application thinking the stream is ready and the stream
> >>>> thread still scheduled out.
> >>>
> >>> Normally, as long as we have a reference on the SHM file descriptor, and
> >>> we have the wakeup FD, we should be good to fetch the data of buffers
> >>> belonging to an application that has already exited, even if it did so
> >>> before the ustctl calls are done.
> >>>
> >>> So I'm wondering why you do the ustctl calls in the sessiond thread ? It
> >>> seems to complexify the implementation needlessly: we could still do the
> >>> ustctl calls and output file open at the same location, the
> >>> data/metadata threads.
> >>
> >> Hmmm, it was my understanding that does
> >
> > does -> those
> >
> >> ustctl_* calls were needed
> >> before the trace could be recording thus making them quickly. Wrong?
> >
> > Can you rephrase your question ? I don't understand.
> >
>
> My understanding was that _those_ ustctl calls need to be done before
> the tracer could start recording data. This is why they were moved to
> the session daemon thread.
>
> Am I wrong here? When receiving an UST stream< on the consumer side, is
> the SHM reference already acquired?
yes, the reference to shm is already acquired: it's the FD that _has_
the reference.
Thanks,
Mathieu
>
> David
>
> > Thanks,
> >
> > Mathieu
> >
> >>
> >> David
> >>
> >>>
> >>> Thanks,
> >>>
> >>> Mathieu
> >>>
> >>>>
> >>>> This commit should speed up the add stream process for the session
> >>>> daemon. There is still some actions to move out of the session daemon
> >>>> poll thread to gain speed significantly, especially for network
> >>>> streaming.
> >>>>
> >>>> Signed-off-by: David Goulet <dgoulet at efficios.com>
> >>>> ---
> >>>> src/common/consumer.c | 123 +++++++++++---------------
> >>>> src/common/consumer.h | 1 +
> >>>> src/common/kernel-consumer/kernel-consumer.c | 24 ++---
> >>>> src/common/ust-consumer/ust-consumer.c | 40 ++++-----
> >>>> 4 files changed, 78 insertions(+), 110 deletions(-)
> >>>>
> >>>> diff --git a/src/common/consumer.c b/src/common/consumer.c
> >>>> index 055de1b..1d2b1f7 100644
> >>>> --- a/src/common/consumer.c
> >>>> +++ b/src/common/consumer.c
> >>>> @@ -89,7 +89,7 @@ static struct lttng_consumer_stream *consumer_find_stream(int key,
> >>>> return stream;
> >>>> }
> >>>>
> >>>> -static void consumer_steal_stream_key(int key, struct lttng_ht *ht)
> >>>> +void consumer_steal_stream_key(int key, struct lttng_ht *ht)
> >>>> {
> >>>> struct lttng_consumer_stream *stream;
> >>>>
> >>>> @@ -409,6 +409,14 @@ struct lttng_consumer_stream *consumer_allocate_stream(
> >>>> lttng_ht_node_init_ulong(&stream->waitfd_node, stream->wait_fd);
> >>>> lttng_ht_node_init_ulong(&stream->node, stream->key);
> >>>>
> >>>> + /*
> >>>> + * The cpu number is needed before using any ustctl_* actions. Ignored for
> >>>> + * the kernel so the value does not matter.
> >>>> + */
> >>>> + pthread_mutex_lock(&consumer_data.lock);
> >>>> + stream->cpu = stream->chan->cpucount++;
> >>>> + pthread_mutex_unlock(&consumer_data.lock);
> >>>> +
> >>>> DBG3("Allocated stream %s (key %d, shm_fd %d, wait_fd %d, mmap_len %llu,"
> >>>> " out_fd %d, net_seq_idx %d)", stream->path_name, stream->key,
> >>>> stream->shm_fd, stream->wait_fd,
> >>>> @@ -437,28 +445,6 @@ int consumer_add_stream(struct lttng_consumer_stream *stream)
> >>>> pthread_mutex_lock(&consumer_data.lock);
> >>>> rcu_read_lock();
> >>>>
> >>>> - switch (consumer_data.type) {
> >>>> - case LTTNG_CONSUMER_KERNEL:
> >>>> - break;
> >>>> - case LTTNG_CONSUMER32_UST:
> >>>> - case LTTNG_CONSUMER64_UST:
> >>>> - stream->cpu = stream->chan->cpucount++;
> >>>> - ret = lttng_ustconsumer_add_stream(stream);
> >>>> - if (ret) {
> >>>> - ret = -EINVAL;
> >>>> - goto error;
> >>>> - }
> >>>> -
> >>>> - /* Steal stream identifier only for UST */
> >>>> - consumer_steal_stream_key(stream->key, consumer_data.stream_ht);
> >>>> - break;
> >>>> - default:
> >>>> - ERR("Unknown consumer_data type");
> >>>> - assert(0);
> >>>> - ret = -ENOSYS;
> >>>> - goto error;
> >>>> - }
> >>>> -
> >>>> lttng_ht_add_unique_ulong(consumer_data.stream_ht, &stream->node);
> >>>>
> >>>> /* Check and cleanup relayd */
> >>>> @@ -485,7 +471,6 @@ int consumer_add_stream(struct lttng_consumer_stream *stream)
> >>>> consumer_data.stream_count++;
> >>>> consumer_data.need_update = 1;
> >>>>
> >>>> -error:
> >>>> rcu_read_unlock();
> >>>> pthread_mutex_unlock(&consumer_data.lock);
> >>>>
> >>>> @@ -1582,17 +1567,6 @@ void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
> >>>>
> >>>> DBG3("Consumer delete metadata stream %d", stream->wait_fd);
> >>>>
> >>>> - if (ht == NULL) {
> >>>> - /* Means the stream was allocated but not successfully added */
> >>>> - goto free_stream;
> >>>> - }
> >>>> -
> >>>> - rcu_read_lock();
> >>>> - iter.iter.node = &stream->waitfd_node.node;
> >>>> - ret = lttng_ht_del(ht, &iter);
> >>>> - assert(!ret);
> >>>> - rcu_read_unlock();
> >>>> -
> >>>> pthread_mutex_lock(&consumer_data.lock);
> >>>> switch (consumer_data.type) {
> >>>> case LTTNG_CONSUMER_KERNEL:
> >>>> @@ -1613,6 +1587,18 @@ void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
> >>>> goto end;
> >>>> }
> >>>>
> >>>> + if (ht == NULL) {
> >>>> + pthread_mutex_unlock(&consumer_data.lock);
> >>>> + /* Means the stream was allocated but not successfully added */
> >>>> + goto free_stream;
> >>>> + }
> >>>> +
> >>>> + rcu_read_lock();
> >>>> + iter.iter.node = &stream->waitfd_node.node;
> >>>> + ret = lttng_ht_del(ht, &iter);
> >>>> + assert(!ret);
> >>>> + rcu_read_unlock();
> >>>> +
> >>>> if (stream->out_fd >= 0) {
> >>>> ret = close(stream->out_fd);
> >>>> if (ret) {
> >>>> @@ -1699,27 +1685,6 @@ static int consumer_add_metadata_stream(struct lttng_consumer_stream *stream,
> >>>>
> >>>> pthread_mutex_lock(&consumer_data.lock);
> >>>>
> >>>> - switch (consumer_data.type) {
> >>>> - case LTTNG_CONSUMER_KERNEL:
> >>>> - break;
> >>>> - case LTTNG_CONSUMER32_UST:
> >>>> - case LTTNG_CONSUMER64_UST:
> >>>> - ret = lttng_ustconsumer_add_stream(stream);
> >>>> - if (ret) {
> >>>> - ret = -EINVAL;
> >>>> - goto error;
> >>>> - }
> >>>> -
> >>>> - /* Steal stream identifier only for UST */
> >>>> - consumer_steal_stream_key(stream->wait_fd, ht);
> >>>> - break;
> >>>> - default:
> >>>> - ERR("Unknown consumer_data type");
> >>>> - assert(0);
> >>>> - ret = -ENOSYS;
> >>>> - goto error;
> >>>> - }
> >>>> -
> >>>> /*
> >>>> * From here, refcounts are updated so be _careful_ when returning an error
> >>>> * after this point.
> >>>> @@ -1749,7 +1714,6 @@ static int consumer_add_metadata_stream(struct lttng_consumer_stream *stream,
> >>>> lttng_ht_add_unique_ulong(ht, &stream->waitfd_node);
> >>>> rcu_read_unlock();
> >>>>
> >>>> -error:
> >>>> pthread_mutex_unlock(&consumer_data.lock);
> >>>> return ret;
> >>>> }
> >>>> @@ -1946,7 +1910,7 @@ void *consumer_thread_data_poll(void *data)
> >>>> int num_rdy, num_hup, high_prio, ret, i;
> >>>> struct pollfd *pollfd = NULL;
> >>>> /* local view of the streams */
> >>>> - struct lttng_consumer_stream **local_stream = NULL;
> >>>> + struct lttng_consumer_stream **local_stream = NULL, *new_stream = NULL;
> >>>> /* local view of consumer_data.fds_count */
> >>>> int nb_fd = 0;
> >>>> struct lttng_consumer_local_data *ctx = data;
> >>>> @@ -2034,13 +1998,35 @@ void *consumer_thread_data_poll(void *data)
> >>>> */
> >>>> if (pollfd[nb_fd].revents & (POLLIN | POLLPRI)) {
> >>>> size_t pipe_readlen;
> >>>> - char tmp;
> >>>>
> >>>> DBG("consumer_poll_pipe wake up");
> >>>> /* Consume 1 byte of pipe data */
> >>>> do {
> >>>> - pipe_readlen = read(ctx->consumer_poll_pipe[0], &tmp, 1);
> >>>> + pipe_readlen = read(ctx->consumer_poll_pipe[0], &new_stream,
> >>>> + sizeof(new_stream));
> >>>> } while (pipe_readlen == -1 && errno == EINTR);
> >>>> +
> >>>> + /*
> >>>> + * If the stream is NULL, just ignore it. It's also possible that
> >>>> + * the sessiond poll thread changed the consumer_quit state and is
> >>>> + * waking us up to test it.
> >>>> + */
> >>>> + if (new_stream == NULL) {
> >>>> + continue;
> >>>> + }
> >>>> +
> >>>> + ret = consumer_add_stream(new_stream);
> >>>> + if (ret) {
> >>>> + ERR("Consumer add stream %d failed. Continuing",
> >>>> + new_stream->key);
> >>>> + /*
> >>>> + * At this point, if the add_stream fails, it is not in the
> >>>> + * hash table thus passing the NULL value here.
> >>>> + */
> >>>> + consumer_del_stream(new_stream, NULL);
> >>>> + }
> >>>> +
> >>>> + /* Continue to update the local streams and handle prio ones */
> >>>> continue;
> >>>> }
> >>>>
> >>>> @@ -2260,19 +2246,16 @@ end:
> >>>> consumer_poll_timeout = LTTNG_CONSUMER_POLL_TIMEOUT;
> >>>>
> >>>> /*
> >>>> - * Wake-up the other end by writing a null byte in the pipe
> >>>> - * (non-blocking). Important note: Because writing into the
> >>>> - * pipe is non-blocking (and therefore we allow dropping wakeup
> >>>> - * data, as long as there is wakeup data present in the pipe
> >>>> - * buffer to wake up the other end), the other end should
> >>>> - * perform the following sequence for waiting:
> >>>> - * 1) empty the pipe (reads).
> >>>> - * 2) perform update operation.
> >>>> - * 3) wait on the pipe (poll).
> >>>> + * Notify the data poll thread to poll back again and test the
> >>>> + * consumer_quit state to quit gracefully.
> >>>> */
> >>>> do {
> >>>> - ret = write(ctx->consumer_poll_pipe[1], "", 1);
> >>>> + struct lttng_consumer_stream *null_stream = NULL;
> >>>> +
> >>>> + ret = write(ctx->consumer_poll_pipe[1], &null_stream,
> >>>> + sizeof(null_stream));
> >>>> } while (ret < 0 && errno == EINTR);
> >>>> +
> >>>> rcu_unregister_thread();
> >>>> return NULL;
> >>>> }
> >>>> diff --git a/src/common/consumer.h b/src/common/consumer.h
> >>>> index 4b225e4..8e5891a 100644
> >>>> --- a/src/common/consumer.h
> >>>> +++ b/src/common/consumer.h
> >>>> @@ -362,6 +362,7 @@ struct consumer_relayd_sock_pair *consumer_allocate_relayd_sock_pair(
> >>>> struct consumer_relayd_sock_pair *consumer_find_relayd(int key);
> >>>> int consumer_handle_stream_before_relayd(struct lttng_consumer_stream *stream,
> >>>> size_t data_size);
> >>>> +void consumer_steal_stream_key(int key, struct lttng_ht *ht);
> >>>>
> >>>> extern struct lttng_consumer_local_data *lttng_consumer_create(
> >>>> enum lttng_consumer_type type,
> >>>> diff --git a/src/common/kernel-consumer/kernel-consumer.c b/src/common/kernel-consumer/kernel-consumer.c
> >>>> index 13cbe21..444f5e0 100644
> >>>> --- a/src/common/kernel-consumer/kernel-consumer.c
> >>>> +++ b/src/common/kernel-consumer/kernel-consumer.c
> >>>> @@ -235,10 +235,12 @@ int lttng_kconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
> >>>> consumer_del_stream(new_stream, NULL);
> >>>> }
> >>>> } else {
> >>>> - ret = consumer_add_stream(new_stream);
> >>>> - if (ret) {
> >>>> - ERR("Consumer add stream %d failed. Continuing",
> >>>> - new_stream->key);
> >>>> + do {
> >>>> + ret = write(ctx->consumer_poll_pipe[1], &new_stream,
> >>>> + sizeof(new_stream));
> >>>> + } while (ret < 0 && errno == EINTR);
> >>>> + if (ret < 0) {
> >>>> + PERROR("write data pipe");
> >>>> consumer_del_stream(new_stream, NULL);
> >>>> goto end_nosignal;
> >>>> }
> >>>> @@ -284,20 +286,6 @@ int lttng_kconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
> >>>> goto end_nosignal;
> >>>> }
> >>>>
> >>>> - /*
> >>>> - * Wake-up the other end by writing a null byte in the pipe (non-blocking).
> >>>> - * Important note: Because writing into the pipe is non-blocking (and
> >>>> - * therefore we allow dropping wakeup data, as long as there is wakeup data
> >>>> - * present in the pipe buffer to wake up the other end), the other end
> >>>> - * should perform the following sequence for waiting:
> >>>> - *
> >>>> - * 1) empty the pipe (reads).
> >>>> - * 2) perform update operation.
> >>>> - * 3) wait on the pipe (poll).
> >>>> - */
> >>>> - do {
> >>>> - ret = write(ctx->consumer_poll_pipe[1], "", 1);
> >>>> - } while (ret < 0 && errno == EINTR);
> >>>> end_nosignal:
> >>>> rcu_read_unlock();
> >>>>
> >>>> diff --git a/src/common/ust-consumer/ust-consumer.c b/src/common/ust-consumer/ust-consumer.c
> >>>> index 1170687..4ca4b84 100644
> >>>> --- a/src/common/ust-consumer/ust-consumer.c
> >>>> +++ b/src/common/ust-consumer/ust-consumer.c
> >>>> @@ -224,6 +224,18 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
> >>>> goto end_nosignal;
> >>>> }
> >>>>
> >>>> + /*
> >>>> + * This needs to be done as soon as we can so we don't block the
> >>>> + * application too long.
> >>>> + */
> >>>> + ret = lttng_ustconsumer_add_stream(new_stream);
> >>>> + if (ret) {
> >>>> + consumer_del_stream(new_stream, NULL);
> >>>> + goto end_nosignal;
> >>>> + }
> >>>> + /* Steal stream identifier to avoid having streams with the same key */
> >>>> + consumer_steal_stream_key(new_stream->key, consumer_data.stream_ht);
> >>>> +
> >>>> /* The stream is not metadata. Get relayd reference if exists. */
> >>>> relayd = consumer_find_relayd(msg.u.stream.net_index);
> >>>> if (relayd != NULL) {
> >>>> @@ -265,14 +277,12 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
> >>>> goto end_nosignal;
> >>>> }
> >>>> } else {
> >>>> - ret = consumer_add_stream(new_stream);
> >>>> - if (ret) {
> >>>> - ERR("Consumer add stream %d failed. Continuing",
> >>>> - new_stream->key);
> >>>> - /*
> >>>> - * At this point, if the add_stream fails, it is not in the
> >>>> - * hash table thus passing the NULL value here.
> >>>> - */
> >>>> + do {
> >>>> + ret = write(ctx->consumer_poll_pipe[1], &new_stream,
> >>>> + sizeof(new_stream));
> >>>> + } while (ret < 0 && errno == EINTR);
> >>>> + if (ret < 0) {
> >>>> + PERROR("write data pipe");
> >>>> consumer_del_stream(new_stream, NULL);
> >>>> goto end_nosignal;
> >>>> }
> >>>> @@ -334,20 +344,6 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
> >>>> break;
> >>>> }
> >>>>
> >>>> - /*
> >>>> - * Wake-up the other end by writing a null byte in the pipe (non-blocking).
> >>>> - * Important note: Because writing into the pipe is non-blocking (and
> >>>> - * therefore we allow dropping wakeup data, as long as there is wakeup data
> >>>> - * present in the pipe buffer to wake up the other end), the other end
> >>>> - * should perform the following sequence for waiting:
> >>>> - *
> >>>> - * 1) empty the pipe (reads).
> >>>> - * 2) perform update operation.
> >>>> - * 3) wait on the pipe (poll).
> >>>> - */
> >>>> - do {
> >>>> - ret = write(ctx->consumer_poll_pipe[1], "", 1);
> >>>> - } while (ret < 0 && errno == EINTR);
> >>>> end_nosignal:
> >>>> rcu_read_unlock();
> >>>>
> >>>> --
> >>>> 1.7.10.4
> >>>>
> >>>>
> >>>> _______________________________________________
> >>>> lttng-dev mailing list
> >>>> lttng-dev at lists.lttng.org
> >>>> http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
> >>>
> >
--
Mathieu Desnoyers
Operating System Efficiency R&D Consultant
EfficiOS Inc.
http://www.efficios.com
^ permalink raw reply [flat|nested] 22+ messages in thread
* [lttng-dev] [PATCH lttng-tools 1/4] Rename consumer threads and spawn them in daemon
2012-10-15 17:39 ` Mathieu Desnoyers
@ 2012-10-15 17:42 ` David Goulet
0 siblings, 0 replies; 22+ messages in thread
From: David Goulet @ 2012-10-15 17:42 UTC (permalink / raw)
Mathieu Desnoyers:
> * David Goulet (dgoulet at efficios.com) wrote:
>>
>>
>> Mathieu Desnoyers:
>>>>>> diff --git a/src/common/consumer.c b/src/common/consumer.c
>>>>>> index 242b05b..055de1b 100644
>>>>>> --- a/src/common/consumer.c
>>>>>> +++ b/src/common/consumer.c
>>>>>> @@ -1131,6 +1131,8 @@ void lttng_consumer_destroy(struct lttng_consumer_local_data *ctx)
>>>>>> PERROR("close");
>>>>>> }
>>>>>> utils_close_pipe(ctx->consumer_splice_metadata_pipe);
>>>>>> + /* This should trigger the metadata thread to exit */
>>>>>> + close(ctx->consumer_metadata_pipe[1]);
>>>>>
>>>>> this is adding a close, but did not remove any other remove that might
>>>>> previously be in place elsewhere.
>>>>
>>>> So we got two possible error path which is either the poll thread fails
>>>> or the consumer could be destroy by hand even though the threads are
>>>> working well.
>>>>
>>>> Actually, this close should check if the value is valid and close it. To
>>>> be honest, this is just a shortcut since close(-1) does not fail and
>>>> ignoring the close error here since we are in the cleanup path anyway so
>>>> we don't necessarily care about the perror message.
>>>>
>>>> Anyhow, we have to handle both error path. An if plus set -1 after close
>>>> can be done so not to confuse.
>>>
>>> if two threads can concurrently perform close on the same fd value, how
>>> can you prove there are no possible races ?
>>
>> Nothing to prove, the race is possible. The point I was trying to
>> explain is that it does not matter actually since we are in a cleanup
>> code path.
>
> what happens if we close FD 0, 1, 2 or another FD, due to this race ?
This does not matter because we are in a "cleanup code path" ... closing
everything is the goal. In other circumstances, I agree that this is
unacceptable.
>
> what happens if our code evolve to restart threads after errors, and we
> leave this race in place, so it becomes hard to reproduce that in some
> occasions we are closing random file descriptors ?
Well... agree but I doubt "lttng_destroy_consumer" will change it's
behavior :P
David
>
>> Anyway, let's remove it since the data thread, when dying, will close
>> the metadata pipe anyway.
>
> my point exactly :)
>
>>
>> This will avoid more discussion for this small detail :).
>
> The devil is in the details, as someone famous said before me.
>
> Thanks,
>
> Mathieu
>
>>
>> David
>>
>>>
>>> Mathieu
>>>
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* [lttng-dev] [PATCH lttng-tools 2/4] Move add data stream to the data thread
2012-10-15 17:42 ` Mathieu Desnoyers
@ 2012-10-15 17:45 ` David Goulet
2012-10-15 17:56 ` Mathieu Desnoyers
0 siblings, 1 reply; 22+ messages in thread
From: David Goulet @ 2012-10-15 17:45 UTC (permalink / raw)
Mathieu Desnoyers:
> * David Goulet (dgoulet at efficios.com) wrote:
>>
>>
>> Mathieu Desnoyers:
>>> * David Goulet (dgoulet at efficios.com) wrote:
>>>>
>>>>
>>>> Mathieu Desnoyers:
>>>>> * David Goulet (dgoulet at efficios.com) wrote:
>>>>>> As a second step of refactoring, upon receiving a data stream, we send
>>>>>> it to the data thread that is now in charge of handling it.
>>>>>>
>>>>>> Furthermore, in order for this to behave correctly, we have to make the
>>>>>> ustctl actions on the stream upon before passing it to the right thread
>>>>>> (the kernel does not need special actions.). This way, once the sessiond
>>>>>> thread reply back to the session daemon, the stream is sure to be open
>>>>>> and ready for data to be recorded on the application side so we avoid a
>>>>>> race between the application thinking the stream is ready and the stream
>>>>>> thread still scheduled out.
>>>>>
>>>>> Normally, as long as we have a reference on the SHM file descriptor, and
>>>>> we have the wakeup FD, we should be good to fetch the data of buffers
>>>>> belonging to an application that has already exited, even if it did so
>>>>> before the ustctl calls are done.
>>>>>
>>>>> So I'm wondering why you do the ustctl calls in the sessiond thread ? It
>>>>> seems to complexify the implementation needlessly: we could still do the
>>>>> ustctl calls and output file open at the same location, the
>>>>> data/metadata threads.
>>>>
>>>> Hmmm, it was my understanding that does
>>>
>>> does -> those
>>>
>>>> ustctl_* calls were needed
>>>> before the trace could be recording thus making them quickly. Wrong?
>>>
>>> Can you rephrase your question ? I don't understand.
>>>
>>
>> My understanding was that _those_ ustctl calls need to be done before
>> the tracer could start recording data. This is why they were moved to
>> the session daemon thread.
>>
>> Am I wrong here? When receiving an UST stream< on the consumer side, is
>> the SHM reference already acquired?
>
> yes, the reference to shm is already acquired: it's the FD that _has_
> the reference.
Ok good. So just to be crystal clear here, the ustctl* calls can be
delayed and done in the right thread? (data/metadata).
David
>
> Thanks,
>
> Mathieu
>
>>
>> David
>>
>>> Thanks,
>>>
>>> Mathieu
>>>
>>>>
>>>> David
>>>>
>>>>>
>>>>> Thanks,
>>>>>
>>>>> Mathieu
>>>>>
>>>>>>
>>>>>> This commit should speed up the add stream process for the session
>>>>>> daemon. There is still some actions to move out of the session daemon
>>>>>> poll thread to gain speed significantly, especially for network
>>>>>> streaming.
>>>>>>
>>>>>> Signed-off-by: David Goulet <dgoulet at efficios.com>
>>>>>> ---
>>>>>> src/common/consumer.c | 123 +++++++++++---------------
>>>>>> src/common/consumer.h | 1 +
>>>>>> src/common/kernel-consumer/kernel-consumer.c | 24 ++---
>>>>>> src/common/ust-consumer/ust-consumer.c | 40 ++++-----
>>>>>> 4 files changed, 78 insertions(+), 110 deletions(-)
>>>>>>
>>>>>> diff --git a/src/common/consumer.c b/src/common/consumer.c
>>>>>> index 055de1b..1d2b1f7 100644
>>>>>> --- a/src/common/consumer.c
>>>>>> +++ b/src/common/consumer.c
>>>>>> @@ -89,7 +89,7 @@ static struct lttng_consumer_stream *consumer_find_stream(int key,
>>>>>> return stream;
>>>>>> }
>>>>>>
>>>>>> -static void consumer_steal_stream_key(int key, struct lttng_ht *ht)
>>>>>> +void consumer_steal_stream_key(int key, struct lttng_ht *ht)
>>>>>> {
>>>>>> struct lttng_consumer_stream *stream;
>>>>>>
>>>>>> @@ -409,6 +409,14 @@ struct lttng_consumer_stream *consumer_allocate_stream(
>>>>>> lttng_ht_node_init_ulong(&stream->waitfd_node, stream->wait_fd);
>>>>>> lttng_ht_node_init_ulong(&stream->node, stream->key);
>>>>>>
>>>>>> + /*
>>>>>> + * The cpu number is needed before using any ustctl_* actions. Ignored for
>>>>>> + * the kernel so the value does not matter.
>>>>>> + */
>>>>>> + pthread_mutex_lock(&consumer_data.lock);
>>>>>> + stream->cpu = stream->chan->cpucount++;
>>>>>> + pthread_mutex_unlock(&consumer_data.lock);
>>>>>> +
>>>>>> DBG3("Allocated stream %s (key %d, shm_fd %d, wait_fd %d, mmap_len %llu,"
>>>>>> " out_fd %d, net_seq_idx %d)", stream->path_name, stream->key,
>>>>>> stream->shm_fd, stream->wait_fd,
>>>>>> @@ -437,28 +445,6 @@ int consumer_add_stream(struct lttng_consumer_stream *stream)
>>>>>> pthread_mutex_lock(&consumer_data.lock);
>>>>>> rcu_read_lock();
>>>>>>
>>>>>> - switch (consumer_data.type) {
>>>>>> - case LTTNG_CONSUMER_KERNEL:
>>>>>> - break;
>>>>>> - case LTTNG_CONSUMER32_UST:
>>>>>> - case LTTNG_CONSUMER64_UST:
>>>>>> - stream->cpu = stream->chan->cpucount++;
>>>>>> - ret = lttng_ustconsumer_add_stream(stream);
>>>>>> - if (ret) {
>>>>>> - ret = -EINVAL;
>>>>>> - goto error;
>>>>>> - }
>>>>>> -
>>>>>> - /* Steal stream identifier only for UST */
>>>>>> - consumer_steal_stream_key(stream->key, consumer_data.stream_ht);
>>>>>> - break;
>>>>>> - default:
>>>>>> - ERR("Unknown consumer_data type");
>>>>>> - assert(0);
>>>>>> - ret = -ENOSYS;
>>>>>> - goto error;
>>>>>> - }
>>>>>> -
>>>>>> lttng_ht_add_unique_ulong(consumer_data.stream_ht, &stream->node);
>>>>>>
>>>>>> /* Check and cleanup relayd */
>>>>>> @@ -485,7 +471,6 @@ int consumer_add_stream(struct lttng_consumer_stream *stream)
>>>>>> consumer_data.stream_count++;
>>>>>> consumer_data.need_update = 1;
>>>>>>
>>>>>> -error:
>>>>>> rcu_read_unlock();
>>>>>> pthread_mutex_unlock(&consumer_data.lock);
>>>>>>
>>>>>> @@ -1582,17 +1567,6 @@ void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
>>>>>>
>>>>>> DBG3("Consumer delete metadata stream %d", stream->wait_fd);
>>>>>>
>>>>>> - if (ht == NULL) {
>>>>>> - /* Means the stream was allocated but not successfully added */
>>>>>> - goto free_stream;
>>>>>> - }
>>>>>> -
>>>>>> - rcu_read_lock();
>>>>>> - iter.iter.node = &stream->waitfd_node.node;
>>>>>> - ret = lttng_ht_del(ht, &iter);
>>>>>> - assert(!ret);
>>>>>> - rcu_read_unlock();
>>>>>> -
>>>>>> pthread_mutex_lock(&consumer_data.lock);
>>>>>> switch (consumer_data.type) {
>>>>>> case LTTNG_CONSUMER_KERNEL:
>>>>>> @@ -1613,6 +1587,18 @@ void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
>>>>>> goto end;
>>>>>> }
>>>>>>
>>>>>> + if (ht == NULL) {
>>>>>> + pthread_mutex_unlock(&consumer_data.lock);
>>>>>> + /* Means the stream was allocated but not successfully added */
>>>>>> + goto free_stream;
>>>>>> + }
>>>>>> +
>>>>>> + rcu_read_lock();
>>>>>> + iter.iter.node = &stream->waitfd_node.node;
>>>>>> + ret = lttng_ht_del(ht, &iter);
>>>>>> + assert(!ret);
>>>>>> + rcu_read_unlock();
>>>>>> +
>>>>>> if (stream->out_fd >= 0) {
>>>>>> ret = close(stream->out_fd);
>>>>>> if (ret) {
>>>>>> @@ -1699,27 +1685,6 @@ static int consumer_add_metadata_stream(struct lttng_consumer_stream *stream,
>>>>>>
>>>>>> pthread_mutex_lock(&consumer_data.lock);
>>>>>>
>>>>>> - switch (consumer_data.type) {
>>>>>> - case LTTNG_CONSUMER_KERNEL:
>>>>>> - break;
>>>>>> - case LTTNG_CONSUMER32_UST:
>>>>>> - case LTTNG_CONSUMER64_UST:
>>>>>> - ret = lttng_ustconsumer_add_stream(stream);
>>>>>> - if (ret) {
>>>>>> - ret = -EINVAL;
>>>>>> - goto error;
>>>>>> - }
>>>>>> -
>>>>>> - /* Steal stream identifier only for UST */
>>>>>> - consumer_steal_stream_key(stream->wait_fd, ht);
>>>>>> - break;
>>>>>> - default:
>>>>>> - ERR("Unknown consumer_data type");
>>>>>> - assert(0);
>>>>>> - ret = -ENOSYS;
>>>>>> - goto error;
>>>>>> - }
>>>>>> -
>>>>>> /*
>>>>>> * From here, refcounts are updated so be _careful_ when returning an error
>>>>>> * after this point.
>>>>>> @@ -1749,7 +1714,6 @@ static int consumer_add_metadata_stream(struct lttng_consumer_stream *stream,
>>>>>> lttng_ht_add_unique_ulong(ht, &stream->waitfd_node);
>>>>>> rcu_read_unlock();
>>>>>>
>>>>>> -error:
>>>>>> pthread_mutex_unlock(&consumer_data.lock);
>>>>>> return ret;
>>>>>> }
>>>>>> @@ -1946,7 +1910,7 @@ void *consumer_thread_data_poll(void *data)
>>>>>> int num_rdy, num_hup, high_prio, ret, i;
>>>>>> struct pollfd *pollfd = NULL;
>>>>>> /* local view of the streams */
>>>>>> - struct lttng_consumer_stream **local_stream = NULL;
>>>>>> + struct lttng_consumer_stream **local_stream = NULL, *new_stream = NULL;
>>>>>> /* local view of consumer_data.fds_count */
>>>>>> int nb_fd = 0;
>>>>>> struct lttng_consumer_local_data *ctx = data;
>>>>>> @@ -2034,13 +1998,35 @@ void *consumer_thread_data_poll(void *data)
>>>>>> */
>>>>>> if (pollfd[nb_fd].revents & (POLLIN | POLLPRI)) {
>>>>>> size_t pipe_readlen;
>>>>>> - char tmp;
>>>>>>
>>>>>> DBG("consumer_poll_pipe wake up");
>>>>>> /* Consume 1 byte of pipe data */
>>>>>> do {
>>>>>> - pipe_readlen = read(ctx->consumer_poll_pipe[0], &tmp, 1);
>>>>>> + pipe_readlen = read(ctx->consumer_poll_pipe[0], &new_stream,
>>>>>> + sizeof(new_stream));
>>>>>> } while (pipe_readlen == -1 && errno == EINTR);
>>>>>> +
>>>>>> + /*
>>>>>> + * If the stream is NULL, just ignore it. It's also possible that
>>>>>> + * the sessiond poll thread changed the consumer_quit state and is
>>>>>> + * waking us up to test it.
>>>>>> + */
>>>>>> + if (new_stream == NULL) {
>>>>>> + continue;
>>>>>> + }
>>>>>> +
>>>>>> + ret = consumer_add_stream(new_stream);
>>>>>> + if (ret) {
>>>>>> + ERR("Consumer add stream %d failed. Continuing",
>>>>>> + new_stream->key);
>>>>>> + /*
>>>>>> + * At this point, if the add_stream fails, it is not in the
>>>>>> + * hash table thus passing the NULL value here.
>>>>>> + */
>>>>>> + consumer_del_stream(new_stream, NULL);
>>>>>> + }
>>>>>> +
>>>>>> + /* Continue to update the local streams and handle prio ones */
>>>>>> continue;
>>>>>> }
>>>>>>
>>>>>> @@ -2260,19 +2246,16 @@ end:
>>>>>> consumer_poll_timeout = LTTNG_CONSUMER_POLL_TIMEOUT;
>>>>>>
>>>>>> /*
>>>>>> - * Wake-up the other end by writing a null byte in the pipe
>>>>>> - * (non-blocking). Important note: Because writing into the
>>>>>> - * pipe is non-blocking (and therefore we allow dropping wakeup
>>>>>> - * data, as long as there is wakeup data present in the pipe
>>>>>> - * buffer to wake up the other end), the other end should
>>>>>> - * perform the following sequence for waiting:
>>>>>> - * 1) empty the pipe (reads).
>>>>>> - * 2) perform update operation.
>>>>>> - * 3) wait on the pipe (poll).
>>>>>> + * Notify the data poll thread to poll back again and test the
>>>>>> + * consumer_quit state to quit gracefully.
>>>>>> */
>>>>>> do {
>>>>>> - ret = write(ctx->consumer_poll_pipe[1], "", 1);
>>>>>> + struct lttng_consumer_stream *null_stream = NULL;
>>>>>> +
>>>>>> + ret = write(ctx->consumer_poll_pipe[1], &null_stream,
>>>>>> + sizeof(null_stream));
>>>>>> } while (ret < 0 && errno == EINTR);
>>>>>> +
>>>>>> rcu_unregister_thread();
>>>>>> return NULL;
>>>>>> }
>>>>>> diff --git a/src/common/consumer.h b/src/common/consumer.h
>>>>>> index 4b225e4..8e5891a 100644
>>>>>> --- a/src/common/consumer.h
>>>>>> +++ b/src/common/consumer.h
>>>>>> @@ -362,6 +362,7 @@ struct consumer_relayd_sock_pair *consumer_allocate_relayd_sock_pair(
>>>>>> struct consumer_relayd_sock_pair *consumer_find_relayd(int key);
>>>>>> int consumer_handle_stream_before_relayd(struct lttng_consumer_stream *stream,
>>>>>> size_t data_size);
>>>>>> +void consumer_steal_stream_key(int key, struct lttng_ht *ht);
>>>>>>
>>>>>> extern struct lttng_consumer_local_data *lttng_consumer_create(
>>>>>> enum lttng_consumer_type type,
>>>>>> diff --git a/src/common/kernel-consumer/kernel-consumer.c b/src/common/kernel-consumer/kernel-consumer.c
>>>>>> index 13cbe21..444f5e0 100644
>>>>>> --- a/src/common/kernel-consumer/kernel-consumer.c
>>>>>> +++ b/src/common/kernel-consumer/kernel-consumer.c
>>>>>> @@ -235,10 +235,12 @@ int lttng_kconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
>>>>>> consumer_del_stream(new_stream, NULL);
>>>>>> }
>>>>>> } else {
>>>>>> - ret = consumer_add_stream(new_stream);
>>>>>> - if (ret) {
>>>>>> - ERR("Consumer add stream %d failed. Continuing",
>>>>>> - new_stream->key);
>>>>>> + do {
>>>>>> + ret = write(ctx->consumer_poll_pipe[1], &new_stream,
>>>>>> + sizeof(new_stream));
>>>>>> + } while (ret < 0 && errno == EINTR);
>>>>>> + if (ret < 0) {
>>>>>> + PERROR("write data pipe");
>>>>>> consumer_del_stream(new_stream, NULL);
>>>>>> goto end_nosignal;
>>>>>> }
>>>>>> @@ -284,20 +286,6 @@ int lttng_kconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
>>>>>> goto end_nosignal;
>>>>>> }
>>>>>>
>>>>>> - /*
>>>>>> - * Wake-up the other end by writing a null byte in the pipe (non-blocking).
>>>>>> - * Important note: Because writing into the pipe is non-blocking (and
>>>>>> - * therefore we allow dropping wakeup data, as long as there is wakeup data
>>>>>> - * present in the pipe buffer to wake up the other end), the other end
>>>>>> - * should perform the following sequence for waiting:
>>>>>> - *
>>>>>> - * 1) empty the pipe (reads).
>>>>>> - * 2) perform update operation.
>>>>>> - * 3) wait on the pipe (poll).
>>>>>> - */
>>>>>> - do {
>>>>>> - ret = write(ctx->consumer_poll_pipe[1], "", 1);
>>>>>> - } while (ret < 0 && errno == EINTR);
>>>>>> end_nosignal:
>>>>>> rcu_read_unlock();
>>>>>>
>>>>>> diff --git a/src/common/ust-consumer/ust-consumer.c b/src/common/ust-consumer/ust-consumer.c
>>>>>> index 1170687..4ca4b84 100644
>>>>>> --- a/src/common/ust-consumer/ust-consumer.c
>>>>>> +++ b/src/common/ust-consumer/ust-consumer.c
>>>>>> @@ -224,6 +224,18 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
>>>>>> goto end_nosignal;
>>>>>> }
>>>>>>
>>>>>> + /*
>>>>>> + * This needs to be done as soon as we can so we don't block the
>>>>>> + * application too long.
>>>>>> + */
>>>>>> + ret = lttng_ustconsumer_add_stream(new_stream);
>>>>>> + if (ret) {
>>>>>> + consumer_del_stream(new_stream, NULL);
>>>>>> + goto end_nosignal;
>>>>>> + }
>>>>>> + /* Steal stream identifier to avoid having streams with the same key */
>>>>>> + consumer_steal_stream_key(new_stream->key, consumer_data.stream_ht);
>>>>>> +
>>>>>> /* The stream is not metadata. Get relayd reference if exists. */
>>>>>> relayd = consumer_find_relayd(msg.u.stream.net_index);
>>>>>> if (relayd != NULL) {
>>>>>> @@ -265,14 +277,12 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
>>>>>> goto end_nosignal;
>>>>>> }
>>>>>> } else {
>>>>>> - ret = consumer_add_stream(new_stream);
>>>>>> - if (ret) {
>>>>>> - ERR("Consumer add stream %d failed. Continuing",
>>>>>> - new_stream->key);
>>>>>> - /*
>>>>>> - * At this point, if the add_stream fails, it is not in the
>>>>>> - * hash table thus passing the NULL value here.
>>>>>> - */
>>>>>> + do {
>>>>>> + ret = write(ctx->consumer_poll_pipe[1], &new_stream,
>>>>>> + sizeof(new_stream));
>>>>>> + } while (ret < 0 && errno == EINTR);
>>>>>> + if (ret < 0) {
>>>>>> + PERROR("write data pipe");
>>>>>> consumer_del_stream(new_stream, NULL);
>>>>>> goto end_nosignal;
>>>>>> }
>>>>>> @@ -334,20 +344,6 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
>>>>>> break;
>>>>>> }
>>>>>>
>>>>>> - /*
>>>>>> - * Wake-up the other end by writing a null byte in the pipe (non-blocking).
>>>>>> - * Important note: Because writing into the pipe is non-blocking (and
>>>>>> - * therefore we allow dropping wakeup data, as long as there is wakeup data
>>>>>> - * present in the pipe buffer to wake up the other end), the other end
>>>>>> - * should perform the following sequence for waiting:
>>>>>> - *
>>>>>> - * 1) empty the pipe (reads).
>>>>>> - * 2) perform update operation.
>>>>>> - * 3) wait on the pipe (poll).
>>>>>> - */
>>>>>> - do {
>>>>>> - ret = write(ctx->consumer_poll_pipe[1], "", 1);
>>>>>> - } while (ret < 0 && errno == EINTR);
>>>>>> end_nosignal:
>>>>>> rcu_read_unlock();
>>>>>>
>>>>>> --
>>>>>> 1.7.10.4
>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>>> lttng-dev mailing list
>>>>>> lttng-dev at lists.lttng.org
>>>>>> http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
>>>>>
>>>
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* [lttng-dev] [PATCH lttng-tools 2/4] Move add data stream to the data thread
2012-10-15 17:45 ` David Goulet
@ 2012-10-15 17:56 ` Mathieu Desnoyers
0 siblings, 0 replies; 22+ messages in thread
From: Mathieu Desnoyers @ 2012-10-15 17:56 UTC (permalink / raw)
* David Goulet (dgoulet at efficios.com) wrote:
>
>
> Mathieu Desnoyers:
> > * David Goulet (dgoulet at efficios.com) wrote:
> >>
> >>
> >> Mathieu Desnoyers:
> >>> * David Goulet (dgoulet at efficios.com) wrote:
> >>>>
> >>>>
> >>>> Mathieu Desnoyers:
> >>>>> * David Goulet (dgoulet at efficios.com) wrote:
> >>>>>> As a second step of refactoring, upon receiving a data stream, we send
> >>>>>> it to the data thread that is now in charge of handling it.
> >>>>>>
> >>>>>> Furthermore, in order for this to behave correctly, we have to make the
> >>>>>> ustctl actions on the stream upon before passing it to the right thread
> >>>>>> (the kernel does not need special actions.). This way, once the sessiond
> >>>>>> thread reply back to the session daemon, the stream is sure to be open
> >>>>>> and ready for data to be recorded on the application side so we avoid a
> >>>>>> race between the application thinking the stream is ready and the stream
> >>>>>> thread still scheduled out.
> >>>>>
> >>>>> Normally, as long as we have a reference on the SHM file descriptor, and
> >>>>> we have the wakeup FD, we should be good to fetch the data of buffers
> >>>>> belonging to an application that has already exited, even if it did so
> >>>>> before the ustctl calls are done.
> >>>>>
> >>>>> So I'm wondering why you do the ustctl calls in the sessiond thread ? It
> >>>>> seems to complexify the implementation needlessly: we could still do the
> >>>>> ustctl calls and output file open at the same location, the
> >>>>> data/metadata threads.
> >>>>
> >>>> Hmmm, it was my understanding that does
> >>>
> >>> does -> those
> >>>
> >>>> ustctl_* calls were needed
> >>>> before the trace could be recording thus making them quickly. Wrong?
> >>>
> >>> Can you rephrase your question ? I don't understand.
> >>>
> >>
> >> My understanding was that _those_ ustctl calls need to be done before
> >> the tracer could start recording data. This is why they were moved to
> >> the session daemon thread.
> >>
> >> Am I wrong here? When receiving an UST stream< on the consumer side, is
> >> the SHM reference already acquired?
> >
> > yes, the reference to shm is already acquired: it's the FD that _has_
> > the reference.
>
> Ok good. So just to be crystal clear here, the ustctl* calls can be
> delayed and done in the right thread? (data/metadata).
yes, I expect it should work.
Mathieu
>
> David
>
> >
> > Thanks,
> >
> > Mathieu
> >
> >>
> >> David
> >>
> >>> Thanks,
> >>>
> >>> Mathieu
> >>>
> >>>>
> >>>> David
> >>>>
> >>>>>
> >>>>> Thanks,
> >>>>>
> >>>>> Mathieu
> >>>>>
> >>>>>>
> >>>>>> This commit should speed up the add stream process for the session
> >>>>>> daemon. There is still some actions to move out of the session daemon
> >>>>>> poll thread to gain speed significantly, especially for network
> >>>>>> streaming.
> >>>>>>
> >>>>>> Signed-off-by: David Goulet <dgoulet at efficios.com>
> >>>>>> ---
> >>>>>> src/common/consumer.c | 123 +++++++++++---------------
> >>>>>> src/common/consumer.h | 1 +
> >>>>>> src/common/kernel-consumer/kernel-consumer.c | 24 ++---
> >>>>>> src/common/ust-consumer/ust-consumer.c | 40 ++++-----
> >>>>>> 4 files changed, 78 insertions(+), 110 deletions(-)
> >>>>>>
> >>>>>> diff --git a/src/common/consumer.c b/src/common/consumer.c
> >>>>>> index 055de1b..1d2b1f7 100644
> >>>>>> --- a/src/common/consumer.c
> >>>>>> +++ b/src/common/consumer.c
> >>>>>> @@ -89,7 +89,7 @@ static struct lttng_consumer_stream *consumer_find_stream(int key,
> >>>>>> return stream;
> >>>>>> }
> >>>>>>
> >>>>>> -static void consumer_steal_stream_key(int key, struct lttng_ht *ht)
> >>>>>> +void consumer_steal_stream_key(int key, struct lttng_ht *ht)
> >>>>>> {
> >>>>>> struct lttng_consumer_stream *stream;
> >>>>>>
> >>>>>> @@ -409,6 +409,14 @@ struct lttng_consumer_stream *consumer_allocate_stream(
> >>>>>> lttng_ht_node_init_ulong(&stream->waitfd_node, stream->wait_fd);
> >>>>>> lttng_ht_node_init_ulong(&stream->node, stream->key);
> >>>>>>
> >>>>>> + /*
> >>>>>> + * The cpu number is needed before using any ustctl_* actions. Ignored for
> >>>>>> + * the kernel so the value does not matter.
> >>>>>> + */
> >>>>>> + pthread_mutex_lock(&consumer_data.lock);
> >>>>>> + stream->cpu = stream->chan->cpucount++;
> >>>>>> + pthread_mutex_unlock(&consumer_data.lock);
> >>>>>> +
> >>>>>> DBG3("Allocated stream %s (key %d, shm_fd %d, wait_fd %d, mmap_len %llu,"
> >>>>>> " out_fd %d, net_seq_idx %d)", stream->path_name, stream->key,
> >>>>>> stream->shm_fd, stream->wait_fd,
> >>>>>> @@ -437,28 +445,6 @@ int consumer_add_stream(struct lttng_consumer_stream *stream)
> >>>>>> pthread_mutex_lock(&consumer_data.lock);
> >>>>>> rcu_read_lock();
> >>>>>>
> >>>>>> - switch (consumer_data.type) {
> >>>>>> - case LTTNG_CONSUMER_KERNEL:
> >>>>>> - break;
> >>>>>> - case LTTNG_CONSUMER32_UST:
> >>>>>> - case LTTNG_CONSUMER64_UST:
> >>>>>> - stream->cpu = stream->chan->cpucount++;
> >>>>>> - ret = lttng_ustconsumer_add_stream(stream);
> >>>>>> - if (ret) {
> >>>>>> - ret = -EINVAL;
> >>>>>> - goto error;
> >>>>>> - }
> >>>>>> -
> >>>>>> - /* Steal stream identifier only for UST */
> >>>>>> - consumer_steal_stream_key(stream->key, consumer_data.stream_ht);
> >>>>>> - break;
> >>>>>> - default:
> >>>>>> - ERR("Unknown consumer_data type");
> >>>>>> - assert(0);
> >>>>>> - ret = -ENOSYS;
> >>>>>> - goto error;
> >>>>>> - }
> >>>>>> -
> >>>>>> lttng_ht_add_unique_ulong(consumer_data.stream_ht, &stream->node);
> >>>>>>
> >>>>>> /* Check and cleanup relayd */
> >>>>>> @@ -485,7 +471,6 @@ int consumer_add_stream(struct lttng_consumer_stream *stream)
> >>>>>> consumer_data.stream_count++;
> >>>>>> consumer_data.need_update = 1;
> >>>>>>
> >>>>>> -error:
> >>>>>> rcu_read_unlock();
> >>>>>> pthread_mutex_unlock(&consumer_data.lock);
> >>>>>>
> >>>>>> @@ -1582,17 +1567,6 @@ void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
> >>>>>>
> >>>>>> DBG3("Consumer delete metadata stream %d", stream->wait_fd);
> >>>>>>
> >>>>>> - if (ht == NULL) {
> >>>>>> - /* Means the stream was allocated but not successfully added */
> >>>>>> - goto free_stream;
> >>>>>> - }
> >>>>>> -
> >>>>>> - rcu_read_lock();
> >>>>>> - iter.iter.node = &stream->waitfd_node.node;
> >>>>>> - ret = lttng_ht_del(ht, &iter);
> >>>>>> - assert(!ret);
> >>>>>> - rcu_read_unlock();
> >>>>>> -
> >>>>>> pthread_mutex_lock(&consumer_data.lock);
> >>>>>> switch (consumer_data.type) {
> >>>>>> case LTTNG_CONSUMER_KERNEL:
> >>>>>> @@ -1613,6 +1587,18 @@ void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
> >>>>>> goto end;
> >>>>>> }
> >>>>>>
> >>>>>> + if (ht == NULL) {
> >>>>>> + pthread_mutex_unlock(&consumer_data.lock);
> >>>>>> + /* Means the stream was allocated but not successfully added */
> >>>>>> + goto free_stream;
> >>>>>> + }
> >>>>>> +
> >>>>>> + rcu_read_lock();
> >>>>>> + iter.iter.node = &stream->waitfd_node.node;
> >>>>>> + ret = lttng_ht_del(ht, &iter);
> >>>>>> + assert(!ret);
> >>>>>> + rcu_read_unlock();
> >>>>>> +
> >>>>>> if (stream->out_fd >= 0) {
> >>>>>> ret = close(stream->out_fd);
> >>>>>> if (ret) {
> >>>>>> @@ -1699,27 +1685,6 @@ static int consumer_add_metadata_stream(struct lttng_consumer_stream *stream,
> >>>>>>
> >>>>>> pthread_mutex_lock(&consumer_data.lock);
> >>>>>>
> >>>>>> - switch (consumer_data.type) {
> >>>>>> - case LTTNG_CONSUMER_KERNEL:
> >>>>>> - break;
> >>>>>> - case LTTNG_CONSUMER32_UST:
> >>>>>> - case LTTNG_CONSUMER64_UST:
> >>>>>> - ret = lttng_ustconsumer_add_stream(stream);
> >>>>>> - if (ret) {
> >>>>>> - ret = -EINVAL;
> >>>>>> - goto error;
> >>>>>> - }
> >>>>>> -
> >>>>>> - /* Steal stream identifier only for UST */
> >>>>>> - consumer_steal_stream_key(stream->wait_fd, ht);
> >>>>>> - break;
> >>>>>> - default:
> >>>>>> - ERR("Unknown consumer_data type");
> >>>>>> - assert(0);
> >>>>>> - ret = -ENOSYS;
> >>>>>> - goto error;
> >>>>>> - }
> >>>>>> -
> >>>>>> /*
> >>>>>> * From here, refcounts are updated so be _careful_ when returning an error
> >>>>>> * after this point.
> >>>>>> @@ -1749,7 +1714,6 @@ static int consumer_add_metadata_stream(struct lttng_consumer_stream *stream,
> >>>>>> lttng_ht_add_unique_ulong(ht, &stream->waitfd_node);
> >>>>>> rcu_read_unlock();
> >>>>>>
> >>>>>> -error:
> >>>>>> pthread_mutex_unlock(&consumer_data.lock);
> >>>>>> return ret;
> >>>>>> }
> >>>>>> @@ -1946,7 +1910,7 @@ void *consumer_thread_data_poll(void *data)
> >>>>>> int num_rdy, num_hup, high_prio, ret, i;
> >>>>>> struct pollfd *pollfd = NULL;
> >>>>>> /* local view of the streams */
> >>>>>> - struct lttng_consumer_stream **local_stream = NULL;
> >>>>>> + struct lttng_consumer_stream **local_stream = NULL, *new_stream = NULL;
> >>>>>> /* local view of consumer_data.fds_count */
> >>>>>> int nb_fd = 0;
> >>>>>> struct lttng_consumer_local_data *ctx = data;
> >>>>>> @@ -2034,13 +1998,35 @@ void *consumer_thread_data_poll(void *data)
> >>>>>> */
> >>>>>> if (pollfd[nb_fd].revents & (POLLIN | POLLPRI)) {
> >>>>>> size_t pipe_readlen;
> >>>>>> - char tmp;
> >>>>>>
> >>>>>> DBG("consumer_poll_pipe wake up");
> >>>>>> /* Consume 1 byte of pipe data */
> >>>>>> do {
> >>>>>> - pipe_readlen = read(ctx->consumer_poll_pipe[0], &tmp, 1);
> >>>>>> + pipe_readlen = read(ctx->consumer_poll_pipe[0], &new_stream,
> >>>>>> + sizeof(new_stream));
> >>>>>> } while (pipe_readlen == -1 && errno == EINTR);
> >>>>>> +
> >>>>>> + /*
> >>>>>> + * If the stream is NULL, just ignore it. It's also possible that
> >>>>>> + * the sessiond poll thread changed the consumer_quit state and is
> >>>>>> + * waking us up to test it.
> >>>>>> + */
> >>>>>> + if (new_stream == NULL) {
> >>>>>> + continue;
> >>>>>> + }
> >>>>>> +
> >>>>>> + ret = consumer_add_stream(new_stream);
> >>>>>> + if (ret) {
> >>>>>> + ERR("Consumer add stream %d failed. Continuing",
> >>>>>> + new_stream->key);
> >>>>>> + /*
> >>>>>> + * At this point, if the add_stream fails, it is not in the
> >>>>>> + * hash table thus passing the NULL value here.
> >>>>>> + */
> >>>>>> + consumer_del_stream(new_stream, NULL);
> >>>>>> + }
> >>>>>> +
> >>>>>> + /* Continue to update the local streams and handle prio ones */
> >>>>>> continue;
> >>>>>> }
> >>>>>>
> >>>>>> @@ -2260,19 +2246,16 @@ end:
> >>>>>> consumer_poll_timeout = LTTNG_CONSUMER_POLL_TIMEOUT;
> >>>>>>
> >>>>>> /*
> >>>>>> - * Wake-up the other end by writing a null byte in the pipe
> >>>>>> - * (non-blocking). Important note: Because writing into the
> >>>>>> - * pipe is non-blocking (and therefore we allow dropping wakeup
> >>>>>> - * data, as long as there is wakeup data present in the pipe
> >>>>>> - * buffer to wake up the other end), the other end should
> >>>>>> - * perform the following sequence for waiting:
> >>>>>> - * 1) empty the pipe (reads).
> >>>>>> - * 2) perform update operation.
> >>>>>> - * 3) wait on the pipe (poll).
> >>>>>> + * Notify the data poll thread to poll back again and test the
> >>>>>> + * consumer_quit state to quit gracefully.
> >>>>>> */
> >>>>>> do {
> >>>>>> - ret = write(ctx->consumer_poll_pipe[1], "", 1);
> >>>>>> + struct lttng_consumer_stream *null_stream = NULL;
> >>>>>> +
> >>>>>> + ret = write(ctx->consumer_poll_pipe[1], &null_stream,
> >>>>>> + sizeof(null_stream));
> >>>>>> } while (ret < 0 && errno == EINTR);
> >>>>>> +
> >>>>>> rcu_unregister_thread();
> >>>>>> return NULL;
> >>>>>> }
> >>>>>> diff --git a/src/common/consumer.h b/src/common/consumer.h
> >>>>>> index 4b225e4..8e5891a 100644
> >>>>>> --- a/src/common/consumer.h
> >>>>>> +++ b/src/common/consumer.h
> >>>>>> @@ -362,6 +362,7 @@ struct consumer_relayd_sock_pair *consumer_allocate_relayd_sock_pair(
> >>>>>> struct consumer_relayd_sock_pair *consumer_find_relayd(int key);
> >>>>>> int consumer_handle_stream_before_relayd(struct lttng_consumer_stream *stream,
> >>>>>> size_t data_size);
> >>>>>> +void consumer_steal_stream_key(int key, struct lttng_ht *ht);
> >>>>>>
> >>>>>> extern struct lttng_consumer_local_data *lttng_consumer_create(
> >>>>>> enum lttng_consumer_type type,
> >>>>>> diff --git a/src/common/kernel-consumer/kernel-consumer.c b/src/common/kernel-consumer/kernel-consumer.c
> >>>>>> index 13cbe21..444f5e0 100644
> >>>>>> --- a/src/common/kernel-consumer/kernel-consumer.c
> >>>>>> +++ b/src/common/kernel-consumer/kernel-consumer.c
> >>>>>> @@ -235,10 +235,12 @@ int lttng_kconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
> >>>>>> consumer_del_stream(new_stream, NULL);
> >>>>>> }
> >>>>>> } else {
> >>>>>> - ret = consumer_add_stream(new_stream);
> >>>>>> - if (ret) {
> >>>>>> - ERR("Consumer add stream %d failed. Continuing",
> >>>>>> - new_stream->key);
> >>>>>> + do {
> >>>>>> + ret = write(ctx->consumer_poll_pipe[1], &new_stream,
> >>>>>> + sizeof(new_stream));
> >>>>>> + } while (ret < 0 && errno == EINTR);
> >>>>>> + if (ret < 0) {
> >>>>>> + PERROR("write data pipe");
> >>>>>> consumer_del_stream(new_stream, NULL);
> >>>>>> goto end_nosignal;
> >>>>>> }
> >>>>>> @@ -284,20 +286,6 @@ int lttng_kconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
> >>>>>> goto end_nosignal;
> >>>>>> }
> >>>>>>
> >>>>>> - /*
> >>>>>> - * Wake-up the other end by writing a null byte in the pipe (non-blocking).
> >>>>>> - * Important note: Because writing into the pipe is non-blocking (and
> >>>>>> - * therefore we allow dropping wakeup data, as long as there is wakeup data
> >>>>>> - * present in the pipe buffer to wake up the other end), the other end
> >>>>>> - * should perform the following sequence for waiting:
> >>>>>> - *
> >>>>>> - * 1) empty the pipe (reads).
> >>>>>> - * 2) perform update operation.
> >>>>>> - * 3) wait on the pipe (poll).
> >>>>>> - */
> >>>>>> - do {
> >>>>>> - ret = write(ctx->consumer_poll_pipe[1], "", 1);
> >>>>>> - } while (ret < 0 && errno == EINTR);
> >>>>>> end_nosignal:
> >>>>>> rcu_read_unlock();
> >>>>>>
> >>>>>> diff --git a/src/common/ust-consumer/ust-consumer.c b/src/common/ust-consumer/ust-consumer.c
> >>>>>> index 1170687..4ca4b84 100644
> >>>>>> --- a/src/common/ust-consumer/ust-consumer.c
> >>>>>> +++ b/src/common/ust-consumer/ust-consumer.c
> >>>>>> @@ -224,6 +224,18 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
> >>>>>> goto end_nosignal;
> >>>>>> }
> >>>>>>
> >>>>>> + /*
> >>>>>> + * This needs to be done as soon as we can so we don't block the
> >>>>>> + * application too long.
> >>>>>> + */
> >>>>>> + ret = lttng_ustconsumer_add_stream(new_stream);
> >>>>>> + if (ret) {
> >>>>>> + consumer_del_stream(new_stream, NULL);
> >>>>>> + goto end_nosignal;
> >>>>>> + }
> >>>>>> + /* Steal stream identifier to avoid having streams with the same key */
> >>>>>> + consumer_steal_stream_key(new_stream->key, consumer_data.stream_ht);
> >>>>>> +
> >>>>>> /* The stream is not metadata. Get relayd reference if exists. */
> >>>>>> relayd = consumer_find_relayd(msg.u.stream.net_index);
> >>>>>> if (relayd != NULL) {
> >>>>>> @@ -265,14 +277,12 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
> >>>>>> goto end_nosignal;
> >>>>>> }
> >>>>>> } else {
> >>>>>> - ret = consumer_add_stream(new_stream);
> >>>>>> - if (ret) {
> >>>>>> - ERR("Consumer add stream %d failed. Continuing",
> >>>>>> - new_stream->key);
> >>>>>> - /*
> >>>>>> - * At this point, if the add_stream fails, it is not in the
> >>>>>> - * hash table thus passing the NULL value here.
> >>>>>> - */
> >>>>>> + do {
> >>>>>> + ret = write(ctx->consumer_poll_pipe[1], &new_stream,
> >>>>>> + sizeof(new_stream));
> >>>>>> + } while (ret < 0 && errno == EINTR);
> >>>>>> + if (ret < 0) {
> >>>>>> + PERROR("write data pipe");
> >>>>>> consumer_del_stream(new_stream, NULL);
> >>>>>> goto end_nosignal;
> >>>>>> }
> >>>>>> @@ -334,20 +344,6 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
> >>>>>> break;
> >>>>>> }
> >>>>>>
> >>>>>> - /*
> >>>>>> - * Wake-up the other end by writing a null byte in the pipe (non-blocking).
> >>>>>> - * Important note: Because writing into the pipe is non-blocking (and
> >>>>>> - * therefore we allow dropping wakeup data, as long as there is wakeup data
> >>>>>> - * present in the pipe buffer to wake up the other end), the other end
> >>>>>> - * should perform the following sequence for waiting:
> >>>>>> - *
> >>>>>> - * 1) empty the pipe (reads).
> >>>>>> - * 2) perform update operation.
> >>>>>> - * 3) wait on the pipe (poll).
> >>>>>> - */
> >>>>>> - do {
> >>>>>> - ret = write(ctx->consumer_poll_pipe[1], "", 1);
> >>>>>> - } while (ret < 0 && errno == EINTR);
> >>>>>> end_nosignal:
> >>>>>> rcu_read_unlock();
> >>>>>>
> >>>>>> --
> >>>>>> 1.7.10.4
> >>>>>>
> >>>>>>
> >>>>>> _______________________________________________
> >>>>>> lttng-dev mailing list
> >>>>>> lttng-dev at lists.lttng.org
> >>>>>> http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
> >>>>>
> >>>
> >
--
Mathieu Desnoyers
Operating System Efficiency R&D Consultant
EfficiOS Inc.
http://www.efficios.com
^ permalink raw reply [flat|nested] 22+ messages in thread
* [lttng-dev] [PATCH lttng-tools 3/4] Make stream hash tables global to the consumer
2012-10-15 15:47 ` David Goulet
@ 2012-10-15 17:57 ` Mathieu Desnoyers
0 siblings, 0 replies; 22+ messages in thread
From: Mathieu Desnoyers @ 2012-10-15 17:57 UTC (permalink / raw)
* David Goulet (dgoulet at efficios.com) wrote:
>
>
> Mathieu Desnoyers:
> > * David Goulet (dgoulet at efficios.com) wrote:
> >> The data stream hash table is now global to the consumer and used in the
> >> data thread. The consumer_data stream_ht is no longer used to track the
> >> data streams but instead will be used (and possibly renamed) by the
> >> session daemon poll thread to keep track of streams on a per session id
> >> basis for the upcoming feature that check traced data availability.
> >>
> >> For now, in order to avoid mind bugging problems to access the streams,
> >> both hash table are now defined globally (metadata and data). However,
> >> stream update are still done in a single thread. Don't count on this to
> >> be guaranteed in the next commits.
> >>
> >> Signed-off-by: David Goulet <dgoulet at efficios.com>
> >> ---
> >> src/common/consumer.c | 91 +++++++++++++++++++++++++-------
> >> src/common/consumer.h | 9 ++--
> >> src/common/ust-consumer/ust-consumer.c | 2 -
> >> 3 files changed, 75 insertions(+), 27 deletions(-)
> >>
> >> diff --git a/src/common/consumer.c b/src/common/consumer.c
> >> index 1d2b1f7..1fb9960 100644
> >> --- a/src/common/consumer.c
> >> +++ b/src/common/consumer.c
> >> @@ -59,6 +59,17 @@ int consumer_poll_timeout = -1;
> >> volatile int consumer_quit = 0;
> >>
> >> /*
> >> + * The following two hash tables are visible by all threads which are separated
> >> + * in different source files.
> >> + *
> >> + * Global hash table containing respectively metadata and data streams. The
> >> + * stream element in this ht should only be updated by the metadata poll thread
> >> + * for the metadata and the data poll thread for the data.
> >> + */
> >> +struct lttng_ht *metadata_ht = NULL;
> >> +struct lttng_ht *data_ht = NULL;
> >> +
> >> +/*
> >> * Find a stream. The consumer_data.lock must be locked during this
> >> * call.
> >> */
> >> @@ -433,19 +444,24 @@ end:
> >> /*
> >> * Add a stream to the global list protected by a mutex.
> >> */
> >> -int consumer_add_stream(struct lttng_consumer_stream *stream)
> >> +static int consumer_add_stream(struct lttng_consumer_stream *stream,
> >> + struct lttng_ht *ht)
> >> {
> >> int ret = 0;
> >> struct consumer_relayd_sock_pair *relayd;
> >>
> >> assert(stream);
> >> + assert(ht);
> >>
> >> DBG3("Adding consumer stream %d", stream->key);
> >>
> >> pthread_mutex_lock(&consumer_data.lock);
> >> rcu_read_lock();
> >>
> >> - lttng_ht_add_unique_ulong(consumer_data.stream_ht, &stream->node);
> >> + /* Steal stream identifier to avoid having streams with the same key */
> >> + consumer_steal_stream_key(stream->key, ht);
> >
> > I don't understand why suddenly this change is needed. Considering what
> > this patch should be doing (just moving a ht from per-thread to global),
> > it should not have any behavior impact.
>
> We move the steal stream key from the sessiond thread to the add_stream
> function call since we do not use the consumer_data hash table anymore
> (stream_ht) and uses per thread hashtable (global for now though).
>
> If you look below, you'll see that the steal stream key call is removed
> (using the consumer data stream_ht).
>
> This commit makes sure that both consumer_add_stream and
> add_metadata_stream steal the stream key if needed.
ok, makes sense.
Thanks!
Mathieu
>
> Thanks
> David
>
> >
> > Thanks,
> >
> > Mathieu
> >
> >> +
> >> + lttng_ht_add_unique_ulong(ht, &stream->node);
> >>
> >> /* Check and cleanup relayd */
> >> relayd = consumer_find_relayd(stream->net_seq_idx);
> >> @@ -783,9 +799,9 @@ end:
> >> *
> >> * Returns the number of fds in the structures.
> >> */
> >> -int consumer_update_poll_array(
> >> +static int consumer_update_poll_array(
> >> struct lttng_consumer_local_data *ctx, struct pollfd **pollfd,
> >> - struct lttng_consumer_stream **local_stream)
> >> + struct lttng_consumer_stream **local_stream, struct lttng_ht *ht)
> >> {
> >> int i = 0;
> >> struct lttng_ht_iter iter;
> >> @@ -793,8 +809,7 @@ int consumer_update_poll_array(
> >>
> >> DBG("Updating poll fd array");
> >> rcu_read_lock();
> >> - cds_lfht_for_each_entry(consumer_data.stream_ht->ht, &iter.iter, stream,
> >> - node.node) {
> >> + cds_lfht_for_each_entry(ht->ht, &iter.iter, stream, node.node) {
> >> if (stream->state != LTTNG_CONSUMER_ACTIVE_STREAM) {
> >> continue;
> >> }
> >> @@ -1523,6 +1538,33 @@ int lttng_consumer_recv_cmd(struct lttng_consumer_local_data *ctx,
> >> /*
> >> * Iterate over all streams of the hashtable and free them properly.
> >> *
> >> + * WARNING: *MUST* be used with data stream only.
> >> + */
> >> +static void destroy_data_stream_ht(struct lttng_ht *ht)
> >> +{
> >> + int ret;
> >> + struct lttng_ht_iter iter;
> >> + struct lttng_consumer_stream *stream;
> >> +
> >> + if (ht == NULL) {
> >> + return;
> >> + }
> >> +
> >> + rcu_read_lock();
> >> + cds_lfht_for_each_entry(ht->ht, &iter.iter, stream, node.node) {
> >> + ret = lttng_ht_del(ht, &iter);
> >> + assert(!ret);
> >> +
> >> + call_rcu(&stream->node.head, consumer_free_stream);
> >> + }
> >> + rcu_read_unlock();
> >> +
> >> + lttng_ht_destroy(ht);
> >> +}
> >> +
> >> +/*
> >> + * Iterate over all streams of the hashtable and free them properly.
> >> + *
> >> * XXX: Should not be only for metadata stream or else use an other name.
> >> */
> >> static void destroy_stream_ht(struct lttng_ht *ht)
> >> @@ -1711,6 +1753,9 @@ static int consumer_add_metadata_stream(struct lttng_consumer_stream *stream,
> >> uatomic_dec(&stream->chan->nb_init_streams);
> >> }
> >>
> >> + /* Steal stream identifier to avoid having streams with the same key */
> >> + consumer_steal_stream_key(stream->key, ht);
> >> +
> >> lttng_ht_add_unique_ulong(ht, &stream->waitfd_node);
> >> rcu_read_unlock();
> >>
> >> @@ -1729,7 +1774,6 @@ void *consumer_thread_metadata_poll(void *data)
> >> struct lttng_consumer_stream *stream = NULL;
> >> struct lttng_ht_iter iter;
> >> struct lttng_ht_node_ulong *node;
> >> - struct lttng_ht *metadata_ht = NULL;
> >> struct lttng_poll_event events;
> >> struct lttng_consumer_local_data *ctx = data;
> >> ssize_t len;
> >> @@ -1738,11 +1782,6 @@ void *consumer_thread_metadata_poll(void *data)
> >>
> >> DBG("Thread metadata poll started");
> >>
> >> - metadata_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
> >> - if (metadata_ht == NULL) {
> >> - goto end;
> >> - }
> >> -
> >> /* Size is set to 1 for the consumer_metadata pipe */
> >> ret = lttng_poll_create(&events, 2, LTTNG_CLOEXEC);
> >> if (ret < 0) {
> >> @@ -1918,6 +1957,11 @@ void *consumer_thread_data_poll(void *data)
> >>
> >> rcu_register_thread();
> >>
> >> + data_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
> >> + if (data_ht == NULL) {
> >> + goto end;
> >> + }
> >> +
> >> local_stream = zmalloc(sizeof(struct lttng_consumer_stream));
> >>
> >> while (1) {
> >> @@ -1955,7 +1999,8 @@ void *consumer_thread_data_poll(void *data)
> >> pthread_mutex_unlock(&consumer_data.lock);
> >> goto end;
> >> }
> >> - ret = consumer_update_poll_array(ctx, &pollfd, local_stream);
> >> + ret = consumer_update_poll_array(ctx, &pollfd, local_stream,
> >> + data_ht);
> >> if (ret < 0) {
> >> ERR("Error in allocating pollfd or local_outfds");
> >> lttng_consumer_send_error(ctx, LTTCOMM_CONSUMERD_POLL_ERROR);
> >> @@ -2015,7 +2060,7 @@ void *consumer_thread_data_poll(void *data)
> >> continue;
> >> }
> >>
> >> - ret = consumer_add_stream(new_stream);
> >> + ret = consumer_add_stream(new_stream, data_ht);
> >> if (ret) {
> >> ERR("Consumer add stream %d failed. Continuing",
> >> new_stream->key);
> >> @@ -2088,22 +2133,19 @@ void *consumer_thread_data_poll(void *data)
> >> if ((pollfd[i].revents & POLLHUP)) {
> >> DBG("Polling fd %d tells it has hung up.", pollfd[i].fd);
> >> if (!local_stream[i]->data_read) {
> >> - consumer_del_stream(local_stream[i],
> >> - consumer_data.stream_ht);
> >> + consumer_del_stream(local_stream[i], data_ht);
> >> num_hup++;
> >> }
> >> } else if (pollfd[i].revents & POLLERR) {
> >> ERR("Error returned in polling fd %d.", pollfd[i].fd);
> >> if (!local_stream[i]->data_read) {
> >> - consumer_del_stream(local_stream[i],
> >> - consumer_data.stream_ht);
> >> + consumer_del_stream(local_stream[i], data_ht);
> >> num_hup++;
> >> }
> >> } else if (pollfd[i].revents & POLLNVAL) {
> >> ERR("Polling fd %d tells fd is not open.", pollfd[i].fd);
> >> if (!local_stream[i]->data_read) {
> >> - consumer_del_stream(local_stream[i],
> >> - consumer_data.stream_ht);
> >> + consumer_del_stream(local_stream[i], data_ht);
> >> num_hup++;
> >> }
> >> }
> >> @@ -2131,6 +2173,10 @@ end:
> >> */
> >> close(ctx->consumer_metadata_pipe[1]);
> >>
> >> + if (data_ht) {
> >> + destroy_data_stream_ht(data_ht);
> >> + }
> >> +
> >> rcu_unregister_thread();
> >> return NULL;
> >> }
> >> @@ -2299,6 +2345,11 @@ void lttng_consumer_init(void)
> >> consumer_data.stream_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
> >> consumer_data.channel_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
> >> consumer_data.relayd_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
> >> +
> >> + metadata_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
> >> + assert(metadata_ht);
> >> + data_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
> >> + assert(data_ht);
> >> }
> >>
> >> /*
> >> diff --git a/src/common/consumer.h b/src/common/consumer.h
> >> index 8e5891a..6bce96d 100644
> >> --- a/src/common/consumer.h
> >> +++ b/src/common/consumer.h
> >> @@ -275,6 +275,10 @@ struct lttng_consumer_global_data {
> >> struct lttng_ht *relayd_ht;
> >> };
> >>
> >> +/* Defined in consumer.c and coupled with explanations */
> >> +extern struct lttng_ht *metadata_ht;
> >> +extern struct lttng_ht *data_ht;
> >> +
> >> /*
> >> * Init consumer data structures.
> >> */
> >> @@ -324,10 +328,6 @@ extern void lttng_consumer_sync_trace_file(
> >> */
> >> extern int lttng_consumer_poll_socket(struct pollfd *kconsumer_sockpoll);
> >>
> >> -extern int consumer_update_poll_array(
> >> - struct lttng_consumer_local_data *ctx, struct pollfd **pollfd,
> >> - struct lttng_consumer_stream **local_consumer_streams);
> >> -
> >> extern struct lttng_consumer_stream *consumer_allocate_stream(
> >> int channel_key, int stream_key,
> >> int shm_fd, int wait_fd,
> >> @@ -340,7 +340,6 @@ extern struct lttng_consumer_stream *consumer_allocate_stream(
> >> int net_index,
> >> int metadata_flag,
> >> int *alloc_ret);
> >> -extern int consumer_add_stream(struct lttng_consumer_stream *stream);
> >> extern void consumer_del_stream(struct lttng_consumer_stream *stream,
> >> struct lttng_ht *ht);
> >> extern void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
> >> diff --git a/src/common/ust-consumer/ust-consumer.c b/src/common/ust-consumer/ust-consumer.c
> >> index 4ca4b84..3b41e55 100644
> >> --- a/src/common/ust-consumer/ust-consumer.c
> >> +++ b/src/common/ust-consumer/ust-consumer.c
> >> @@ -233,8 +233,6 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
> >> consumer_del_stream(new_stream, NULL);
> >> goto end_nosignal;
> >> }
> >> - /* Steal stream identifier to avoid having streams with the same key */
> >> - consumer_steal_stream_key(new_stream->key, consumer_data.stream_ht);
> >>
> >> /* The stream is not metadata. Get relayd reference if exists. */
> >> relayd = consumer_find_relayd(msg.u.stream.net_index);
> >> --
> >> 1.7.10.4
> >>
> >>
> >> _______________________________________________
> >> lttng-dev mailing list
> >> lttng-dev at lists.lttng.org
> >> http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
> >
--
Mathieu Desnoyers
Operating System Efficiency R&D Consultant
EfficiOS Inc.
http://www.efficios.com
^ permalink raw reply [flat|nested] 22+ messages in thread
* [lttng-dev] [PATCH lttng-tools 4/4] Change the metadata hash table node
2012-10-13 16:00 ` Mathieu Desnoyers
@ 2012-10-15 19:22 ` David Goulet
0 siblings, 0 replies; 22+ messages in thread
From: David Goulet @ 2012-10-15 19:22 UTC (permalink / raw)
Oh forgot to reply :P
Yes... my bad. Present... the patch does what's described :)
David
Mathieu Desnoyers:
> * David Goulet (dgoulet at efficios.com) wrote:
>> Remove the use of the "waitfd_node" for metadata and index the "node" by
>> wait fd during stream allocation only for metadata stream.
>>
>> This was done so the waitfd node could be used later on for the hash
>> table indexing stream by session id the traced data check command (soon
>> to be implemented).
>
> this last changelog paragraph, being using "was" (past) is confusing me.
> Is it what you are now doing (present) or what was there before that you
> are changing ?
>
> Thanks,
>
> Mathieu
>
>>
>> Signed-off-by: David Goulet <dgoulet at efficios.com>
>> ---
>> src/common/consumer.c | 36 +++++++++++++++++-------------------
>> 1 file changed, 17 insertions(+), 19 deletions(-)
>>
>> diff --git a/src/common/consumer.c b/src/common/consumer.c
>> index 1fb9960..0c1a812 100644
>> --- a/src/common/consumer.c
>> +++ b/src/common/consumer.c
>> @@ -172,17 +172,6 @@ void consumer_free_stream(struct rcu_head *head)
>> free(stream);
>> }
>>
>> -static
>> -void consumer_free_metadata_stream(struct rcu_head *head)
>> -{
>> - struct lttng_ht_node_ulong *node =
>> - caa_container_of(head, struct lttng_ht_node_ulong, head);
>> - struct lttng_consumer_stream *stream =
>> - caa_container_of(node, struct lttng_consumer_stream, waitfd_node);
>> -
>> - free(stream);
>> -}
>> -
>> /*
>> * RCU protected relayd socket pair free.
>> */
>> @@ -417,8 +406,17 @@ struct lttng_consumer_stream *consumer_allocate_stream(
>> stream->metadata_flag = metadata_flag;
>> strncpy(stream->path_name, path_name, sizeof(stream->path_name));
>> stream->path_name[sizeof(stream->path_name) - 1] = '\0';
>> - lttng_ht_node_init_ulong(&stream->waitfd_node, stream->wait_fd);
>> - lttng_ht_node_init_ulong(&stream->node, stream->key);
>> +
>> + /*
>> + * Index differently the metadata node because the thread is using an
>> + * internal hash table to match streams in the metadata_ht to the epoll set
>> + * file descriptor.
>> + */
>> + if (metadata_flag) {
>> + lttng_ht_node_init_ulong(&stream->node, stream->wait_fd);
>> + } else {
>> + lttng_ht_node_init_ulong(&stream->node, stream->key);
>> + }
>>
>> /*
>> * The cpu number is needed before using any ustctl_* actions. Ignored for
>> @@ -1578,11 +1576,11 @@ static void destroy_stream_ht(struct lttng_ht *ht)
>> }
>>
>> rcu_read_lock();
>> - cds_lfht_for_each_entry(ht->ht, &iter.iter, stream, waitfd_node.node) {
>> + cds_lfht_for_each_entry(ht->ht, &iter.iter, stream, node.node) {
>> ret = lttng_ht_del(ht, &iter);
>> assert(!ret);
>>
>> - call_rcu(&stream->waitfd_node.head, consumer_free_metadata_stream);
>> + call_rcu(&stream->node.head, consumer_free_stream);
>> }
>> rcu_read_unlock();
>>
>> @@ -1636,7 +1634,7 @@ void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
>> }
>>
>> rcu_read_lock();
>> - iter.iter.node = &stream->waitfd_node.node;
>> + iter.iter.node = &stream->node.node;
>> ret = lttng_ht_del(ht, &iter);
>> assert(!ret);
>> rcu_read_unlock();
>> @@ -1707,7 +1705,7 @@ end:
>> }
>>
>> free_stream:
>> - call_rcu(&stream->waitfd_node.head, consumer_free_metadata_stream);
>> + call_rcu(&stream->node.head, consumer_free_stream);
>> }
>>
>> /*
>> @@ -1756,7 +1754,7 @@ static int consumer_add_metadata_stream(struct lttng_consumer_stream *stream,
>> /* Steal stream identifier to avoid having streams with the same key */
>> consumer_steal_stream_key(stream->key, ht);
>>
>> - lttng_ht_add_unique_ulong(ht, &stream->waitfd_node);
>> + lttng_ht_add_unique_ulong(ht, &stream->node);
>> rcu_read_unlock();
>>
>> pthread_mutex_unlock(&consumer_data.lock);
>> @@ -1881,7 +1879,7 @@ restart:
>> assert(node);
>>
>> stream = caa_container_of(node, struct lttng_consumer_stream,
>> - waitfd_node);
>> + node);
>>
>> /* Check for error event */
>> if (revents & (LPOLLERR | LPOLLHUP)) {
>> --
>> 1.7.10.4
>>
>>
>> _______________________________________________
>> lttng-dev mailing list
>> lttng-dev at lists.lttng.org
>> http://lists.lttng.org/cgi-bin/mailman/listinfo/lttng-dev
>
^ permalink raw reply [flat|nested] 22+ messages in thread
end of thread, other threads:[~2012-10-15 19:22 UTC | newest]
Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-10-12 14:30 [lttng-dev] [PATCH lttng-tools 1/4] Rename consumer threads and spawn them in daemon David Goulet
2012-10-12 14:30 ` [lttng-dev] [PATCH lttng-tools 2/4] Move add data stream to the data thread David Goulet
2012-10-13 15:53 ` Mathieu Desnoyers
2012-10-15 15:40 ` David Goulet
2012-10-15 17:31 ` Mathieu Desnoyers
2012-10-15 17:40 ` David Goulet
2012-10-15 17:42 ` Mathieu Desnoyers
2012-10-15 17:45 ` David Goulet
2012-10-15 17:56 ` Mathieu Desnoyers
2012-10-12 14:30 ` [lttng-dev] [PATCH lttng-tools 3/4] Make stream hash tables global to the consumer David Goulet
2012-10-13 15:56 ` Mathieu Desnoyers
2012-10-15 15:47 ` David Goulet
2012-10-15 17:57 ` Mathieu Desnoyers
2012-10-12 14:30 ` [lttng-dev] [PATCH lttng-tools 4/4] Change the metadata hash table node David Goulet
2012-10-13 16:00 ` Mathieu Desnoyers
2012-10-15 19:22 ` David Goulet
2012-10-13 15:41 ` [lttng-dev] [PATCH lttng-tools 1/4] Rename consumer threads and spawn them in daemon Mathieu Desnoyers
2012-10-15 15:39 ` David Goulet
2012-10-15 17:28 ` Mathieu Desnoyers
2012-10-15 17:37 ` David Goulet
2012-10-15 17:39 ` Mathieu Desnoyers
2012-10-15 17:42 ` David Goulet
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox