| // Copyright 2018 The Fuchsia Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include <lib/async-loop/cpp/loop.h> | 
 | #include <lib/async-loop/default.h> | 
 | #include <lib/trace-engine/context.h> | 
 | #include <lib/trace-engine/handler.h> | 
 | #include <lib/trace-engine/types.h> | 
 | #include <lib/trace-provider/handler.h> | 
 | #include <stddef.h> | 
 |  | 
 | #include <array> | 
 | #include <memory> | 
 |  | 
 | #include <trace-test-utils/compare_records.h> | 
 | #include <trace-test-utils/read_records.h> | 
 | #include <zxtest/zxtest.h> | 
 |  | 
 | #include "trace-vthread/event_vthread.h" | 
 |  | 
 | // Helper macros for writing tests. | 
 | #define I32_ARGS1 "k1", TA_INT32(1) | 
 | #define I32_ARGS4 "k1", TA_INT32(1), "k2", TA_INT32(2), "k3", TA_INT32(3), "k4", TA_INT32(4) | 
 | #define STR_ARGS1 "k1", TA_STRING("v1") | 
 | #define STR_ARGS4 \ | 
 |   "k1", TA_STRING("v1"), "k2", TA_STRING("v2"), "k3", TA_STRING("v3"), "k4", TA_STRING("v4") | 
 |  | 
 | class TraceFixture : private trace::TraceHandler { | 
 |  public: | 
 |   static constexpr trace_buffering_mode_t kBufferingMode = TRACE_BUFFERING_MODE_ONESHOT; | 
 |  | 
 |   static constexpr size_t kBufferSize = 1024 * 1024; | 
 |  | 
 |   TraceFixture() { buffer_.reset(new std::array<uint8_t, kBufferSize>); } | 
 |  | 
 |   bool StartTracing() { | 
 |     zx_status_t init_status = trace_engine_initialize(loop_.dispatcher(), this, kBufferingMode, | 
 |                                                       buffer_->data(), buffer_->size()); | 
 |     zx_status_t start_status = trace_engine_start(TRACE_START_CLEAR_ENTIRE_BUFFER); | 
 |     return init_status == ZX_OK && start_status == ZX_OK; | 
 |   } | 
 |  | 
 |   bool StopTracing() { | 
 |     trace_engine_terminate(); | 
 |     loop_.RunUntilIdle(); | 
 |     return true; | 
 |   } | 
 |  | 
 |   void CompareBuffer(const char* expected) { | 
 |     fbl::Vector<trace::Record> records; | 
 |     ASSERT_TRUE(trace_testing::ReadRecords(buffer_->data(), buffer_->size(), &records)); | 
 |     ASSERT_TRUE(trace_testing::CompareBuffer(records, expected)); | 
 |   } | 
 |  | 
 |  private: | 
 |   async::Loop loop_{&kAsyncLoopConfigAttachToCurrentThread}; | 
 |  | 
 |   std::unique_ptr<std::array<uint8_t, kBufferSize>> buffer_; | 
 | }; | 
 |  | 
 | TEST(EventThreadTests, TestVthreadDurationBegin) { | 
 |   TraceFixture fixture; | 
 |  | 
 |   ASSERT_TRUE(fixture.StartTracing()); | 
 |  | 
 |   TRACE_VTHREAD_DURATION_BEGIN("+enabled", "name", "virtual-thread", 1u, zx_ticks_get()); | 
 |   TRACE_VTHREAD_DURATION_BEGIN("+enabled", "name", "virtual-thread", 1u, zx_ticks_get(), STR_ARGS1); | 
 |   TRACE_VTHREAD_DURATION_BEGIN("+enabled", "name", "virtual-thread", 1u, zx_ticks_get(), STR_ARGS4); | 
 |  | 
 |   ASSERT_TRUE(fixture.StopTracing()); | 
 |  | 
 |   ASSERT_NO_FATAL_FAILURES( | 
 |       fixture.CompareBuffer("\ | 
 | String(index: 1, \"+enabled\")\n\ | 
 | String(index: 2, \"process\")\n\ | 
 | KernelObject(koid: <>, type: thread, name: \"virtual-thread\", {process: koid(<>)})\n\ | 
 | Thread(index: 1, <>)\n\ | 
 | String(index: 3, \"name\")\n\ | 
 | Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", DurationBegin, {})\n\ | 
 | String(index: 4, \"k1\")\n\ | 
 | Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", DurationBegin, {k1: string(\"v1\")})\n\ | 
 | String(index: 5, \"k2\")\n\ | 
 | String(index: 6, \"k3\")\n\ | 
 | String(index: 7, \"k4\")\n\ | 
 | Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", DurationBegin, {k1: string(\"v1\"), k2: string(\"v2\"), k3: string(\"v3\"), k4: string(\"v4\")})\n\ | 
 | ")); | 
 | } | 
 |  | 
 | TEST(EventThreadTests, TestVthreadDurationEnd) { | 
 |   TraceFixture fixture; | 
 |  | 
 |   ASSERT_TRUE(fixture.StartTracing()); | 
 |  | 
 |   TRACE_VTHREAD_DURATION_END("+enabled", "name", "virtual-thread", 1u, zx_ticks_get()); | 
 |   TRACE_VTHREAD_DURATION_END("+enabled", "name", "virtual-thread", 1u, zx_ticks_get(), STR_ARGS1); | 
 |   TRACE_VTHREAD_DURATION_END("+enabled", "name", "virtual-thread", 1u, zx_ticks_get(), STR_ARGS4); | 
 |  | 
 |   ASSERT_TRUE(fixture.StopTracing()); | 
 |  | 
 |   ASSERT_NO_FATAL_FAILURES( | 
 |       fixture.CompareBuffer("\ | 
 | String(index: 1, \"+enabled\")\n\ | 
 | String(index: 2, \"process\")\n\ | 
 | KernelObject(koid: <>, type: thread, name: \"virtual-thread\", {process: koid(<>)})\n\ | 
 | Thread(index: 1, <>)\n\ | 
 | String(index: 3, \"name\")\n\ | 
 | Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", DurationEnd, {})\n\ | 
 | String(index: 4, \"k1\")\n\ | 
 | Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", DurationEnd, {k1: string(\"v1\")})\n\ | 
 | String(index: 5, \"k2\")\n\ | 
 | String(index: 6, \"k3\")\n\ | 
 | String(index: 7, \"k4\")\n\ | 
 | Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", DurationEnd, {k1: string(\"v1\"), k2: string(\"v2\"), k3: string(\"v3\"), k4: string(\"v4\")})\n\ | 
 | ")); | 
 | } | 
 |  | 
 | TEST(EventThreadTests, TestVthreadFlowBegin) { | 
 |   TraceFixture fixture; | 
 |  | 
 |   ASSERT_TRUE(fixture.StartTracing()); | 
 |  | 
 |   TRACE_VTHREAD_FLOW_BEGIN("+enabled", "name", "virtual-thread", 1u, 2u, zx_ticks_get()); | 
 |   TRACE_VTHREAD_FLOW_BEGIN("+enabled", "name", "virtual-thread", 1u, 2u, zx_ticks_get(), STR_ARGS1); | 
 |   TRACE_VTHREAD_FLOW_BEGIN("+enabled", "name", "virtual-thread", 1u, 2u, zx_ticks_get(), STR_ARGS4); | 
 |  | 
 |   ASSERT_TRUE(fixture.StopTracing()); | 
 |  | 
 |   ASSERT_NO_FATAL_FAILURES( | 
 |       fixture.CompareBuffer("\ | 
 | String(index: 1, \"+enabled\")\n\ | 
 | String(index: 2, \"process\")\n\ | 
 | KernelObject(koid: <>, type: thread, name: \"virtual-thread\", {process: koid(<>)})\n\ | 
 | Thread(index: 1, <>)\n\ | 
 | String(index: 3, \"name\")\n\ | 
 | Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", FlowBegin(id: 2), {})\n\ | 
 | String(index: 4, \"k1\")\n\ | 
 | Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", FlowBegin(id: 2), {k1: string(\"v1\")})\n\ | 
 | String(index: 5, \"k2\")\n\ | 
 | String(index: 6, \"k3\")\n\ | 
 | String(index: 7, \"k4\")\n\ | 
 | Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", FlowBegin(id: 2), {k1: string(\"v1\"), k2: string(\"v2\"), k3: string(\"v3\"), k4: string(\"v4\")})\n\ | 
 | ")); | 
 | } | 
 |  | 
 | TEST(EventThreadTests, TestVthreadFlowStep) { | 
 |   TraceFixture fixture; | 
 |  | 
 |   ASSERT_TRUE(fixture.StartTracing()); | 
 |  | 
 |   TRACE_VTHREAD_FLOW_STEP("+enabled", "name", "virtual-thread", 1u, 2u, zx_ticks_get()); | 
 |   TRACE_VTHREAD_FLOW_STEP("+enabled", "name", "virtual-thread", 1u, 2u, zx_ticks_get(), STR_ARGS1); | 
 |   TRACE_VTHREAD_FLOW_STEP("+enabled", "name", "virtual-thread", 1u, 2u, zx_ticks_get(), STR_ARGS4); | 
 |  | 
 |   ASSERT_TRUE(fixture.StopTracing()); | 
 |  | 
 |   ASSERT_NO_FATAL_FAILURES( | 
 |       fixture.CompareBuffer("\ | 
 | String(index: 1, \"+enabled\")\n\ | 
 | String(index: 2, \"process\")\n\ | 
 | KernelObject(koid: <>, type: thread, name: \"virtual-thread\", {process: koid(<>)})\n\ | 
 | Thread(index: 1, <>)\n\ | 
 | String(index: 3, \"name\")\n\ | 
 | Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", FlowStep(id: 2), {})\n\ | 
 | String(index: 4, \"k1\")\n\ | 
 | Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", FlowStep(id: 2), {k1: string(\"v1\")})\n\ | 
 | String(index: 5, \"k2\")\n\ | 
 | String(index: 6, \"k3\")\n\ | 
 | String(index: 7, \"k4\")\n\ | 
 | Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", FlowStep(id: 2), {k1: string(\"v1\"), k2: string(\"v2\"), k3: string(\"v3\"), k4: string(\"v4\")})\n\ | 
 | ")); | 
 | } | 
 |  | 
 | TEST(EventThreadTests, TestVthreadFlowEnd) { | 
 |   TraceFixture fixture; | 
 |  | 
 |   ASSERT_TRUE(fixture.StartTracing()); | 
 |  | 
 |   TRACE_VTHREAD_FLOW_END("+enabled", "name", "virtual-thread", 1u, 2u, zx_ticks_get()); | 
 |   TRACE_VTHREAD_FLOW_END("+enabled", "name", "virtual-thread", 1u, 2u, zx_ticks_get(), STR_ARGS1); | 
 |   TRACE_VTHREAD_FLOW_END("+enabled", "name", "virtual-thread", 1u, 2u, zx_ticks_get(), STR_ARGS4); | 
 |  | 
 |   ASSERT_TRUE(fixture.StopTracing()); | 
 |  | 
 |   ASSERT_NO_FATAL_FAILURES( | 
 |       fixture.CompareBuffer("\ | 
 | String(index: 1, \"+enabled\")\n\ | 
 | String(index: 2, \"process\")\n\ | 
 | KernelObject(koid: <>, type: thread, name: \"virtual-thread\", {process: koid(<>)})\n\ | 
 | Thread(index: 1, <>)\n\ | 
 | String(index: 3, \"name\")\n\ | 
 | Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", FlowEnd(id: 2), {})\n\ | 
 | String(index: 4, \"k1\")\n\ | 
 | Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", FlowEnd(id: 2), {k1: string(\"v1\")})\n\ | 
 | String(index: 5, \"k2\")\n\ | 
 | String(index: 6, \"k3\")\n\ | 
 | String(index: 7, \"k4\")\n\ | 
 | Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", FlowEnd(id: 2), {k1: string(\"v1\"), k2: string(\"v2\"), k3: string(\"v3\"), k4: string(\"v4\")})\n\ | 
 | ")); | 
 | } | 
 |  | 
 | TEST(EventThreadTests, TestVthreadCounter) { | 
 |   TraceFixture fixture; | 
 |  | 
 |   ASSERT_TRUE(fixture.StartTracing()); | 
 |  | 
 |   TRACE_VTHREAD_COUNTER("+enabled", "name", "virtual-thread", 1u, 2u, zx_ticks_get()); | 
 |   TRACE_VTHREAD_COUNTER("+enabled", "name", "virtual-thread", 1u, 2u, zx_ticks_get(), I32_ARGS1); | 
 |   TRACE_VTHREAD_COUNTER("+enabled", "name", "virtual-thread", 1u, 2u, zx_ticks_get(), I32_ARGS4); | 
 |  | 
 |   ASSERT_TRUE(fixture.StopTracing()); | 
 |  | 
 |   ASSERT_NO_FATAL_FAILURES( | 
 |       fixture.CompareBuffer("\ | 
 | String(index: 1, \"+enabled\")\n\ | 
 | String(index: 2, \"process\")\n\ | 
 | KernelObject(koid: <>, type: thread, name: \"virtual-thread\", {process: koid(<>)})\n\ | 
 | Thread(index: 1, <>)\n\ | 
 | String(index: 3, \"name\")\n\ | 
 | Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", Counter(id: 2), {})\n\ | 
 | String(index: 4, \"k1\")\n\ | 
 | Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", Counter(id: 2), {k1: int32(1)})\n\ | 
 | String(index: 5, \"k2\")\n\ | 
 | String(index: 6, \"k3\")\n\ | 
 | String(index: 7, \"k4\")\n\ | 
 | Event(ts: <>, pt: <>, category: \"+enabled\", name: \"name\", Counter(id: 2), {k1: int32(1), k2: int32(2), k3: int32(3), k4: int32(4)})\n\ | 
 | ")); | 
 | } |