1*61c4878aSAndroid Build Coastguard Worker // Copyright 2020 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker //==============================================================================
15*61c4878aSAndroid Build Coastguard Worker // ninja -C out/host trace_sample
16*61c4878aSAndroid Build Coastguard Worker // ./out/host/obj/pw_trace_tokenized/trace_sample
17*61c4878aSAndroid Build Coastguard Worker // python pw_trace_tokenized/py/trace.py -i out1.bin -o trace.json
18*61c4878aSAndroid Build Coastguard Worker // ./out/host/obj/pw_trace_tokenized/trace_sample
19*61c4878aSAndroid Build Coastguard Worker #include <stdio.h>
20*61c4878aSAndroid Build Coastguard Worker
21*61c4878aSAndroid Build Coastguard Worker #include <array>
22*61c4878aSAndroid Build Coastguard Worker #include <chrono>
23*61c4878aSAndroid Build Coastguard Worker
24*61c4878aSAndroid Build Coastguard Worker #include "pw_ring_buffer/prefixed_entry_ring_buffer.h"
25*61c4878aSAndroid Build Coastguard Worker #include "pw_trace/trace.h"
26*61c4878aSAndroid Build Coastguard Worker
27*61c4878aSAndroid Build Coastguard Worker #ifndef SAMPLE_APP_SLEEP_MILLIS
28*61c4878aSAndroid Build Coastguard Worker #include <thread>
29*61c4878aSAndroid Build Coastguard Worker #define SAMPLE_APP_SLEEP_MILLIS(millis) \
30*61c4878aSAndroid Build Coastguard Worker std::this_thread::sleep_for(std::chrono::milliseconds(millis));
31*61c4878aSAndroid Build Coastguard Worker #endif // SAMPLE_APP_SLEEP_MILLIS
32*61c4878aSAndroid Build Coastguard Worker
33*61c4878aSAndroid Build Coastguard Worker using namespace std::chrono;
34*61c4878aSAndroid Build Coastguard Worker
35*61c4878aSAndroid Build Coastguard Worker namespace {
36*61c4878aSAndroid Build Coastguard Worker
37*61c4878aSAndroid Build Coastguard Worker // Time helper function
38*61c4878aSAndroid Build Coastguard Worker auto start = system_clock::now();
GetTimeSinceBootMillis()39*61c4878aSAndroid Build Coastguard Worker uint32_t GetTimeSinceBootMillis() {
40*61c4878aSAndroid Build Coastguard Worker auto delta = system_clock::now() - start;
41*61c4878aSAndroid Build Coastguard Worker return floor<milliseconds>(delta).count();
42*61c4878aSAndroid Build Coastguard Worker }
43*61c4878aSAndroid Build Coastguard Worker
44*61c4878aSAndroid Build Coastguard Worker // Creating a very simple runnable with predictable behaviour to help with the
45*61c4878aSAndroid Build Coastguard Worker // example. Each Runnable, has a method ShouldRun which indicates if it has work
46*61c4878aSAndroid Build Coastguard Worker // to do, calling Run will then do the work.
47*61c4878aSAndroid Build Coastguard Worker class SimpleRunnable {
48*61c4878aSAndroid Build Coastguard Worker public:
49*61c4878aSAndroid Build Coastguard Worker virtual const char* Name() const = 0;
50*61c4878aSAndroid Build Coastguard Worker virtual bool ShouldRun() = 0;
51*61c4878aSAndroid Build Coastguard Worker virtual void Run() = 0;
~SimpleRunnable()52*61c4878aSAndroid Build Coastguard Worker virtual ~SimpleRunnable() {}
53*61c4878aSAndroid Build Coastguard Worker };
54*61c4878aSAndroid Build Coastguard Worker
55*61c4878aSAndroid Build Coastguard Worker // Processing module
56*61c4878aSAndroid Build Coastguard Worker // Uses trace_id and groups to track the multiple stages of "processing".
57*61c4878aSAndroid Build Coastguard Worker // These are intentionally long running so they will be processing concurrently.
58*61c4878aSAndroid Build Coastguard Worker // The trace ID is used to seperates these concurrent jobs.
59*61c4878aSAndroid Build Coastguard Worker #undef PW_TRACE_MODULE_NAME
60*61c4878aSAndroid Build Coastguard Worker #define PW_TRACE_MODULE_NAME "Processing"
61*61c4878aSAndroid Build Coastguard Worker class ProcessingTask : public SimpleRunnable {
62*61c4878aSAndroid Build Coastguard Worker public:
63*61c4878aSAndroid Build Coastguard Worker // Run task maintains a buffer of "jobs" which just sleeps for an amount of
64*61c4878aSAndroid Build Coastguard Worker // time and reposts the job until the value is zero. This gives an async
65*61c4878aSAndroid Build Coastguard Worker // behaviour where multiple of the same job are happening concurrently, and
66*61c4878aSAndroid Build Coastguard Worker // also has a nesting effect of a job having many stages.
67*61c4878aSAndroid Build Coastguard Worker struct Job {
68*61c4878aSAndroid Build Coastguard Worker uint32_t job_id;
69*61c4878aSAndroid Build Coastguard Worker uint8_t value;
70*61c4878aSAndroid Build Coastguard Worker };
71*61c4878aSAndroid Build Coastguard Worker struct JobBytes {
72*61c4878aSAndroid Build Coastguard Worker union {
73*61c4878aSAndroid Build Coastguard Worker Job job;
74*61c4878aSAndroid Build Coastguard Worker std::byte bytes[sizeof(Job)];
75*61c4878aSAndroid Build Coastguard Worker };
76*61c4878aSAndroid Build Coastguard Worker };
ProcessingTask()77*61c4878aSAndroid Build Coastguard Worker ProcessingTask() {
78*61c4878aSAndroid Build Coastguard Worker // Buffer is used for the job queue.
79*61c4878aSAndroid Build Coastguard Worker pw::span<std::byte> buf_span = pw::span<std::byte>(
80*61c4878aSAndroid Build Coastguard Worker reinterpret_cast<std::byte*>(jobs_buffer_), sizeof(jobs_buffer_));
81*61c4878aSAndroid Build Coastguard Worker jobs_.SetBuffer(buf_span)
82*61c4878aSAndroid Build Coastguard Worker .IgnoreError(); // TODO: b/242598609 - Handle Status properly
83*61c4878aSAndroid Build Coastguard Worker }
Name() const84*61c4878aSAndroid Build Coastguard Worker const char* Name() const override { return "Processing Task"; }
ShouldRun()85*61c4878aSAndroid Build Coastguard Worker bool ShouldRun() override { return jobs_.EntryCount() > 0; }
Run()86*61c4878aSAndroid Build Coastguard Worker void Run() override {
87*61c4878aSAndroid Build Coastguard Worker JobBytes job_bytes;
88*61c4878aSAndroid Build Coastguard Worker size_t bytes_read;
89*61c4878aSAndroid Build Coastguard Worker
90*61c4878aSAndroid Build Coastguard Worker // Trace the job count backlog
91*61c4878aSAndroid Build Coastguard Worker size_t entry_count = jobs_.EntryCount();
92*61c4878aSAndroid Build Coastguard Worker
93*61c4878aSAndroid Build Coastguard Worker // Get the next job from the queue.
94*61c4878aSAndroid Build Coastguard Worker jobs_.PeekFront(job_bytes.bytes, &bytes_read)
95*61c4878aSAndroid Build Coastguard Worker .IgnoreError(); // TODO: b/242598609 - Handle Status properly
96*61c4878aSAndroid Build Coastguard Worker jobs_.PopFront()
97*61c4878aSAndroid Build Coastguard Worker .IgnoreError(); // TODO: b/242598609 - Handle Status properly
98*61c4878aSAndroid Build Coastguard Worker Job& job = job_bytes.job;
99*61c4878aSAndroid Build Coastguard Worker
100*61c4878aSAndroid Build Coastguard Worker // Process the job
101*61c4878aSAndroid Build Coastguard Worker ProcessingJob(job);
102*61c4878aSAndroid Build Coastguard Worker if (job.value > 0) { // repost for more work if value > 0
103*61c4878aSAndroid Build Coastguard Worker AddJobInternal(job.job_id, job.value - 1);
104*61c4878aSAndroid Build Coastguard Worker } else {
105*61c4878aSAndroid Build Coastguard Worker PW_TRACE_END("Job", "Process", job.job_id);
106*61c4878aSAndroid Build Coastguard Worker }
107*61c4878aSAndroid Build Coastguard Worker PW_TRACE_INSTANT_DATA("job_backlog_count",
108*61c4878aSAndroid Build Coastguard Worker "@pw_arg_counter",
109*61c4878aSAndroid Build Coastguard Worker &entry_count,
110*61c4878aSAndroid Build Coastguard Worker sizeof(entry_count));
111*61c4878aSAndroid Build Coastguard Worker }
AddJob(uint32_t job_id,uint8_t value)112*61c4878aSAndroid Build Coastguard Worker void AddJob(uint32_t job_id, uint8_t value) {
113*61c4878aSAndroid Build Coastguard Worker PW_TRACE_START_DATA(
114*61c4878aSAndroid Build Coastguard Worker "Job", "Process", job_id, "@pw_py_struct_fmt:B", &value, sizeof(value));
115*61c4878aSAndroid Build Coastguard Worker AddJobInternal(job_id, value);
116*61c4878aSAndroid Build Coastguard Worker }
117*61c4878aSAndroid Build Coastguard Worker
118*61c4878aSAndroid Build Coastguard Worker private:
119*61c4878aSAndroid Build Coastguard Worker static constexpr size_t kMaxJobs = 10;
120*61c4878aSAndroid Build Coastguard Worker static constexpr size_t kProcessingTimePerValueMillis = 250;
121*61c4878aSAndroid Build Coastguard Worker Job jobs_buffer_[kMaxJobs];
122*61c4878aSAndroid Build Coastguard Worker pw::ring_buffer::PrefixedEntryRingBuffer jobs_{false};
123*61c4878aSAndroid Build Coastguard Worker
ProcessingJob(const Job & job)124*61c4878aSAndroid Build Coastguard Worker void ProcessingJob(const Job& job) {
125*61c4878aSAndroid Build Coastguard Worker PW_TRACE_FUNCTION("Process", job.job_id);
126*61c4878aSAndroid Build Coastguard Worker for (uint8_t i = 0; i < job.value; i++) {
127*61c4878aSAndroid Build Coastguard Worker PW_TRACE_SCOPE("loop", "Process", job.job_id);
128*61c4878aSAndroid Build Coastguard Worker SAMPLE_APP_SLEEP_MILLIS(50); // Fake processing time
129*61c4878aSAndroid Build Coastguard Worker SomeProcessing(&job);
130*61c4878aSAndroid Build Coastguard Worker }
131*61c4878aSAndroid Build Coastguard Worker }
132*61c4878aSAndroid Build Coastguard Worker
SomeProcessing(const Job * job)133*61c4878aSAndroid Build Coastguard Worker void SomeProcessing(const Job* job) {
134*61c4878aSAndroid Build Coastguard Worker uint32_t id = job->job_id;
135*61c4878aSAndroid Build Coastguard Worker PW_TRACE_FUNCTION("Process", id);
136*61c4878aSAndroid Build Coastguard Worker SAMPLE_APP_SLEEP_MILLIS(
137*61c4878aSAndroid Build Coastguard Worker kProcessingTimePerValueMillis); // Fake processing time
138*61c4878aSAndroid Build Coastguard Worker }
AddJobInternal(uint32_t job_id,uint8_t value)139*61c4878aSAndroid Build Coastguard Worker void AddJobInternal(uint32_t job_id, uint8_t value) {
140*61c4878aSAndroid Build Coastguard Worker JobBytes job{.job = {.job_id = job_id, .value = value}};
141*61c4878aSAndroid Build Coastguard Worker jobs_.PushBack(job.bytes)
142*61c4878aSAndroid Build Coastguard Worker .IgnoreError(); // TODO: b/242598609 - Handle Status properly
143*61c4878aSAndroid Build Coastguard Worker }
144*61c4878aSAndroid Build Coastguard Worker } processing_task;
145*61c4878aSAndroid Build Coastguard Worker
146*61c4878aSAndroid Build Coastguard Worker // Input Module
147*61c4878aSAndroid Build Coastguard Worker // Uses traces in groups to indicate the different steps of reading the new
148*61c4878aSAndroid Build Coastguard Worker // event.
149*61c4878aSAndroid Build Coastguard Worker // Uses an instant data event to dump the read sample into the trace.
150*61c4878aSAndroid Build Coastguard Worker #undef PW_TRACE_MODULE_NAME
151*61c4878aSAndroid Build Coastguard Worker #define PW_TRACE_MODULE_NAME "Input"
152*61c4878aSAndroid Build Coastguard Worker class InputTask : public SimpleRunnable {
153*61c4878aSAndroid Build Coastguard Worker // Every second generate new output
154*61c4878aSAndroid Build Coastguard Worker public:
Name() const155*61c4878aSAndroid Build Coastguard Worker const char* Name() const override { return "Input Task"; }
ShouldRun()156*61c4878aSAndroid Build Coastguard Worker bool ShouldRun() override {
157*61c4878aSAndroid Build Coastguard Worker return (GetTimeSinceBootMillis() - last_run_time_ > kRunInterval);
158*61c4878aSAndroid Build Coastguard Worker }
Run()159*61c4878aSAndroid Build Coastguard Worker void Run() override {
160*61c4878aSAndroid Build Coastguard Worker last_run_time_ = GetTimeSinceBootMillis();
161*61c4878aSAndroid Build Coastguard Worker PW_TRACE_FUNCTION("Input");
162*61c4878aSAndroid Build Coastguard Worker SAMPLE_APP_SLEEP_MILLIS(50);
163*61c4878aSAndroid Build Coastguard Worker uint8_t value = GetValue();
164*61c4878aSAndroid Build Coastguard Worker PW_TRACE_INSTANT_DATA("value", "@pw_arg_counter", &value, sizeof(value));
165*61c4878aSAndroid Build Coastguard Worker processing_task.AddJob(sample_count_, value);
166*61c4878aSAndroid Build Coastguard Worker sample_count_++;
167*61c4878aSAndroid Build Coastguard Worker }
168*61c4878aSAndroid Build Coastguard Worker
169*61c4878aSAndroid Build Coastguard Worker private:
GetValue()170*61c4878aSAndroid Build Coastguard Worker uint8_t GetValue() {
171*61c4878aSAndroid Build Coastguard Worker PW_TRACE_FUNCTION("Input");
172*61c4878aSAndroid Build Coastguard Worker SAMPLE_APP_SLEEP_MILLIS(100); // Fake processing time
173*61c4878aSAndroid Build Coastguard Worker return sample_count_ % 4 + 1;
174*61c4878aSAndroid Build Coastguard Worker }
175*61c4878aSAndroid Build Coastguard Worker size_t sample_count_ = 0;
176*61c4878aSAndroid Build Coastguard Worker uint32_t last_run_time_ = 0;
177*61c4878aSAndroid Build Coastguard Worker static constexpr uint32_t kRunInterval = 1000;
178*61c4878aSAndroid Build Coastguard Worker } input_task;
179*61c4878aSAndroid Build Coastguard Worker
180*61c4878aSAndroid Build Coastguard Worker // Simple main loop acting as the "Kernel"
181*61c4878aSAndroid Build Coastguard Worker // Uses simple named trace durations to indicate which task/job is running
182*61c4878aSAndroid Build Coastguard Worker #undef PW_TRACE_MODULE_NAME
183*61c4878aSAndroid Build Coastguard Worker #define PW_TRACE_MODULE_NAME "Kernel"
StartFakeKernel()184*61c4878aSAndroid Build Coastguard Worker void StartFakeKernel() {
185*61c4878aSAndroid Build Coastguard Worker std::array<SimpleRunnable*, 2> tasks = {&input_task, &processing_task};
186*61c4878aSAndroid Build Coastguard Worker
187*61c4878aSAndroid Build Coastguard Worker bool idle = false;
188*61c4878aSAndroid Build Coastguard Worker while (true) {
189*61c4878aSAndroid Build Coastguard Worker bool have_any_run = false;
190*61c4878aSAndroid Build Coastguard Worker for (auto& task : tasks) {
191*61c4878aSAndroid Build Coastguard Worker if (task->ShouldRun()) {
192*61c4878aSAndroid Build Coastguard Worker if (idle) {
193*61c4878aSAndroid Build Coastguard Worker PW_TRACE_END("Idle", "Idle");
194*61c4878aSAndroid Build Coastguard Worker idle = false;
195*61c4878aSAndroid Build Coastguard Worker }
196*61c4878aSAndroid Build Coastguard Worker have_any_run = true;
197*61c4878aSAndroid Build Coastguard Worker // The task name is not a string literal and is therefore put in the
198*61c4878aSAndroid Build Coastguard Worker // data section, so it can also work with tokenized trace.
199*61c4878aSAndroid Build Coastguard Worker PW_TRACE_START_DATA(
200*61c4878aSAndroid Build Coastguard Worker "Running", "@pw_arg_group", task->Name(), strlen(task->Name()));
201*61c4878aSAndroid Build Coastguard Worker task->Run();
202*61c4878aSAndroid Build Coastguard Worker PW_TRACE_END_DATA(
203*61c4878aSAndroid Build Coastguard Worker "Running", "@pw_arg_group", task->Name(), strlen(task->Name()));
204*61c4878aSAndroid Build Coastguard Worker }
205*61c4878aSAndroid Build Coastguard Worker }
206*61c4878aSAndroid Build Coastguard Worker if (!idle && !have_any_run) {
207*61c4878aSAndroid Build Coastguard Worker PW_TRACE_START("Idle", "Idle");
208*61c4878aSAndroid Build Coastguard Worker idle = true;
209*61c4878aSAndroid Build Coastguard Worker }
210*61c4878aSAndroid Build Coastguard Worker }
211*61c4878aSAndroid Build Coastguard Worker }
212*61c4878aSAndroid Build Coastguard Worker
213*61c4878aSAndroid Build Coastguard Worker } // namespace
214*61c4878aSAndroid Build Coastguard Worker
RunTraceSampleApp()215*61c4878aSAndroid Build Coastguard Worker void RunTraceSampleApp() { StartFakeKernel(); }
216