From 1cc2fd57d1def9f191a3479628497743d670e02d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Nicolai=20H=C3=A4hnle?= Date: Fri, 4 Aug 2017 15:31:46 +0200 Subject: [PATCH] util: add chunk logging module MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Reviewed-by: Marek Olšák --- src/gallium/auxiliary/Makefile.sources | 2 + src/gallium/auxiliary/util/u_log.c | 178 +++++++++++++++++++++++++ src/gallium/auxiliary/util/u_log.h | 83 ++++++++++++ 3 files changed, 263 insertions(+) create mode 100644 src/gallium/auxiliary/util/u_log.c create mode 100644 src/gallium/auxiliary/util/u_log.h diff --git a/src/gallium/auxiliary/Makefile.sources b/src/gallium/auxiliary/Makefile.sources index 9ae8e6c8ca5..2adc60ca657 100644 --- a/src/gallium/auxiliary/Makefile.sources +++ b/src/gallium/auxiliary/Makefile.sources @@ -260,6 +260,8 @@ C_SOURCES := \ util/u_keymap.h \ util/u_linear.c \ util/u_linear.h \ + util/u_log.c \ + util/u_log.h \ util/u_math.c \ util/u_math.h \ util/u_memory.h \ diff --git a/src/gallium/auxiliary/util/u_log.c b/src/gallium/auxiliary/util/u_log.c new file mode 100644 index 00000000000..6d826f0adda --- /dev/null +++ b/src/gallium/auxiliary/util/u_log.c @@ -0,0 +1,178 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "u_log.h" + +#include "u_memory.h" + +struct page_entry { + const struct u_log_chunk_type *type; + void *data; +}; + +struct u_log_page { + struct page_entry *entries; + unsigned num_entries; + unsigned max_entries; +}; + +/** + * Initialize the given logging context. + */ +void +u_log_context_init(struct u_log_context *ctx) +{ + ctx->cur = NULL; +} + +/** + * Free all resources associated with the given logging context. + * + * Pages taken from the context via \ref u_log_new_page must be destroyed + * separately. + */ +void +u_log_context_destroy(struct u_log_context *ctx) +{ + u_log_page_destroy(ctx->cur); + ctx->cur = NULL; +} + +static void str_print(void *data, FILE *stream) +{ + fputs((char *)data, stream); +} + +static const struct u_log_chunk_type str_chunk_type = { + .destroy = free, + .print = str_print, +}; + +void +u_log_printf(struct u_log_context *ctx, const char *fmt, ...) +{ + va_list va; + char *str = NULL; + + va_start(va, fmt); + int ret = vasprintf(&str, fmt, va); + va_end(va); + + if (ret >= 0) { + u_log_chunk(ctx, &str_chunk_type, str); + } else { + fprintf(stderr, "Gallium u_log_printf: out of memory\n"); + } +} + +/** + * Add a custom chunk to the log. + * + * type->destroy will be called as soon as \p data is no longer needed. + */ +void +u_log_chunk(struct u_log_context *ctx, const struct u_log_chunk_type *type, + void *data) +{ + struct u_log_page *page = ctx->cur; + + if (!page) { + ctx->cur = CALLOC_STRUCT(u_log_page); + page = ctx->cur; + if (!page) + goto out_of_memory; + } + + if (page->num_entries >= page->max_entries) { + unsigned new_max_entries = MAX2(16, page->num_entries * 2); + struct page_entry *new_entries = REALLOC(page->entries, + page->max_entries * sizeof(*page->entries), + new_max_entries * sizeof(*page->entries)); + if (!new_entries) + goto out_of_memory; + + page->entries = new_entries; + page->max_entries = new_max_entries; + } + + page->entries[page->num_entries].type = type; + page->entries[page->num_entries].data = data; + page->num_entries++; + return; + +out_of_memory: + fprintf(stderr, "Gallium: u_log: out of memory\n"); +} + +/** + * Convenience helper that starts a new page and prints the previous one. + */ +void +u_log_new_page_print(struct u_log_context *ctx, FILE *stream) +{ + if (ctx->cur) { + u_log_page_print(ctx->cur, stream); + u_log_page_destroy(ctx->cur); + ctx->cur = NULL; + } +} + +/** + * Return the current page from the logging context and start a new one. + * + * The caller is responsible for destroying the returned page. + */ +struct u_log_page * +u_log_new_page(struct u_log_context *ctx) +{ + struct u_log_page *page = ctx->cur; + ctx->cur = NULL; + return page; +} + +/** + * Free all data associated with \p page. + */ +void +u_log_page_destroy(struct u_log_page *page) +{ + if (!page) + return; + + for (unsigned i = 0; i < page->num_entries; ++i) { + if (page->entries[i].type->destroy) + page->entries[i].type->destroy(page->entries[i].data); + } + FREE(page->entries); + FREE(page); +} + +/** + * Print the given page to \p stream. + */ +void +u_log_page_print(struct u_log_page *page, FILE *stream) +{ + for (unsigned i = 0; i < page->num_entries; ++i) + page->entries[i].type->print(page->entries[i].data, stream); +} diff --git a/src/gallium/auxiliary/util/u_log.h b/src/gallium/auxiliary/util/u_log.h new file mode 100644 index 00000000000..d4e6018c9f7 --- /dev/null +++ b/src/gallium/auxiliary/util/u_log.h @@ -0,0 +1,83 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @file u_log.h + * @brief Context logging facilities + * + * Provides a means of logging context events (draw calls, command streams, ...) + * into files. + * + * Log entries start their life cycle as "chunks". Chunks can be plain text + * written by \ref u_log_printf or custom internal representations added by + * \ref u_log_chunk that are only converted to text on-demand (e.g. for higher + * performance pipelined hang-debugging). + * + * 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. + */ + +#ifndef U_LOG_H +#define U_LOG_H + +#include + +#include "u_debug.h" + +struct u_log_page; + +struct u_log_chunk_type { + void (*destroy)(void *data); + void (*print)(void *data, FILE *stream); +}; + +struct u_log_context { + struct u_log_page *cur; +}; + +void +u_log_context_init(struct u_log_context *ctx); + +void +u_log_context_destroy(struct u_log_context *ctx); + +void +u_log_printf(struct u_log_context *ctx, const char *fmt, ...) _util_printf_format(2,3); + +void +u_log_chunk(struct u_log_context *ctx, const struct u_log_chunk_type *type, + void *data); + +void +u_log_new_page_print(struct u_log_context *ctx, FILE *stream); + +struct u_log_page * +u_log_new_page(struct u_log_context *ctx); + +void +u_log_page_destroy(struct u_log_page *page); + +void +u_log_page_print(struct u_log_page *page, FILE *stream); + +#endif /* U_LOG_H */ -- 2.30.2