util/log: add auto logger facility
authorNicolai Hähnle <nicolai.haehnle@amd.com>
Tue, 15 Aug 2017 13:15:47 +0000 (15:15 +0200)
committerNicolai Hähnle <nicolai.haehnle@amd.com>
Tue, 22 Aug 2017 07:50:40 +0000 (09:50 +0200)
Reviewed-by: Marek Olšák <marek.olsak@amd.com>
src/gallium/auxiliary/util/u_log.c
src/gallium/auxiliary/util/u_log.h

index 6d826f0addae605182840a53721b2194598dc294..359b3e10a2e23c542205e90bd7efcd58267bdf7f 100644 (file)
@@ -36,13 +36,18 @@ struct u_log_page {
    unsigned max_entries;
 };
 
+struct u_log_auto_logger {
+   u_auto_log_fn *callback;
+   void *data;
+};
+
 /**
  * Initialize the given logging context.
  */
 void
 u_log_context_init(struct u_log_context *ctx)
 {
-   ctx->cur = NULL;
+   memset(ctx, 0, sizeof(*ctx));
 }
 
 /**
@@ -55,7 +60,56 @@ void
 u_log_context_destroy(struct u_log_context *ctx)
 {
    u_log_page_destroy(ctx->cur);
-   ctx->cur = NULL;
+   FREE(ctx->auto_loggers);
+   memset(ctx, 0, sizeof(*ctx));
+}
+
+/**
+ * Add an auto logger.
+ *
+ * Auto loggers are called each time a chunk is added to the log.
+ */
+void
+u_log_add_auto_logger(struct u_log_context *ctx, u_auto_log_fn *callback,
+                      void *data)
+{
+   struct u_log_auto_logger *new_auto_loggers =
+      REALLOC(ctx->auto_loggers,
+              sizeof(*new_auto_loggers) * ctx->num_auto_loggers,
+              sizeof(*new_auto_loggers) * (ctx->num_auto_loggers + 1));
+   if (!new_auto_loggers) {
+      fprintf(stderr, "Gallium u_log: out of memory\n");
+      return;
+   }
+
+   unsigned idx = ctx->num_auto_loggers++;
+   ctx->auto_loggers = new_auto_loggers;
+   ctx->auto_loggers[idx].callback = callback;
+   ctx->auto_loggers[idx].data = data;
+}
+
+/**
+ * Make sure that auto loggers have run.
+ */
+void
+u_log_flush(struct u_log_context *ctx)
+{
+   if (!ctx->num_auto_loggers)
+      return;
+
+   struct u_log_auto_logger *auto_loggers = ctx->auto_loggers;
+   unsigned num_auto_loggers = ctx->num_auto_loggers;
+
+   /* Prevent recursion. */
+   ctx->num_auto_loggers = 0;
+   ctx->auto_loggers = NULL;
+
+   for (unsigned i = 0; i < num_auto_loggers; ++i)
+      auto_loggers[i].callback(auto_loggers[i].data, ctx);
+
+   assert(!ctx->num_auto_loggers);
+   ctx->num_auto_loggers = num_auto_loggers;
+   ctx->auto_loggers = auto_loggers;
 }
 
 static void str_print(void *data, FILE *stream)
@@ -96,6 +150,8 @@ u_log_chunk(struct u_log_context *ctx, const struct u_log_chunk_type *type,
 {
    struct u_log_page *page = ctx->cur;
 
+   u_log_flush(ctx);
+
    if (!page) {
       ctx->cur = CALLOC_STRUCT(u_log_page);
       page = ctx->cur;
index d4e6018c9f700ea6546a26e6150e923665338d2a..09c47caee557c5b2abbcfd6173300497b2673333 100644 (file)
  *
  * Chunks are accumulated into "pages". The manager of the log can periodically
  * take out the current page using \ref u_log_new_page and dump it to a file.
+ *
+ * Furthermore, "auto loggers" can be added to a context, which are callbacks
+ * that are given the opportunity to add their own logging each time a chunk is
+ * added. Drivers can use this to lazily log chunks of their command stream.
+ * Lazy loggers don't need to be re-entrant.
  */
 
 #ifndef U_LOG_H
@@ -45,6 +50,7 @@
 #include "u_debug.h"
 
 struct u_log_page;
+struct u_log_auto_logger;
 
 struct u_log_chunk_type {
    void (*destroy)(void *data);
@@ -53,14 +59,25 @@ struct u_log_chunk_type {
 
 struct u_log_context {
    struct u_log_page *cur;
+   struct u_log_auto_logger *auto_loggers;
+   unsigned num_auto_loggers;
 };
 
+typedef void (u_auto_log_fn)(void *data, struct u_log_context *ctx);
+
 void
 u_log_context_init(struct u_log_context *ctx);
 
 void
 u_log_context_destroy(struct u_log_context *ctx);
 
+void
+u_log_add_auto_logger(struct u_log_context *ctx, u_auto_log_fn *callback,
+                      void *data);
+
+void
+u_log_flush(struct u_log_context *ctx);
+
 void
 u_log_printf(struct u_log_context *ctx, const char *fmt, ...) _util_printf_format(2,3);