#ifndef lib_trace_h #define lib_trace_h /* Cesar project {{{ * * Copyright (C) 2007 Spidcom * * <<>> * * }}} */ /** * \file lib/trace.h * \brief Trace system. * \ingroup lib * * The trace system provides an events recording system. It is coupled with * the dynamic allocation system in order to use all the available memory for * trace buffers. */ #include "config/trace.h" #if CONFIG_TRACE #include "lib/blk.h" #include "lib/list.h" /** Useful to initialise a trace_event_id_t. */ #define TRACE_EVENT(id, format_string_, options...) \ [(id)] = { .format_string = (format_string_) \ PREPROC_FOR_EACH (TRACE_EVENT_OPTIONS_, options) } #define TRACE_EVENT_OPTIONS_(option) , PASTE (TRACE_EVENT_OPTIONS_, option) #define TRACE_EVENT_OPTIONS_TIMESTAMP .timestamp = true /** Could be used to define tracing shortcut. * \param prefix text to prepend to id symbol * \param buffer trace buffer * \param id event id postfix part * \param args optional arguments * * This macro will count its arguments, call the right trace function and cast * each arguments to an integer. */ #define TRACE_SHORT(prefix, buffer, id, args...) \ PASTE_EXPAND (trace_print, PREPROC_NARG (args)) \ ((buffer), PREPROC_FOR_EACH_COMMA (TRACE_SHORT_CAST, \ PASTE (prefix, id), ## args)) #define TRACE_SHORT_CAST(x) ((int) (x)) /** Could be used to define tracing shortcut for fast traces. * See TRACE_SHORT. */ #define TRACE_FAST_SHORT(prefix, buffer, id, args...) \ PASTE_EXPAND (trace_fast_print, PREPROC_NARG (args)) \ ((buffer), PREPROC_FOR_EACH_COMMA (TRACE_SHORT_CAST, \ PASTE (prefix, id), ## args)) /** Split a 64 bit parameter in two parameters, lsb first. Will evaluate the * argument two times. */ #define TRACE_U64(dw) \ ((u32) ((dw) & 0xffffffff)), ((u32) ((dw) >> 32)) /** Could be used to define tracing shortcut for n arguments. * \param prefix text to prepend to id symbol * \param buffer trace buffer * \param id event id postfix part * \param args arguments array * \param nb_args number of arguments */ #define TRACE_N_SHORT(prefix, buffer, id, args, nb_args) \ trace_printn ((buffer), PASTE (prefix, id), (args), (nb_args)) /** Could be used to define tracing shortcut for fast traces for n arguments. * \param prefix text to prepend to id symbol * \param buffer trace buffer * \param id event id postfix part * \param args arguments array * \param nb_args number of arguments */ #define TRACE_FAST_N_SHORT(prefix, buffer, id, args, nb_args) \ trace_fast_printn ((buffer), PASTE (prefix, id), (args), (nb_args)) /** * Compile something only when trace is activated. * \param smth the thing conditionally compiled */ #define trace_do(smth) smth /* Forward declarations. */ typedef struct trace_t trace_t; typedef struct trace_buffer_t trace_buffer_t; typedef struct trace_chunk_t trace_chunk_t; typedef struct trace_buffer_bare_t trace_buffer_bare_t; typedef struct trace_namespace_t trace_namespace_t; /** Trace buffer context. */ struct trace_buffer_t { /** List node in trace context. */ list_node_t node; /** Number of chunks. */ uint chunks_nb; /** Drop policy level, 0-31. See trace_drop_chunks(). */ uint drop_level; /** Reserved chunks, there will be always at least that much chunks in * this buffer. Theses extra buffers can be used to write events without * allocating new chunks. */ uint preload; /** Is this buffer locked? Locked buffers can not lose chunks. */ bool locked; /** Pointer to head (older) chunk descriptor in this buffer. */ trace_chunk_t *head; /** Pointer to tail (newer, current) chunk descriptor in this buffer. */ trace_chunk_t *tail; /** Pointer to the bare trace buffer data if not a regular trace * buffer. */ trace_buffer_bare_t *bare; /** Trace buffer name. */ const char *name; /** Name space used for text dump. */ trace_namespace_t *namespace; }; /** Trace buffer chunk descriptor. */ struct trace_chunk_t { /** Next (newer) chunk in this trace buffer. */ trace_chunk_t *next; /** Data in this chunk. */ u32 *data; /** Number of committed words in this chunk. */ uint commit_index; /** Number of reserved words in this chunk. */ uint tail_index; }; /** Bare trace buffer, for use in assembly sources. * * This is a simplified circular buffer: trace events are written after * data_tail and it is then incremented, modulo the buffer size. Head is * considered to start right after data_tail. * * There is no resynchronisation yet in the dump code, therefore, trace buffer * should have a size multiple of the event size which should be the same for * all events. */ struct trace_buffer_bare_t { /** Tail pointer, where data gets written. */ u32 *data_tail; /** End address of the circular buffer. */ u32 *data_end; /** Base address of the circular buffer. */ u32 *data; }; /** * Callback for trace formating. * \param text text buffer to write to * \param text_size text buffer size * \param data data to format * \return number of characters written, or -1 for error * * This callback is not supposed to append any trailing new line or null * character. * * Note that the return value can not be used to know how many characters * would have been necessary. */ typedef int (*trace_format_u32_t) (char *text, uint text_size, int data); /** * Callback for trace formating, 64 bit version. * \param text text buffer to write to * \param text_size text buffer size * \param data data to format * \return number of characters written, or -1 for error * * This callback is not supposed to append any trailing new line or null * character. * * Note that the return value can not be used to know how many characters * would have been necessary. */ typedef int (*trace_format_u64_t) (char *text, uint text_size, u64 data); /** * Callback for trace formating, table version. * \param text text buffer to write to * \param text_size text buffer size * \param data data to format * \param data_size number of data word * \return number of characters written, or -1 for error * * This callback is not supposed to append any trailing new line or null * character. * * Note that the return value can not be used to know how many characters * would have been necessary. */ typedef int (*trace_format_table_t) (char *text, uint text_size, const int *data, uint data_size); /** Trace event id. */ struct trace_event_id_t { /** Associated format string. */ const char *format_string; /** Is the first parameter a timestamp? */ bool timestamp; }; typedef struct trace_event_id_t trace_event_id_t; /** Trace arguments formatting. */ struct trace_format_t { /** Number of used parameters. */ uint size; /** Formatting callback. */ union { /** 32 bit version. */ trace_format_u32_t format_u32; /** 64 bit version. */ trace_format_u64_t format_u64; /** Table version. */ trace_format_table_t format_table; } callback; }; typedef struct trace_format_t trace_format_t; /** Trace name space. Provides information to dump a trace buffer as text. */ struct trace_namespace_t { /** Map an event identifier to its format string. */ const trace_event_id_t *event_ids; /** Number of registered events. */ uint event_ids_nb; /** Map a format letter to its formatting callback. */ trace_format_t formats['z' - 'A' + 1]; }; /** * Callback for text dump. * \param user user parameter * \param text text buffer with text to write * \param text_size size of text to write, i.e. number of characters * \return should return size, any other value will stop dump */ typedef int (*trace_dump_callback_t) (void *user, const char *text, uint text_size); BEGIN_DECLS /** * Initialise the trace system. */ void trace_init (void); /** * Uninitialise the trace system. */ void trace_uninit (void); /** * Try to drop chunks in order to release memory. * \param n number of chunk to release * \return false if no more memory can be released * * The trace system is supposed to use all the remaining memory of the system. * However, its priority is of course lesser than other modules. When there * is a memory starvation, the allocator call this method to ask the trace * module to release memory. * * As there is several different trace buffers, the question is now to decide * which trace buffer should drop data. All trace buffers share the remaining * memory, but some buffers can use more memory than others. This is * represented by the drop_level parameter. Each trace buffer will have its * memory part divided by 2^drop_level. This means that a trace buffer with * drop_level = 0 will use twice as much memory than a trace buffer with * drop_level = 1, and so on... * * The preload parameter defines a number of reserved trace chunks which do * not count towards this sharing system. * * Note that the blocks are released, not freed. This means that if some * chunks are referenced by another component, this function can free less * memory than expected. */ bool trace_drop_chunks (uint n); /** * Initialise a name space and fill default formats. * \param ns name space to initialise * \param event_ids table of event id * \param event_ids_nb number of event id in the table */ void trace_namespace_init (trace_namespace_t *ns, const trace_event_id_t *event_ids, uint event_ids_nb); /** * Register a format code. * \param ns the name space * \param code the assigned code * \param format the formating callback */ void trace_namespace_register_format (trace_namespace_t *ns, char code, trace_format_u32_t format); /** * Register a format code for u64 parameters. * \param ns the name space * \param code the assigned code * \param format the formating callback */ void trace_namespace_register_format_u64 (trace_namespace_t *ns, char code, trace_format_u64_t format); /** * Register a format code for table parameters. * \param ns the name space * \param code the assigned code * \param format the formating callback * \param size table size */ void trace_namespace_register_format_table (trace_namespace_t *ns, char code, trace_format_table_t format, uint size); /** * Add a new trace buffer. * \param buf the uninitialised buffer structure to add * \param name buffer name * \param drop_level the buffer drop_level (see trace_drop_chunks()) * \param preload the buffer preload, this many chunks are allocated * immediately (minimum 1) * \param locked the buffer will not participate in the remaining memory * sharing, use for real time trace buffers * \param namespace name space for trace text dump */ void trace_buffer_add (trace_buffer_t *buf, const char *name, uint drop_level, uint preload, bool locked, trace_namespace_t *namespace); /** * Add a new bare trace buffer. * \param buf the uninitialised buffer structure to add * \param name buffer name * \param bare bare buffer structure * \param data pointer to buffer * \param size buffer size in words * \param namespace name space for trace text dump */ void trace_buffer_add_bare (trace_buffer_t *buf, const char *name, trace_buffer_bare_t *bare, u32 *data, uint size, trace_namespace_t *namespace); /** * Remove a trace buffer and release used memory. * \param buf the buffer to remove */ void trace_buffer_remove (trace_buffer_t *buf); /** * Get a trace buffer by its name. * \param name trace buffer name * \return found trace buffer or NULL */ trace_buffer_t * trace_buffer_get (const char *name); /** * Dump a full trace buffer as text. * \param buf trace buffer * \param cb callback called several times with text data * \param user user data passed to the callback * \return number of character written or -1 on any error (if one callback * did not return its size parameter) */ int trace_buffer_dump (trace_buffer_t *buf, trace_dump_callback_t cb, void *user); /** * Start a text trace bundle. * \param name bundle name, may be NULL for no name * \param cb callback called several times with text data * \param user user data passed to the callback * \return number of character written or -1 on any error (if one callback * did not return its size parameter) */ int trace_bundle_start (const char *name, trace_dump_callback_t cb, void *user); /** * Stop a text trace bundle. * \param cb callback called several times with text data * \param user user data passed to the callback * \return number of character written or -1 on any error (if one callback * did not return its size parameter) */ int trace_bundle_stop (trace_dump_callback_t cb, void *user); /** * Dump all trace buffers as a text trace bundle. * \param name bundle name, may be NULL for no name * \param cb callback called several times with text data * \param user user data passed to the callback * \return number of character written or -1 on any error (if one callback * did not return its size parameter) */ int trace_bundle_dump_all (const char *name, trace_dump_callback_t cb, void *user); /** * Dump a full trace buffer as text during debug. * \param buf trace buffer * * This can be useful to dump a trace buffer from a debugger. */ void trace_buffer_dbg_dump (trace_buffer_t *buf); /** * Dump all trace buffer as a text bundle during debug. */ void trace_dbg_dump_all (void); /** * Write event to trace buffer. * \param buf the trace buffer to write to * \param id event identifier * * If no room left, a new chunk is allocated. */ void trace_print0 (trace_buffer_t *buf, uint id); /** See trace_print0(). */ void trace_print1 (trace_buffer_t *buf, uint id, int arg0); /** See trace_print0(). */ void trace_print2 (trace_buffer_t *buf, uint id, int arg0, int arg1); /** See trace_print0(). */ void trace_print3 (trace_buffer_t *buf, uint id, int arg0, int arg1, int arg2); /** See trace_print0(). */ void trace_print4 (trace_buffer_t *buf, uint id, int arg0, int arg1, int arg2, int arg3); /** See trace_print0(). */ void trace_print5 (trace_buffer_t *buf, uint id, int arg0, int arg1, int arg2, int arg3, int arg4); /** See trace_print0(). */ void trace_print6 (trace_buffer_t *buf, uint id, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5); /** See trace_print0(). */ void trace_print7 (trace_buffer_t *buf, uint id, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6); /** See trace_print0(). */ void trace_print8 (trace_buffer_t *buf, uint id, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7); /** * Write event to trace buffer with a variable number of argument. * \param buf the trace buffer to write to * \param id event identifier * \param args pointer to arguments * \param nb_args number of arguments * * If no room left, a new chunk is allocated. */ void trace_printn (trace_buffer_t *buf, uint id, const int *args, uint nb_args); /** * Write event to trace buffer, fast version. * \param buf the trace buffer to write to * \param id event identifier * * The fast version will never allocate new memory to record the provided * event. This is useful when real time constrains forbid any undefined * complexity algorithms. */ void trace_fast_print0 (trace_buffer_t *buf, uint id); /** See trace_fast_print0(). */ void trace_fast_print1 (trace_buffer_t *buf, uint id, int arg1); /** See trace_fast_print0(). */ void trace_fast_print2 (trace_buffer_t *buf, uint id, int arg1, int arg2); /** See trace_fast_print0(). */ void trace_fast_print3 (trace_buffer_t *buf, uint id, int arg1, int arg2, int arg3); /** See trace_fast_print0(). */ void trace_fast_print4 (trace_buffer_t *buf, uint id, int arg1, int arg2, int arg3, int arg4); /** See trace_fast_print0(). */ void trace_fast_print5 (trace_buffer_t *buf, uint id, int arg1, int arg2, int arg3, int arg4, int arg5); /** See trace_fast_print0(). */ void trace_fast_print6 (trace_buffer_t *buf, uint id, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6); /** See trace_fast_print0(). */ void trace_fast_print7 (trace_buffer_t *buf, uint id, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7); /** See trace_fast_print0(). */ void trace_fast_print8 (trace_buffer_t *buf, uint id, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8); /** * Write event to trace buffer with a variable number of argument, fast * version. * \param buf the trace buffer to write to * \param id event identifier * \param args pointer to arguments * \param nb_args number of arguments * * The fast version will never allocate new memory to record the provided * event. This is useful when real time constrains forbid any undefined * complexity algorithms. */ void trace_fast_printn (trace_buffer_t *buf, uint id, const int *args, uint nb_args); END_DECLS #else /* !CONFIG_TRACE */ # define trace_init() ((void) 0) # define trace_uninit() ((void) 0) # define trace_drop_chunks(n) ((void) ((n), 0)) # define trace_do(smth) # define TRACE_SHORT(prefix, buffer, id, args...) ((void) 0) # define TRACE_FAST_SHORT(prefix, buffer, id, args...) ((void) 0) # define TRACE_N_SHORT(prefix, buffer, id, args, nb_args) ((void) 0) # define TRACE_FAST_N_SHORT(prefix, buffer, id, args, nb_args) ((void) 0) #endif /* !CONFIG_TRACE */ #endif /* lib_trace_h */