net: tcp: Fix TSO for incoming connections
[akaros.git] / kern / include / trace.h
1 /* Copyright (c) 2013 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * See LICENSE for details.
4  *
5  * Simple ring-buffer tracing for in-kernel events.  The rings have a
6  * power-of-two number of slots, and each entry size will be rounded up to the
7  * nearest power of two.  Ring slot acquisition by default is thread-safe, but
8  * we provide racy helpers if you want a little less overhead.
9  *
10  * Users need to provide a contiguous memory buffer and the size of an event
11  * struct to init.  For example:
12  *
13  *              trace_ring_init(my_trace_ring_ptr, my_buf, buf_sz, event_sz);
14  *
15  * And then to store a trace, first get a slot, then fill it in:
16  *
17  *              struct my_trace_event *my_trace = get_trace_slot(my_trace_ring_ptr);
18  *              if (my_trace)   // only need to check if we aren't overwriting
19  *                      my_trace = whatever;
20  *
21  * Later, to process the traces, provide a function pointer to
22  * trace_ring_foreach().  This performs the func on all traces in the ring,
23  * including the unused:
24  *
25  *              void trace_handler(void *trace_event, void *data)
26  *              {
27  *                      whatever();
28  *              }
29  *              trace_ring_foreach(my_trace_ring_ptr, trace_handler, optional_blob);
30  *
31  * Rings can be racy or not, and can overwrite entries or not.  If you are not
32  * overwriting, the ring will stop giving you slots.  You need to reset the ring
33  * to get fresh slots again.  If you are overwriting, you don't need to check
34  * the return value of get_trace_slot_overwrite().
35  *
36  * Given there is overwrite, tr_next doesn't really tell us which ones were
37  * used.  So your handler should check for a flag or something.  Timestamps
38  * might help make sense of the data in these cases too. */
39
40 #pragma once
41
42 #include <ros/common.h>
43 #include <assert.h>
44
45 struct trace_ring {
46         unsigned char                           *tr_buf;
47         size_t                                          tr_buf_sz;
48         unsigned int                            tr_event_sz_shift;
49         unsigned int                            tr_max;
50         unsigned long                           tr_next;
51 };
52
53 typedef void (*trace_handler_t)(void *event, void *blob);
54
55 static inline void *get_trace_slot(struct trace_ring *tr);
56 static inline void *get_trace_slot_overwrite(struct trace_ring *tr);
57 static inline void *get_trace_slot_racy(struct trace_ring *tr);
58 static inline void *get_trace_slot_overwrite_racy(struct trace_ring *tr);
59
60 void trace_ring_init(struct trace_ring *tr, void *buf, size_t buf_size,
61                      size_t event_size);
62 void trace_ring_reset(struct trace_ring *tr);
63 void trace_ring_reset_and_clear(struct trace_ring *tr);
64 void trace_ring_foreach(struct trace_ring *tr, trace_handler_t tr_func,
65                         void *data);
66
67 /* Inlined funcs, declared above */
68
69 /* Helper */
70 /* Get next trace ring slot with no wrapping */
71 static inline void *__get_tr_slot(struct trace_ring *tr, unsigned long ind)
72 {
73         dassert(0 <= ind && ind < tr->tr_max);
74         /* event sizes are rounded up to the nearest power of 2 (sz_shift) */
75         return (void *) (tr->tr_buf + (ind << tr->tr_event_sz_shift));
76 }
77
78 /* Get next trace ring slot with wrapping */
79 static inline void *
80 __get_tr_slot_overwrite(struct trace_ring *tr, unsigned long slot)
81 {
82         /* tr_max is a power of 2, we're ignoring the upper bits of slot */
83         slot &= tr->tr_max - 1;
84         return __get_tr_slot(tr, slot);
85 }
86
87 static inline void *get_trace_slot(struct trace_ring *tr)
88 {
89         /* Using syncs, instead of atomics, since we access tr_next as both atomic
90          * and 'normal'. */
91         unsigned long my_slot = __sync_fetch_and_add(&tr->tr_next, 1);
92         /* We can briefly go over, so long as we subtract back down to where we were
93          * before.  This will work so long as we don't have ~2^64 threads... */
94         if (my_slot >= tr->tr_max) {
95                 __sync_fetch_and_add(&tr->tr_next, -1);
96                 return 0;
97         }
98         return __get_tr_slot(tr, my_slot);
99 }
100
101 static inline void *get_trace_slot_overwrite(struct trace_ring *tr)
102 {
103         return __get_tr_slot_overwrite(tr, __sync_fetch_and_add(&tr->tr_next, 1));
104 }
105
106 static inline void *get_trace_slot_racy(struct trace_ring *tr)
107 {
108         unsigned long my_slot = tr->tr_next;
109         if (my_slot >= tr->tr_max)
110                 return 0;
111         tr->tr_next++;
112         return __get_tr_slot(tr, my_slot);
113 }
114
115 static inline void *get_trace_slot_overwrite_racy(struct trace_ring *tr)
116 {
117         return __get_tr_slot_overwrite(tr, tr->tr_next++);
118 }