]>
Commit | Line | Data |
---|---|---|
bd6521f0 A |
1 | // |
2 | // EventRingBuffer.hpp | |
3 | // msa | |
4 | // | |
5 | // Created by James McIlree on 10/8/13. | |
6 | // Copyright (c) 2014 Apple. All rights reserved. | |
7 | // | |
8 | ||
9 | #ifndef __msa__EventRingBuffer__ | |
10 | #define __msa__EventRingBuffer__ | |
11 | ||
12 | template <typename SIZE> | |
13 | class EventRingBuffer { | |
14 | protected: | |
15 | const Globals& _globals; // Used for printing the ringbuffer | |
16 | std::vector<KDEvent<SIZE>> _events; | |
17 | std::size_t _head; | |
18 | std::size_t _tail; | |
19 | ||
20 | public: | |
21 | EventRingBuffer(const Globals& globals, std::size_t size); | |
22 | ||
23 | // Returns: | |
24 | // | |
25 | // events, capacity, number_read | |
26 | std::tuple<KDEvent<SIZE>*, std::size_t, std::size_t> read(); | |
27 | ||
28 | void print() const; | |
29 | void print_event_index(std::size_t index) const; | |
30 | void print_all_events() const; | |
31 | void print_last_events(std::size_t lastN) const; | |
32 | void print_from_timestamp(uint64_t timestamp) const; | |
33 | }; | |
34 | ||
35 | template <typename SIZE> | |
36 | EventRingBuffer<SIZE>::EventRingBuffer(const Globals& globals, std::size_t size) : | |
37 | _globals(globals), | |
38 | _events(size), | |
39 | _head(0), | |
40 | _tail(0) | |
41 | { | |
42 | ASSERT(size, "Sanity"); | |
43 | ||
44 | // Force all pages into memory so the first bazillion | |
45 | // trace entries aren't VM_FAULT... | |
46 | bzero(_events.data(), _events.size() * sizeof(KDEvent<SIZE>)); | |
47 | } | |
48 | ||
49 | template <typename SIZE> | |
50 | std::tuple<KDEvent<SIZE>*, std::size_t, std::size_t> EventRingBuffer<SIZE>::read() { | |
51 | std::size_t modulo_index = _tail % _events.size(); | |
52 | std::size_t count, capacity = _events.size() - modulo_index; | |
53 | KDEvent<SIZE>* events = &_events.data()[modulo_index]; | |
54 | ||
55 | if ((count = KDBG::read(events, capacity * sizeof(KDEvent<SIZE>)))) { | |
56 | // Update head/tail as soon as we have added data. | |
57 | _tail += count; | |
58 | if (_tail - _head > _events.size()) { | |
59 | _head += count; | |
60 | } | |
61 | } | |
62 | ||
63 | return std::make_tuple(events, count, capacity); | |
64 | } | |
65 | ||
66 | #if 0 | |
67 | ||
68 | template <typename SIZE> | |
69 | void EventRingBuffer<SIZE>::print() const { | |
70 | printf("%zu events in buffer [%zu -> %zu)\n", _tail - _head, _head, _tail); | |
71 | } | |
72 | ||
73 | template <typename SIZE> | |
74 | void EventRingBuffer<SIZE>::print_event_index(std::size_t index) const { | |
75 | const KDEvent<SIZE>& event = _events[index % _events.size()]; | |
76 | ||
77 | const char* type = event.is_func_start() ? "beg" : (event.is_func_end() ? "end" : "---"); | |
78 | auto trace_code_it = _globals.trace_codes().find(event.dbg_cooked()); | |
79 | ||
80 | if (trace_code_it == _globals.trace_codes().end()) { | |
81 | printf("event[%ld] { timestamp=%llx, arg1=%llx, arg2=%llx, arg3=%llx, arg4=%llx, tid=%llx, %4s %x, cpu=%u }\n", index, event.timestamp().value(), | |
82 | (uint64_t)event.arg1(), (uint64_t)event.arg2(), (uint64_t)event.arg3(), (uint64_t)event.arg4(), (uint64_t)event.tid(), type, event.dbg_cooked(), event.cpu()); | |
83 | } else { | |
84 | printf("event[%ld] { timestamp=%llx, arg1=%llx, arg2=%llx, arg3=%llx, arg4=%llx, tid=%llx, %4s %s, cpu=%u }\n", index, event.timestamp().value(), | |
85 | (uint64_t)event.arg1(), (uint64_t)event.arg2(), (uint64_t)event.arg3(), (uint64_t)event.arg4(), (uint64_t)event.tid(), type, trace_code_it->second.c_str(), event.cpu()); | |
86 | } | |
87 | } | |
88 | ||
89 | template <typename SIZE> | |
90 | void EventRingBuffer<SIZE>::print_all_events() const { | |
91 | std::size_t begin = _head; | |
92 | while (begin < _tail) { | |
93 | print_event_index(begin++); | |
94 | } | |
95 | } | |
96 | ||
97 | template <typename SIZE> | |
98 | void EventRingBuffer<SIZE>::print_last_events(std::size_t lastN) const { | |
99 | std::size_t length = std::min(lastN, _tail - _head); | |
100 | std::size_t begin = _tail - length; | |
101 | ASSERT(begin <= _tail, "Sanity"); | |
102 | while (begin < _tail) { | |
103 | print_event_index(begin++); | |
104 | } | |
105 | } | |
106 | ||
107 | template <typename SIZE> | |
108 | void EventRingBuffer<SIZE>::print_from_timestamp(uint64_t t) const { | |
109 | std::size_t begin = _head; | |
110 | while (begin < _tail) { | |
111 | const KDEvent<SIZE>& event = _events[begin % _events.size()]; | |
112 | if (event.timestamp() >= t) | |
113 | break; | |
114 | begin++; | |
115 | } | |
116 | ||
117 | while (begin < _tail) { | |
118 | print_event_index(begin++); | |
119 | } | |
120 | } | |
121 | ||
122 | void PrintEventRingBuffer() { | |
123 | // uint64_t _timestamp; | |
124 | // uint64_t _arg1; | |
125 | // uint64_t _arg2; | |
126 | // uint64_t _arg3; | |
127 | // uint64_t _arg4; | |
128 | // uint64_t _thread; | |
129 | // uint32_t _debugid; | |
130 | // uint32_t _cpuid; | |
131 | ||
132 | const KDEvent<Kernel64>* events = (const KDEvent<Kernel64>*)g_rb; | |
133 | for (std::size_t i=ring_buffer_head_index; i<ring_buffer_tail_index; i++) { | |
134 | const KDEvent<Kernel64>& event = events[i % g_rb_size]; | |
135 | printf("event[%ld] { timestamp=%llx, ", i, event.timestamp().value()); | |
136 | printf("arg1=%llx, ", event.arg1()); | |
137 | printf("arg2=%llx, ", event.arg2()); | |
138 | printf("arg3=%llx, ", event.arg3()); | |
139 | printf("arg4=%llx, ", event.arg4()); | |
140 | printf("tid=%llx, ", event.tid()); | |
141 | const char* type = event.is_func_start() ? "beg" : (event.is_func_end() ? "end" : "---"); | |
142 | auto trace_code_it = gglobals->trace_codes().find(event.dbg_cooked()); | |
143 | if (trace_code_it == gglobals->trace_codes().end()) { | |
144 | printf("%4s %x, ", type, event.dbg_cooked()); | |
145 | } else { | |
146 | printf("%4s %s, ", type, trace_code_it->second.c_str()); | |
147 | } | |
148 | printf("cpu=%u }\n", event.cpu()); | |
149 | } | |
150 | printf("%lu\n", ring_buffer_tail_index - ring_buffer_head_index); | |
151 | } | |
152 | #endif | |
153 | ||
154 | #endif /* defined(__staintracker__EventRingBuffer__) */ |