blob: 4b38c58885d7d20a4d8fe5f875437fc590769dfe [file] [log] [blame]
/* TODO(gvdl): Who holds the copyright?
* Godfrey van der Linden <gvdl@google.com>
* See LICENSE for details.
*
* Timed tracing.
* Kernel header
* TODO(gvdl): Documentation goes here. */
#ifndef INC_TTRACE_H
#define INC_TTRACE_H
#define TTRACE_NULL_STATEMENT do { } while(0)
#ifndef CONFIG_TTRACE
// If the TTRACE is not configured then null out the initters
#define ttrace_init() TTRACE_NULL_STATEMENT
#define ttrace_cleanup() TTRACE_NULL_STATEMENT
#else /* CONFIG_TTRACE */
#include <atomic.h>
#include <ros/ttrace.h>
// Global data
// Active tracepoint mask, see TTRACE_TYPE... enums in ros/ttrace.h
extern uint64_t ttrace_type_mask;
// Two phase initialisation. Call ttrace_init() as soon as page memory
// allocation is possible so that we can trace very early in system boot.
// However, that early in boot we do not yet know how many cores we will
// manange, ttrace_cleanup() is called once we know and returns memory
// previously allocated for unused cores.
extern void ttrace_init();
extern void ttrace_cleanup();
// devttrace accessor routines
struct trace_ring* get_ttrace_ring_for_core(uint32_t coreid);
void fill_ttrace_version(struct ttrace_version *versp);
const uint8_t *bufferp get_ttrace_aux_buffer(void)
void get_ttrace_aux_buffer_snapshot(ptrdiff_t *firstp, ptrdiff_t *lastp);
// Low level data collection apis, do not use directly but rather use the macro
// wrappers, such as TTRACE_PROC_ALLOC() below.
extern uint64_t _ttrace_point(uint64_t type_start_stop,
uintptr_t d0, uintptr_t d1, uintptr_t d2,
uintptr_t d3, uintptr_t d4);
extern void _ttrace_point_cont(uint64_t timestamp, uintptr_t d0, uintptr_t d1,
uintptr_t d2, uintptr_t d3, uintptr_t d4,
uintptr_t d5, uintptr_t d6);
// Slow takes rwlock, updates auxillary buffer, call this rarely
extern void _ttrace_point_string(uint8_t tag, uintptr_t ident, const char *str);
static inline uintptr_t __attribute__((always_inline))
take_tracepoint(uintptr_t type_start_stop)
{
uintptr_t cur_mask = atomic_read((atomic_t *) &ttrace_type_mask);
return cur_mask & type_start_stop & TTRACE_TYPE_MASK;
}
static inline uint64_t _ttrace_point5(uint64_t type_start_stop,
uintptr_t d0, uintptr_t d1, uintptr_t d2,
uintptr_t d3, uintptr_t d4)
{
if (take_tracepoint(type_start_stop))
return _ttrace_point(type_start_stop, d0, d1, d2, d3, d4);
return 0;
}
#define TTRACE_POINT5(type, start_stop, data...) do { \
static_assert(type & TTRACE_TYPE_MASK); \
_ttrace_point5(type | start_stop, data); \
} while(false)
static inline uint64_t _ttrace_point12(uint64_t type_start_stop,
uintptr_t d0, uintptr_t d1, uintptr_t d2,
uintptr_t d3, uintptr_t d4, uintptr_t d5,
uintptr_t d6, uintptr_t d7, uintptr_t d8,
uintptr_t d9, uintptr_t da, uintptr_t db)
{
if (take_tracepoint(type_start_stop)) {
const uint64_t tsc = _ttrace_point(type_start_stop, d0, d1, d2, d3, d4);
_ttrace_point_cont(tsc, d5, d6, d7, d8, d9, da, db);
return tsc;
} else
return 0;
}
#define TTRACE_POINT12(type, start_stop, data...) do { \
static_assert(type & TTRACE_TYPE_MASK); \
_ttrace_point12(type | start_stop, data); \
} while(false)
static inline void _ttrace_string(uint64_t type, uint8_t tag,
uintptr_t ident, const char* str)
{
if (take_tracepoint(type))
_ttrace_point_string(tag, ident, str);
}
// string len < TTRACE_AUX_ENTRY_MAXSTRLEN
#define TTRACE_STRING(type, tag, ident, str) do { \
static_assert(type & TTRACE_TYPE_MASK); \
static_assert(tag & TTRACEH_TAG_MASK); \
_ttrace_string(type, tag, ident, str);
} while(false)
//
// CONFIG_TTRACE macros
//
// These macros are the data collection side of ttrace. Each CONFIG_TTRACE type
// has its own group of macros which are empty if the group is not configured.
// CONFIG_TTRACE_PROCESS trace point macros.
#ifdef CONFIG_TTRACE_PROCESS
#define TTRACE_PROC_ALLOC(pid, ppid) TTRACE_POINT5( \
TTRACE_TYPE_PROCESS, TTRACE_ENTRY_START, pid, ppid, 0, 0, 0);
#define TTRACE_PROC_FREE(pid, cpid) TTRACE_POINT5( \
TTRACE_TYPE_PROCESS, TTRACE_ENTRY_STOP, pid, cpid, 0, 0, 0);
#define TTRACE_PROC_READY(pid) TTRACE_POINT5( \
TTRACE_TYPE_PROCESS, TTRACE_ENTRY_ENTRY, pid, 0, 0, 0, 0);
#define TTRACE_PROC_SETSTATE(pid, state, curstate) TTRACE_POINT5( \
TTRACE_TYPE_PROCESS, TTRACE_ENTRY_EXIT, pid, state, curstate, 0, 0);
#define TTRACE_PROC_SETNAME(pid, name) \
TTRACE_STRING(TTRACE_TYPE_PROCESS, TTRACEH_TAG_PROC, pid, name)
#else /* !CONFIG_TTRACE_PROCESS */
#define TTRACE_PROC_ALLOC(pid, ppid) TTRACE_NULL_STATEMENT
#define TTRACE_PROC_FREE(pid, cpid) TTRACE_NULL_STATEMENT
#define TTRACE_PROC_READY(pid) TTRACE_NULL_STATEMENT
#define TTRACE_PROC_SETSTATE(pid, state, curstate) TTRACE_NULL_STATEMENT
#define TTRACE_PROC_SETNAME(pid, name) TTRACE_NULL_STATEMENT
#endif /* CONFIG_TTRACE_PROCESS */
#endif /* !CONFIG_TTRACE */
#endif /* INC_TTRACE_H */