1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2019-2021 Collabora, Ltd.
3bf215546Sopenharmony_ci * Author: Antonio Caggiano <antonio.caggiano@collabora.com>
4bf215546Sopenharmony_ci * Author: Rohan Garg <rohan.garg@collabora.com>
5bf215546Sopenharmony_ci * Author: Robert Beckett <bob.beckett@collabora.com>
6bf215546Sopenharmony_ci * Author: Corentin Noël <corentin.noel@collabora.com>
7bf215546Sopenharmony_ci *
8bf215546Sopenharmony_ci * SPDX-License-Identifier: MIT
9bf215546Sopenharmony_ci */
10bf215546Sopenharmony_ci
11bf215546Sopenharmony_ci#include "pps_datasource.h"
12bf215546Sopenharmony_ci#include "pps_driver.h"
13bf215546Sopenharmony_ci
14bf215546Sopenharmony_ci#include <condition_variable>
15bf215546Sopenharmony_ci#include <thread>
16bf215546Sopenharmony_ci#include <variant>
17bf215546Sopenharmony_ci
18bf215546Sopenharmony_ci// Minimum supported sampling period in nanoseconds
19bf215546Sopenharmony_ci#define MIN_SAMPLING_PERIOD_NS 50000
20bf215546Sopenharmony_ci
21bf215546Sopenharmony_ci#define CORRELATION_TIMESTAMP_PERIOD (1000000000ull)
22bf215546Sopenharmony_ci
23bf215546Sopenharmony_cinamespace pps
24bf215546Sopenharmony_ci{
25bf215546Sopenharmony_cistatic std::string driver_name;
26bf215546Sopenharmony_ci
27bf215546Sopenharmony_ci/// Synchronize access to started_cv and started
28bf215546Sopenharmony_cistatic std::mutex started_m;
29bf215546Sopenharmony_cistatic std::condition_variable started_cv;
30bf215546Sopenharmony_cistatic bool started = false;
31bf215546Sopenharmony_ci
32bf215546Sopenharmony_cifloat ms(const std::chrono::nanoseconds &t)
33bf215546Sopenharmony_ci{
34bf215546Sopenharmony_ci   return t.count() / 1000000.0f;
35bf215546Sopenharmony_ci}
36bf215546Sopenharmony_ci
37bf215546Sopenharmony_civoid GpuDataSource::OnSetup(const SetupArgs &args)
38bf215546Sopenharmony_ci{
39bf215546Sopenharmony_ci   // Create drivers for all supported devices
40bf215546Sopenharmony_ci   auto drm_devices = DrmDevice::create_all();
41bf215546Sopenharmony_ci   for (auto &drm_device : drm_devices) {
42bf215546Sopenharmony_ci      if (drm_device.name != driver_name)
43bf215546Sopenharmony_ci         continue;
44bf215546Sopenharmony_ci
45bf215546Sopenharmony_ci      if (auto driver = Driver::get_driver(std::move(drm_device))) {
46bf215546Sopenharmony_ci         if (!driver->init_perfcnt()) {
47bf215546Sopenharmony_ci            // Skip failing driver
48bf215546Sopenharmony_ci            PPS_LOG_ERROR("Failed to initialize %s driver", driver->drm_device.name.c_str());
49bf215546Sopenharmony_ci            continue;
50bf215546Sopenharmony_ci         }
51bf215546Sopenharmony_ci
52bf215546Sopenharmony_ci         this->driver = driver;
53bf215546Sopenharmony_ci      }
54bf215546Sopenharmony_ci   }
55bf215546Sopenharmony_ci   if (driver == nullptr) {
56bf215546Sopenharmony_ci      PPS_LOG_FATAL("No DRM devices supported");
57bf215546Sopenharmony_ci   }
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci   // Parse perfetto config
60bf215546Sopenharmony_ci   const std::string &config_raw = args.config->gpu_counter_config_raw();
61bf215546Sopenharmony_ci   perfetto::protos::pbzero::GpuCounterConfig::Decoder config(config_raw);
62bf215546Sopenharmony_ci
63bf215546Sopenharmony_ci   if (config.has_counter_ids()) {
64bf215546Sopenharmony_ci      // Get enabled counters
65bf215546Sopenharmony_ci      PPS_LOG_IMPORTANT("Selecting counters");
66bf215546Sopenharmony_ci      for (auto it = config.counter_ids(); it; ++it) {
67bf215546Sopenharmony_ci         uint32_t counter_id = it->as_uint32();
68bf215546Sopenharmony_ci         driver->enable_counter(counter_id);
69bf215546Sopenharmony_ci      }
70bf215546Sopenharmony_ci   } else {
71bf215546Sopenharmony_ci      // Enable all counters
72bf215546Sopenharmony_ci      driver->enable_all_counters();
73bf215546Sopenharmony_ci   }
74bf215546Sopenharmony_ci
75bf215546Sopenharmony_ci   // Get sampling period
76bf215546Sopenharmony_ci   auto min_sampling_period = std::chrono::nanoseconds(MIN_SAMPLING_PERIOD_NS);
77bf215546Sopenharmony_ci
78bf215546Sopenharmony_ci   auto dev_supported = std::chrono::nanoseconds(driver->get_min_sampling_period_ns());
79bf215546Sopenharmony_ci   if (dev_supported > min_sampling_period) {
80bf215546Sopenharmony_ci      min_sampling_period = dev_supported;
81bf215546Sopenharmony_ci   }
82bf215546Sopenharmony_ci
83bf215546Sopenharmony_ci   time_to_sleep = std::max(time_to_sleep, min_sampling_period);
84bf215546Sopenharmony_ci
85bf215546Sopenharmony_ci   if (config.has_counter_period_ns()) {
86bf215546Sopenharmony_ci      auto requested_sampling_period = std::chrono::nanoseconds(config.counter_period_ns());
87bf215546Sopenharmony_ci      if (requested_sampling_period < min_sampling_period) {
88bf215546Sopenharmony_ci         PPS_LOG_ERROR("Sampling period should be greater than %" PRIu64 " ns (%.2f ms)",
89bf215546Sopenharmony_ci            uint64_t(min_sampling_period.count()),
90bf215546Sopenharmony_ci            ms(min_sampling_period));
91bf215546Sopenharmony_ci      } else {
92bf215546Sopenharmony_ci         time_to_sleep = requested_sampling_period;
93bf215546Sopenharmony_ci      }
94bf215546Sopenharmony_ci   }
95bf215546Sopenharmony_ci   PPS_LOG("Sampling period set to %" PRIu64 " ns", uint64_t(time_to_sleep.count()));
96bf215546Sopenharmony_ci}
97bf215546Sopenharmony_ci
98bf215546Sopenharmony_civoid GpuDataSource::OnStart(const StartArgs &args)
99bf215546Sopenharmony_ci{
100bf215546Sopenharmony_ci   driver->enable_perfcnt(time_to_sleep.count());
101bf215546Sopenharmony_ci
102bf215546Sopenharmony_ci   state = State::Start;
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_ci   {
105bf215546Sopenharmony_ci      std::lock_guard<std::mutex> lock(started_m);
106bf215546Sopenharmony_ci      started = true;
107bf215546Sopenharmony_ci   }
108bf215546Sopenharmony_ci   started_cv.notify_all();
109bf215546Sopenharmony_ci}
110bf215546Sopenharmony_ci
111bf215546Sopenharmony_civoid close_callback(GpuDataSource::TraceContext ctx)
112bf215546Sopenharmony_ci{
113bf215546Sopenharmony_ci   auto packet = ctx.NewTracePacket();
114bf215546Sopenharmony_ci   packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
115bf215546Sopenharmony_ci   packet->set_timestamp(perfetto::base::GetBootTimeNs().count());
116bf215546Sopenharmony_ci   packet->Finalize();
117bf215546Sopenharmony_ci   ctx.Flush();
118bf215546Sopenharmony_ci   PPS_LOG("Context flushed");
119bf215546Sopenharmony_ci}
120bf215546Sopenharmony_ci
121bf215546Sopenharmony_civoid GpuDataSource::OnStop(const StopArgs &args)
122bf215546Sopenharmony_ci{
123bf215546Sopenharmony_ci   state = State::Stop;
124bf215546Sopenharmony_ci   auto stop_closure = args.HandleStopAsynchronously();
125bf215546Sopenharmony_ci   Trace(close_callback);
126bf215546Sopenharmony_ci   stop_closure();
127bf215546Sopenharmony_ci
128bf215546Sopenharmony_ci   driver->disable_perfcnt();
129bf215546Sopenharmony_ci   driver = nullptr;
130bf215546Sopenharmony_ci
131bf215546Sopenharmony_ci   std::lock_guard<std::mutex> lock(started_m);
132bf215546Sopenharmony_ci   started = false;
133bf215546Sopenharmony_ci}
134bf215546Sopenharmony_ci
135bf215546Sopenharmony_civoid GpuDataSource::wait_started()
136bf215546Sopenharmony_ci{
137bf215546Sopenharmony_ci   std::unique_lock<std::mutex> lock(started_m);
138bf215546Sopenharmony_ci   if (!started) {
139bf215546Sopenharmony_ci      PPS_LOG("Waiting for start");
140bf215546Sopenharmony_ci      started_cv.wait(lock, [] { return started; });
141bf215546Sopenharmony_ci   }
142bf215546Sopenharmony_ci}
143bf215546Sopenharmony_ci
144bf215546Sopenharmony_civoid GpuDataSource::register_data_source(const std::string &_driver_name)
145bf215546Sopenharmony_ci{
146bf215546Sopenharmony_ci   driver_name = _driver_name;
147bf215546Sopenharmony_ci   static perfetto::DataSourceDescriptor dsd;
148bf215546Sopenharmony_ci   dsd.set_name("gpu.counters." + driver_name);
149bf215546Sopenharmony_ci   Register(dsd);
150bf215546Sopenharmony_ci}
151bf215546Sopenharmony_ci
152bf215546Sopenharmony_civoid add_group(perfetto::protos::pbzero::GpuCounterDescriptor *desc,
153bf215546Sopenharmony_ci   const CounterGroup &group,
154bf215546Sopenharmony_ci   const std::string &prefix,
155bf215546Sopenharmony_ci   int32_t gpu_num)
156bf215546Sopenharmony_ci{
157bf215546Sopenharmony_ci   if (!group.counters.empty()) {
158bf215546Sopenharmony_ci      // Define a block for each group containing counters
159bf215546Sopenharmony_ci      auto block_desc = desc->add_blocks();
160bf215546Sopenharmony_ci      block_desc->set_name(prefix + "." + group.name);
161bf215546Sopenharmony_ci      block_desc->set_block_id(group.id);
162bf215546Sopenharmony_ci
163bf215546Sopenharmony_ci      // Associate counters to blocks
164bf215546Sopenharmony_ci      for (auto id : group.counters) {
165bf215546Sopenharmony_ci         block_desc->add_counter_ids(id);
166bf215546Sopenharmony_ci      }
167bf215546Sopenharmony_ci   }
168bf215546Sopenharmony_ci
169bf215546Sopenharmony_ci   for (auto const &sub : group.subgroups) {
170bf215546Sopenharmony_ci      // Perfetto doesnt currently support nested groups.
171bf215546Sopenharmony_ci      // Flatten group hierarchy, using dot separator
172bf215546Sopenharmony_ci      add_group(desc, sub, prefix + "." + group.name, gpu_num);
173bf215546Sopenharmony_ci   }
174bf215546Sopenharmony_ci}
175bf215546Sopenharmony_ci
176bf215546Sopenharmony_civoid add_descriptors(perfetto::protos::pbzero::GpuCounterEvent *event,
177bf215546Sopenharmony_ci   std::vector<CounterGroup> const &groups,
178bf215546Sopenharmony_ci   std::vector<Counter> const &counters,
179bf215546Sopenharmony_ci   Driver &driver)
180bf215546Sopenharmony_ci{
181bf215546Sopenharmony_ci   // Start a counter descriptor
182bf215546Sopenharmony_ci   auto desc = event->set_counter_descriptor();
183bf215546Sopenharmony_ci
184bf215546Sopenharmony_ci   // Add the groups
185bf215546Sopenharmony_ci   for (auto const &group : groups) {
186bf215546Sopenharmony_ci      add_group(desc, group, driver.drm_device.name, driver.drm_device.gpu_num);
187bf215546Sopenharmony_ci   }
188bf215546Sopenharmony_ci
189bf215546Sopenharmony_ci   // Add the counters
190bf215546Sopenharmony_ci   for (auto const &counter : counters) {
191bf215546Sopenharmony_ci      auto spec = desc->add_specs();
192bf215546Sopenharmony_ci      spec->set_counter_id(counter.id);
193bf215546Sopenharmony_ci      spec->set_name(counter.name);
194bf215546Sopenharmony_ci
195bf215546Sopenharmony_ci      auto units = perfetto::protos::pbzero::GpuCounterDescriptor::NONE;
196bf215546Sopenharmony_ci      switch (counter.units) {
197bf215546Sopenharmony_ci      case Counter::Units::Percent:
198bf215546Sopenharmony_ci         units = perfetto::protos::pbzero::GpuCounterDescriptor::PERCENT;
199bf215546Sopenharmony_ci         break;
200bf215546Sopenharmony_ci      case Counter::Units::Byte:
201bf215546Sopenharmony_ci         units = perfetto::protos::pbzero::GpuCounterDescriptor::BYTE;
202bf215546Sopenharmony_ci         break;
203bf215546Sopenharmony_ci      case Counter::Units::Hertz:
204bf215546Sopenharmony_ci         units = perfetto::protos::pbzero::GpuCounterDescriptor::HERTZ;
205bf215546Sopenharmony_ci         break;
206bf215546Sopenharmony_ci      case Counter::Units::None:
207bf215546Sopenharmony_ci         units = perfetto::protos::pbzero::GpuCounterDescriptor::NONE;
208bf215546Sopenharmony_ci         break;
209bf215546Sopenharmony_ci      default:
210bf215546Sopenharmony_ci         assert(false && "Missing counter units type!");
211bf215546Sopenharmony_ci         break;
212bf215546Sopenharmony_ci      }
213bf215546Sopenharmony_ci      spec->add_numerator_units(units);
214bf215546Sopenharmony_ci   }
215bf215546Sopenharmony_ci}
216bf215546Sopenharmony_ci
217bf215546Sopenharmony_civoid add_samples(perfetto::protos::pbzero::GpuCounterEvent &event, const Driver &driver)
218bf215546Sopenharmony_ci{
219bf215546Sopenharmony_ci   if (driver.enabled_counters.size() == 0) {
220bf215546Sopenharmony_ci      PPS_LOG_FATAL("There are no counters enabled");
221bf215546Sopenharmony_ci   }
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_ci   for (const auto &counter : driver.enabled_counters) {
224bf215546Sopenharmony_ci      auto counter_event = event.add_counters();
225bf215546Sopenharmony_ci
226bf215546Sopenharmony_ci      counter_event->set_counter_id(counter.id);
227bf215546Sopenharmony_ci
228bf215546Sopenharmony_ci      auto value = counter.get_value(driver);
229bf215546Sopenharmony_ci      if (auto d_value = std::get_if<double>(&value)) {
230bf215546Sopenharmony_ci         counter_event->set_double_value(*d_value);
231bf215546Sopenharmony_ci      } else if (auto i_value = std::get_if<int64_t>(&value)) {
232bf215546Sopenharmony_ci         counter_event->set_int_value(*i_value);
233bf215546Sopenharmony_ci      } else {
234bf215546Sopenharmony_ci         PPS_LOG_ERROR("Failed to get value for counter %s", counter.name.c_str());
235bf215546Sopenharmony_ci      }
236bf215546Sopenharmony_ci   }
237bf215546Sopenharmony_ci}
238bf215546Sopenharmony_ci
239bf215546Sopenharmony_civoid add_timestamp(perfetto::protos::pbzero::ClockSnapshot *event, const Driver *driver)
240bf215546Sopenharmony_ci{
241bf215546Sopenharmony_ci   uint32_t gpu_clock_id = driver->gpu_clock_id();
242bf215546Sopenharmony_ci   if (perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME == gpu_clock_id)
243bf215546Sopenharmony_ci      return;
244bf215546Sopenharmony_ci
245bf215546Sopenharmony_ci   // Send a correlation event between GPU & CPU timestamps
246bf215546Sopenharmony_ci   uint64_t cpu_ts = perfetto::base::GetBootTimeNs().count();
247bf215546Sopenharmony_ci   uint64_t gpu_ts = driver->gpu_timestamp();
248bf215546Sopenharmony_ci
249bf215546Sopenharmony_ci   {
250bf215546Sopenharmony_ci      auto clock = event->add_clocks();
251bf215546Sopenharmony_ci
252bf215546Sopenharmony_ci      clock->set_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
253bf215546Sopenharmony_ci      clock->set_timestamp(cpu_ts);
254bf215546Sopenharmony_ci   }
255bf215546Sopenharmony_ci
256bf215546Sopenharmony_ci   {
257bf215546Sopenharmony_ci      auto clock = event->add_clocks();
258bf215546Sopenharmony_ci
259bf215546Sopenharmony_ci      clock->set_clock_id(gpu_clock_id);
260bf215546Sopenharmony_ci      clock->set_timestamp(gpu_ts);
261bf215546Sopenharmony_ci   }
262bf215546Sopenharmony_ci}
263bf215546Sopenharmony_ci
264bf215546Sopenharmony_civoid GpuDataSource::trace(TraceContext &ctx)
265bf215546Sopenharmony_ci{
266bf215546Sopenharmony_ci   using namespace perfetto::protos::pbzero;
267bf215546Sopenharmony_ci
268bf215546Sopenharmony_ci   if (auto state = ctx.GetIncrementalState(); state->was_cleared) {
269bf215546Sopenharmony_ci      descriptor_timestamp = perfetto::base::GetBootTimeNs().count();
270bf215546Sopenharmony_ci
271bf215546Sopenharmony_ci      {
272bf215546Sopenharmony_ci         // Mark any incremental state before this point invalid
273bf215546Sopenharmony_ci         auto packet = ctx.NewTracePacket();
274bf215546Sopenharmony_ci         packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
275bf215546Sopenharmony_ci         packet->set_timestamp(descriptor_timestamp);
276bf215546Sopenharmony_ci         packet->set_sequence_flags(TracePacket::SEQ_INCREMENTAL_STATE_CLEARED);
277bf215546Sopenharmony_ci      }
278bf215546Sopenharmony_ci
279bf215546Sopenharmony_ci      descriptor_timestamp = perfetto::base::GetBootTimeNs().count();
280bf215546Sopenharmony_ci      {
281bf215546Sopenharmony_ci         // Counter descriptions
282bf215546Sopenharmony_ci         auto packet = ctx.NewTracePacket();
283bf215546Sopenharmony_ci         packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
284bf215546Sopenharmony_ci         packet->set_timestamp(descriptor_timestamp);
285bf215546Sopenharmony_ci         auto event = packet->set_gpu_counter_event();
286bf215546Sopenharmony_ci         event->set_gpu_id(driver->drm_device.gpu_num);
287bf215546Sopenharmony_ci
288bf215546Sopenharmony_ci         auto &groups = driver->groups;
289bf215546Sopenharmony_ci         auto &counters = driver->enabled_counters;
290bf215546Sopenharmony_ci         add_descriptors(event, groups, counters, *driver);
291bf215546Sopenharmony_ci      }
292bf215546Sopenharmony_ci
293bf215546Sopenharmony_ci      {
294bf215546Sopenharmony_ci         // Initial timestamp correlation event
295bf215546Sopenharmony_ci         auto packet = ctx.NewTracePacket();
296bf215546Sopenharmony_ci         packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
297bf215546Sopenharmony_ci         packet->set_timestamp(descriptor_timestamp);
298bf215546Sopenharmony_ci         last_correlation_timestamp = perfetto::base::GetBootTimeNs().count();
299bf215546Sopenharmony_ci         auto event = packet->set_clock_snapshot();
300bf215546Sopenharmony_ci         add_timestamp(event, driver);
301bf215546Sopenharmony_ci      }
302bf215546Sopenharmony_ci
303bf215546Sopenharmony_ci      // Capture GPU timestamp of the first packet. Anything prior to this can
304bf215546Sopenharmony_ci      // be discarded.
305bf215546Sopenharmony_ci      descriptor_gpu_timestamp = driver->gpu_timestamp();
306bf215546Sopenharmony_ci      state->was_cleared = false;
307bf215546Sopenharmony_ci   }
308bf215546Sopenharmony_ci
309bf215546Sopenharmony_ci   // Save current scheduler for restoring later
310bf215546Sopenharmony_ci   int prev_sched_policy = sched_getscheduler(0);
311bf215546Sopenharmony_ci   sched_param prev_priority_param;
312bf215546Sopenharmony_ci   sched_getparam(0, &prev_priority_param);
313bf215546Sopenharmony_ci
314bf215546Sopenharmony_ci   // Use FIFO policy to avoid preemption while collecting counters
315bf215546Sopenharmony_ci   int sched_policy = SCHED_FIFO;
316bf215546Sopenharmony_ci   // Do not use max priority to avoid starving migration and watchdog threads
317bf215546Sopenharmony_ci   int priority_value = sched_get_priority_max(sched_policy) - 1;
318bf215546Sopenharmony_ci   sched_param priority_param { priority_value };
319bf215546Sopenharmony_ci   sched_setscheduler(0, sched_policy, &priority_param);
320bf215546Sopenharmony_ci
321bf215546Sopenharmony_ci   if (driver->dump_perfcnt()) {
322bf215546Sopenharmony_ci      while (auto gpu_timestamp = driver->next()) {
323bf215546Sopenharmony_ci         if (gpu_timestamp <= descriptor_gpu_timestamp) {
324bf215546Sopenharmony_ci            // Do not send counter values before counter descriptors
325bf215546Sopenharmony_ci            PPS_LOG_ERROR("Skipping counter values coming before descriptors");
326bf215546Sopenharmony_ci            continue;
327bf215546Sopenharmony_ci         }
328bf215546Sopenharmony_ci
329bf215546Sopenharmony_ci         auto packet = ctx.NewTracePacket();
330bf215546Sopenharmony_ci         packet->set_timestamp_clock_id(driver->gpu_clock_id());
331bf215546Sopenharmony_ci         packet->set_timestamp(gpu_timestamp);
332bf215546Sopenharmony_ci
333bf215546Sopenharmony_ci         auto event = packet->set_gpu_counter_event();
334bf215546Sopenharmony_ci         event->set_gpu_id(driver->drm_device.gpu_num);
335bf215546Sopenharmony_ci
336bf215546Sopenharmony_ci         add_samples(*event, *driver);
337bf215546Sopenharmony_ci      }
338bf215546Sopenharmony_ci   }
339bf215546Sopenharmony_ci
340bf215546Sopenharmony_ci   uint64_t cpu_ts = perfetto::base::GetBootTimeNs().count();
341bf215546Sopenharmony_ci   if ((cpu_ts - last_correlation_timestamp) > CORRELATION_TIMESTAMP_PERIOD) {
342bf215546Sopenharmony_ci      auto packet = ctx.NewTracePacket();
343bf215546Sopenharmony_ci      packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_BOOTTIME);
344bf215546Sopenharmony_ci      packet->set_timestamp(cpu_ts);
345bf215546Sopenharmony_ci      auto event = packet->set_clock_snapshot();
346bf215546Sopenharmony_ci      add_timestamp(event, driver);
347bf215546Sopenharmony_ci      last_correlation_timestamp = cpu_ts;
348bf215546Sopenharmony_ci   }
349bf215546Sopenharmony_ci
350bf215546Sopenharmony_ci   // Reset normal scheduler
351bf215546Sopenharmony_ci   sched_setscheduler(0, prev_sched_policy, &prev_priority_param);
352bf215546Sopenharmony_ci}
353bf215546Sopenharmony_ci
354bf215546Sopenharmony_civoid GpuDataSource::trace_callback(TraceContext ctx)
355bf215546Sopenharmony_ci{
356bf215546Sopenharmony_ci   using namespace std::chrono;
357bf215546Sopenharmony_ci
358bf215546Sopenharmony_ci   nanoseconds sleep_time = nanoseconds(0);
359bf215546Sopenharmony_ci
360bf215546Sopenharmony_ci   if (auto data_source = ctx.GetDataSourceLocked()) {
361bf215546Sopenharmony_ci      if (data_source->time_to_sleep > data_source->time_to_trace) {
362bf215546Sopenharmony_ci         sleep_time = data_source->time_to_sleep - data_source->time_to_trace;
363bf215546Sopenharmony_ci      }
364bf215546Sopenharmony_ci   }
365bf215546Sopenharmony_ci
366bf215546Sopenharmony_ci   // Wait sampling period before tracing
367bf215546Sopenharmony_ci   std::this_thread::sleep_for(sleep_time);
368bf215546Sopenharmony_ci
369bf215546Sopenharmony_ci   auto time_zero = perfetto::base::GetBootTimeNs();
370bf215546Sopenharmony_ci   if (auto data_source = ctx.GetDataSourceLocked()) {
371bf215546Sopenharmony_ci      // Check data source is still running
372bf215546Sopenharmony_ci      if (data_source->state == pps::State::Start) {
373bf215546Sopenharmony_ci         data_source->trace(ctx);
374bf215546Sopenharmony_ci         data_source->time_to_trace = perfetto::base::GetBootTimeNs() - time_zero;
375bf215546Sopenharmony_ci      }
376bf215546Sopenharmony_ci   } else {
377bf215546Sopenharmony_ci      PPS_LOG("Tracing finished");
378bf215546Sopenharmony_ci   }
379bf215546Sopenharmony_ci}
380bf215546Sopenharmony_ci
381bf215546Sopenharmony_ci} // namespace pps
382