Initial commit
[nbds] / include / lwt.h
1 /* 
2  * Written by Josh Dybnis and released to the public domain, as explained at
3  * http://creativecommons.org/licenses/publicdomain
4  *
5  * lightweight tracing
6  */ 
7 #ifndef LWT_H
8 #define LWT_H
9 #include "tls.h"
10
11 #ifndef ENABLE_TRACE
12 #define TRACE(...) do { } while (0)
13 #else
14 #define TRACE(flag, format, v1, v2) lwt_trace(flag, format, (size_t)(v1), (size_t)(v2))
15 #endif
16
17 #define LWT_BUFFER_SCALE 16
18 #define LWT_BUFFER_SIZE (1 << LWT_BUFFER_SCALE)
19 #define LWT_BUFFER_MASK (LWT_BUFFER_SIZE - 1)
20
21 typedef struct lwt_record {
22     uint64_t timestamp;
23     const char *format;
24     size_t value1;
25     size_t value2;
26 } lwt_record_t;
27
28 typedef struct lwt_buffer {
29     uint32_t head;
30     lwt_record_t x[0];
31 } lwt_buffer_t;
32
33 void lwt_init (void);
34 void lwt_thread_init (int thread_id);
35
36 void lwt_dump (const char *file_name) __attribute__ ((externally_visible));
37
38 // <flags> indicates what kind of trace messages should be included in the dump. <flags> is a sequence of letters
39 // followed by numbers (e.g. "x1c9n2g3"). The letters indicate trace categories and the numbers are trace levels 
40 // for each category. If a category appears in <flags>, then messages from that category will be included in the
41 // dump if they have a trace level less than or equal to the one specified in <flags>. Categories are case
42 // sensitive.
43 void lwt_set_trace_level (const char *flags);
44
45 // <flag> is a two character string containing a letter followed by a number (e.g. "f3"). The letter indicates a
46 // trace category, and the number a trace level. <flag> controls whether or not the trace message gets included in
47 // the dump. It is only included when its specified category is enabled at a trace level greater than or equal to
48 // the one in <flag>. Categories are case sensitive. 
49 static inline void lwt_trace (const char *flag, const char *format, size_t value1, size_t value2) {
50     extern uint64_t flag_mask_;
51     if (EXPECT_FALSE(flag_mask_ & (1 << (flag[0] - 'A')))) {
52         LOCALIZE_THREAD_LOCAL(tb_, lwt_buffer_t *);
53         unsigned int u, l;
54         __asm__ __volatile__("rdtsc" : "=a" (l), "=d" (u)); 
55         uint64_t timestamp = ((uint64_t)u << 32) | l; 
56         // embed <flags> in <format> so we don't have to make the lwt_record_t any bigger than it already is
57         format = (const char *)((size_t)format | ((uint64_t)flag[0] << 56) | ((uint64_t)flag[1] << 48));
58         lwt_record_t temp = { timestamp, format, value1, value2 };
59         if (tb_) {
60             tb_->x[tb_->head++ & LWT_BUFFER_MASK] = temp;
61         }
62     }
63 }
64 #endif//LWT_H