blob: 5c175e32e2b49d33185df597af66e26d63963844 [file] [log] [blame]
// Copyright 2023 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/syslog/cpp/macros.h>
#include <lib/trace-provider/provider.h>
#include <lib/trace/event.h>
#include <unistd.h>
#include <thread>
#include "lib/async/cpp/task.h"
#include "zircon/system/public/zircon/process.h"
size_t async_id = 0;
size_t flow_id = 0;
uint64_t data = 0;
uint64_t data2 = UINT32_MAX;
void EmitSomeEvents(async_dispatcher_t* dispatcher) {
// The simplest trace event is an instant event, which marks a point in time. It has both a name
// and a category to differentiate it. It will show up in the Perfetto UI as a little arrow.
TRACE_INSTANT("example", "example_instant", TRACE_SCOPE_THREAD);
TRACE_COUNTER("example", "example_counter", 0, "somedataseries", data++);
TRACE_COUNTER("example", "example_counter2", 1, "someotherdataseries", data2--);
// Only slightly more complicated is a duration event, which marks _two_ points in time.
// It will appear in the viewer as a block
TRACE_DURATION_BEGIN("example", "example_duration");
usleep(50000);
// It needs to be matched by a duration end with the same name and category.
TRACE_DURATION_END("example", "example_duration");
// Alternatively, you can use the RAII macro which will automatically handle this for you when it
// goes out of scope.
TRACE_DURATION("example", "example_duration_raii");
usleep(25000);
// You can use async events to record an operation that may occur across threads.
// In the viewer, the events will appear linearly on their own track based on the name of the
// async begin event as opposed to the thread they were emitted on.
TRACE_ASYNC_BEGIN("example", "example_async", async_id);
TRACE_ASYNC_BEGIN("example", "example_async2", async_id + 1);
std::thread thread1([id = async_id] {
usleep(5000);
TRACE_ASYNC_INSTANT("example", "example_async_instant1", id);
});
std::thread thread2([id = async_id] {
usleep(10000);
TRACE_ASYNC_INSTANT("example", "example_async_instant2", id);
});
std::thread thread3([id = async_id] {
usleep(5000);
TRACE_ASYNC_INSTANT("example", "example_async_instant3", id + 1);
});
std::thread thread4([id = async_id] {
usleep(10000);
TRACE_ASYNC_INSTANT("example", "example_async_instant4", id + 1);
});
thread1.join();
thread2.join();
thread3.join();
thread4.join();
TRACE_ASYNC_END("example", "example_async", async_id);
TRACE_ASYNC_END("example", "example_async2", async_id + 1);
async_id += 2;
// Flow events allow you to link together duration events that may occur across threads or
// abstraction layers. Each flow event must be enclosed by a duration event. The viewer then
// displays the flow events as arrows connecting each of the duration events.
TRACE_FLOW_BEGIN("example", "example_flow", flow_id);
TRACE_FLOW_BEGIN("example", "example_flow2", flow_id + 1);
std::thread thread5([id = flow_id] {
TRACE_DURATION("example", "thread5");
usleep(1000);
TRACE_FLOW_STEP("example", "example_flow_step1", id);
});
std::thread thread6([id = flow_id] {
TRACE_DURATION("example", "thread6");
usleep(2000);
TRACE_FLOW_STEP("example", "example_flow_step2", id);
});
std::thread thread7([id = flow_id] {
TRACE_DURATION("example", "thread7");
usleep(3000);
TRACE_FLOW_STEP("example", "example_flow_step3", id + 1);
});
std::thread thread8([id = flow_id] {
TRACE_DURATION("example", "thread8");
usleep(4000);
TRACE_FLOW_STEP("example", "example_flow_step4", id + 1);
});
std::thread thread9([id = flow_id] {
TRACE_DURATION("example", "thread9");
usleep(5000);
TRACE_FLOW_END("example", "example_flow", id);
});
std::thread thread10([id = flow_id] {
TRACE_DURATION("example", "thread10");
usleep(6000);
TRACE_FLOW_END("example", "example_flow2", id + 1);
});
thread5.join();
thread6.join();
thread7.join();
thread8.join();
thread9.join();
thread10.join();
flow_id += 2;
// Trace Events can also have arguments associated with them that will show up when you click on
// the event in the viewer
//
// Null arguments are just a name and no data
TRACE_INSTANT("example", "example_instant_args", TRACE_SCOPE_THREAD, "SomeNullArg", TA_NULL());
// There are standard int types
TRACE_INSTANT("example", "example_instant_args", TRACE_SCOPE_THREAD, "Someuint32",
uint32_t{2145});
TRACE_INSTANT("example", "example_instant_args", TRACE_SCOPE_THREAD, "Someuint64",
uint64_t{423621626134123415});
TRACE_INSTANT("example", "example_instant_args", TRACE_SCOPE_THREAD, "Someint32", int32_t{-7});
TRACE_INSTANT("example", "example_instant_args", TRACE_SCOPE_THREAD, "Someint64",
int64_t{-234516543631231});
// Doubles
TRACE_INSTANT("example", "example_instant_args", TRACE_SCOPE_THREAD, "Somedouble",
double{3.1415});
// Strings
TRACE_INSTANT("example", "example_instant_args", TRACE_SCOPE_THREAD, "ping", "pong");
// Pointers will format in hex in the viewer
int i = 0;
// You can also specifically specify the trace argument type when type deduction would otherwise
// resolve to the wrong type.
TRACE_INSTANT("example", "example_instant_args", TRACE_SCOPE_THREAD, "somepointer", &i,
"someotherpointer", TA_POINTER(0xABCD));
// Koids has their own type, but it's really just a uint64_t that has special meaning on the most
// significant bit being 1 or not.
TRACE_INSTANT("example", "example_instant_args", TRACE_SCOPE_THREAD, "somekoid", TA_KOID(0x0012));
// Booleans with display as "true" or "false"
TRACE_INSTANT("example", "example_instant_args", TRACE_SCOPE_THREAD, "somebool", true);
TRACE_INSTANT("example", "example_instant_args", TRACE_SCOPE_THREAD, "someotherbool", false);
async::PostDelayedTask(
dispatcher, [dispatcher] { EmitSomeEvents(dispatcher); }, zx::msec(10));
}
int main() {
async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
async_dispatcher_t* dispatcher = loop.dispatcher();
// Once we link against tracing and include the tracing client shard, all we need to do in create
// TraceProvider object.
trace::TraceProviderWithFdio trace_provider(dispatcher, "example_trace_provider");
// Let's continuously emit some trace events
async::PostTask(dispatcher, [dispatcher] { EmitSomeEvents(dispatcher); });
// Don't forget to start the loop!
loop.Run();
return 0;
}