From: Nicolai Hähnle Date: Tue, 15 Aug 2017 13:15:47 +0000 (+0200) Subject: util/log: add auto logger facility X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=177144cefc83f3670d46418c1e401d3f27e2d33e;p=mesa.git util/log: add auto logger facility Reviewed-by: Marek Olšák --- diff --git a/src/gallium/auxiliary/util/u_log.c b/src/gallium/auxiliary/util/u_log.c index 6d826f0adda..359b3e10a2e 100644 --- a/src/gallium/auxiliary/util/u_log.c +++ b/src/gallium/auxiliary/util/u_log.c @@ -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; diff --git a/src/gallium/auxiliary/util/u_log.h b/src/gallium/auxiliary/util/u_log.h index d4e6018c9f7..09c47caee55 100644 --- a/src/gallium/auxiliary/util/u_log.h +++ b/src/gallium/auxiliary/util/u_log.h @@ -35,6 +35,11 @@ * * 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);