1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <stddef.h>
6
7 #include <array>
8 #include <memory>
9
10 #include <lib/async-loop/cpp/loop.h>
11 #include <trace-engine/context.h>
12 #include <trace-engine/handler.h>
13 #include <trace-engine/types.h>
14 #include <trace-provider/handler.h>
15 #include <trace-test-utils/compare_records.h>
16 #include <trace-test-utils/read_records.h>
17 #include <unittest/unittest.h>
18
19 #include "trace-vthread/event_vthread.h"
20
21 // Helper macros for writing tests.
22 #define STR_ARGS1 "k1", TA_STRING("v1")
23 #define STR_ARGS4 "k1", TA_STRING("v1"), "k2", TA_STRING("v2"), \
24 "k3", TA_STRING("v3"), "k4", TA_STRING("v4")
25
26 class TraceFixture : private trace::TraceHandler {
27 public:
28 static constexpr trace_buffering_mode_t kBufferingMode =
29 TRACE_BUFFERING_MODE_ONESHOT;
30
31 static constexpr size_t kBufferSize = 1024 * 1024;
32
TraceFixture()33 TraceFixture() {
34 buffer_.reset(new std::array<uint8_t, kBufferSize>);
35 }
36
StartTracing()37 bool StartTracing() {
38 zx_status_t status = trace_start_engine(loop_.dispatcher(), this,
39 kBufferingMode,
40 buffer_->data(), buffer_->size());
41 return status == ZX_OK;
42 }
43
StopTracing()44 bool StopTracing() {
45 zx_status_t status = trace_stop_engine(ZX_OK);
46 loop_.RunUntilIdle();
47 return status == ZX_OK;
48 }
49
CompareBuffer(const char * expected)50 bool CompareBuffer(const char* expected) {
51 BEGIN_HELPER;
52 fbl::Vector<trace::Record> records;
53 ASSERT_TRUE(trace_testing::ReadRecords(buffer_->data(), buffer_->size(),
54 &records));
55 ASSERT_TRUE(trace_testing::CompareBuffer(records, expected));
56 END_HELPER;
57 }
58
59 private:
60 async::Loop loop_{&kAsyncLoopConfigAttachToThread};
61
62 std::unique_ptr<std::array<uint8_t, kBufferSize>> buffer_;
63 };
64
TestVthreadDurationBegin()65 bool TestVthreadDurationBegin() {
66 TraceFixture fixture;
67
68 BEGIN_TEST;
69
70 ASSERT_TRUE(fixture.StartTracing());
71
72 TRACE_VTHREAD_DURATION_BEGIN("+enabled", "name", "virtual-thread", 1u, zx_ticks_get());
73 TRACE_VTHREAD_DURATION_BEGIN("+enabled", "name", "virtual-thread", 1u, zx_ticks_get(), STR_ARGS1);
74 TRACE_VTHREAD_DURATION_BEGIN("+enabled", "name", "virtual-thread", 1u, zx_ticks_get(), STR_ARGS4);
75
76 ASSERT_TRUE(fixture.StopTracing());
77
78 ASSERT_TRUE(fixture.CompareBuffer("\
79 String(index: 1, \"+enabled\")\n\
80 String(index: 2, \"process\")\n\
81 KernelObject(koid: <>, type: thread, name: \"virtual-thread\", {process: koid(<>)})\n\
82 Thread(index: 1, <>)\n\
83 String(index: 3, \"name\")\n\
84 Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", DurationBegin, {})\n\
85 String(index: 4, \"k1\")\n\
86 Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", DurationBegin, {k1: string(\"v1\")})\n\
87 String(index: 5, \"k2\")\n\
88 String(index: 6, \"k3\")\n\
89 String(index: 7, \"k4\")\n\
90 Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", DurationBegin, {k1: string(\"v1\"), k2: string(\"v2\"), k3: string(\"v3\"), k4: string(\"v4\")})\n\
91 "));
92
93 END_TEST;
94 }
95
TestVthreadDurationEnd()96 bool TestVthreadDurationEnd() {
97 TraceFixture fixture;
98
99 BEGIN_TEST;
100
101 ASSERT_TRUE(fixture.StartTracing());
102
103 TRACE_VTHREAD_DURATION_END("+enabled", "name", "virtual-thread", 1u, zx_ticks_get());
104 TRACE_VTHREAD_DURATION_END("+enabled", "name", "virtual-thread", 1u, zx_ticks_get(), STR_ARGS1);
105 TRACE_VTHREAD_DURATION_END("+enabled", "name", "virtual-thread", 1u, zx_ticks_get(), STR_ARGS4);
106
107 ASSERT_TRUE(fixture.StopTracing());
108
109 ASSERT_TRUE(fixture.CompareBuffer("\
110 String(index: 1, \"+enabled\")\n\
111 String(index: 2, \"process\")\n\
112 KernelObject(koid: <>, type: thread, name: \"virtual-thread\", {process: koid(<>)})\n\
113 Thread(index: 1, <>)\n\
114 String(index: 3, \"name\")\n\
115 Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", DurationEnd, {})\n\
116 String(index: 4, \"k1\")\n\
117 Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", DurationEnd, {k1: string(\"v1\")})\n\
118 String(index: 5, \"k2\")\n\
119 String(index: 6, \"k3\")\n\
120 String(index: 7, \"k4\")\n\
121 Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", DurationEnd, {k1: string(\"v1\"), k2: string(\"v2\"), k3: string(\"v3\"), k4: string(\"v4\")})\n\
122 "));
123
124 END_TEST;
125 }
126
TestVthreadFlowBegin()127 bool TestVthreadFlowBegin() {
128 TraceFixture fixture;
129
130 BEGIN_TEST;
131
132 ASSERT_TRUE(fixture.StartTracing());
133
134 TRACE_VTHREAD_FLOW_BEGIN("+enabled", "name", "virtual-thread", 1u, 2u, zx_ticks_get());
135 TRACE_VTHREAD_FLOW_BEGIN("+enabled", "name", "virtual-thread", 1u, 2u, zx_ticks_get(), STR_ARGS1);
136 TRACE_VTHREAD_FLOW_BEGIN("+enabled", "name", "virtual-thread", 1u, 2u, zx_ticks_get(), STR_ARGS4);
137
138 ASSERT_TRUE(fixture.StopTracing());
139
140 ASSERT_TRUE(fixture.CompareBuffer("\
141 String(index: 1, \"+enabled\")\n\
142 String(index: 2, \"process\")\n\
143 KernelObject(koid: <>, type: thread, name: \"virtual-thread\", {process: koid(<>)})\n\
144 Thread(index: 1, <>)\n\
145 String(index: 3, \"name\")\n\
146 Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", FlowBegin(id: 2), {})\n\
147 String(index: 4, \"k1\")\n\
148 Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", FlowBegin(id: 2), {k1: string(\"v1\")})\n\
149 String(index: 5, \"k2\")\n\
150 String(index: 6, \"k3\")\n\
151 String(index: 7, \"k4\")\n\
152 Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", FlowBegin(id: 2), {k1: string(\"v1\"), k2: string(\"v2\"), k3: string(\"v3\"), k4: string(\"v4\")})\n\
153 "));
154
155 END_TEST;
156 }
157
TestVthreadFlowStep()158 bool TestVthreadFlowStep() {
159 TraceFixture fixture;
160
161 BEGIN_TEST;
162
163 ASSERT_TRUE(fixture.StartTracing());
164
165 TRACE_VTHREAD_FLOW_STEP("+enabled", "name", "virtual-thread", 1u, 2u, zx_ticks_get());
166 TRACE_VTHREAD_FLOW_STEP("+enabled", "name", "virtual-thread", 1u, 2u, zx_ticks_get(), STR_ARGS1);
167 TRACE_VTHREAD_FLOW_STEP("+enabled", "name", "virtual-thread", 1u, 2u, zx_ticks_get(), STR_ARGS4);
168
169 ASSERT_TRUE(fixture.StopTracing());
170
171 ASSERT_TRUE(fixture.CompareBuffer("\
172 String(index: 1, \"+enabled\")\n\
173 String(index: 2, \"process\")\n\
174 KernelObject(koid: <>, type: thread, name: \"virtual-thread\", {process: koid(<>)})\n\
175 Thread(index: 1, <>)\n\
176 String(index: 3, \"name\")\n\
177 Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", FlowStep(id: 2), {})\n\
178 String(index: 4, \"k1\")\n\
179 Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", FlowStep(id: 2), {k1: string(\"v1\")})\n\
180 String(index: 5, \"k2\")\n\
181 String(index: 6, \"k3\")\n\
182 String(index: 7, \"k4\")\n\
183 Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", FlowStep(id: 2), {k1: string(\"v1\"), k2: string(\"v2\"), k3: string(\"v3\"), k4: string(\"v4\")})\n\
184 "));
185
186 END_TEST;
187 }
188
TestVthreadFlowEnd()189 bool TestVthreadFlowEnd() {
190 TraceFixture fixture;
191
192 BEGIN_TEST;
193
194 ASSERT_TRUE(fixture.StartTracing());
195
196 TRACE_VTHREAD_FLOW_END("+enabled", "name", "virtual-thread", 1u, 2u, zx_ticks_get());
197 TRACE_VTHREAD_FLOW_END("+enabled", "name", "virtual-thread", 1u, 2u, zx_ticks_get(), STR_ARGS1);
198 TRACE_VTHREAD_FLOW_END("+enabled", "name", "virtual-thread", 1u, 2u, zx_ticks_get(), STR_ARGS4);
199
200 ASSERT_TRUE(fixture.StopTracing());
201
202 ASSERT_TRUE(fixture.CompareBuffer("\
203 String(index: 1, \"+enabled\")\n\
204 String(index: 2, \"process\")\n\
205 KernelObject(koid: <>, type: thread, name: \"virtual-thread\", {process: koid(<>)})\n\
206 Thread(index: 1, <>)\n\
207 String(index: 3, \"name\")\n\
208 Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", FlowEnd(id: 2), {})\n\
209 String(index: 4, \"k1\")\n\
210 Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", FlowEnd(id: 2), {k1: string(\"v1\")})\n\
211 String(index: 5, \"k2\")\n\
212 String(index: 6, \"k3\")\n\
213 String(index: 7, \"k4\")\n\
214 Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", FlowEnd(id: 2), {k1: string(\"v1\"), k2: string(\"v2\"), k3: string(\"v3\"), k4: string(\"v4\")})\n\
215 "));
216
217 END_TEST;
218 }
219
220 BEGIN_TEST_CASE(event_thread_tests)
RUN_TEST(TestVthreadDurationBegin)221 RUN_TEST(TestVthreadDurationBegin)
222 RUN_TEST(TestVthreadDurationEnd)
223 RUN_TEST(TestVthreadFlowBegin)
224 RUN_TEST(TestVthreadFlowStep)
225 RUN_TEST(TestVthreadFlowEnd)
226 END_TEST_CASE(event_thread_tests)
227
228 int main(int argc, char** argv) {
229 return unittest_run_all_tests(argc, argv) ? 0 : -1;
230 }
231