| // Copyright 2015 Google Inc. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "base/threading/thread.h" |
| #include "build/build_config.h" |
| #include "cobalt/trace_event/benchmark.h" |
| |
| #if defined(OS_STARBOARD) |
| #include "starboard/thread.h" |
| #define usleep(usec) SbThreadSleep(usec) |
| #endif |
| |
| // A sample simple benchmark that tracks only a single event, in this case, |
| // "LoopIteration". |
| TRACE_EVENT_BENCHMARK1( |
| SampleTestBenchmarkWithOneTrackedEvent, |
| "LoopIteration", cobalt::trace_event::IN_SCOPE_DURATION) { |
| const int kRenderIterationCount = 40; |
| for (int i = 0; i < kRenderIterationCount; ++i) { |
| TRACE_EVENT0("SampleBenchmark", "LoopIteration"); |
| { |
| TRACE_EVENT0("SampleBenchmark", "SubEventA"); |
| usleep(10000); |
| } |
| { |
| TRACE_EVENT0("SampleBenchmark", "SubEventB"); |
| usleep(20000); |
| } |
| } |
| } |
| |
| // This sample benchmark is very similar to the single event tracking benchmark |
| // above, however it tracks 3 events instead of 1. For one of those 3 events, |
| // "SubEventA", we track both its in-scope duration as well as the time between |
| // subsequent event instance start times. |
| TRACE_EVENT_BENCHMARK4( |
| SampleTestBenchmarkWithThreeTrackedEvents, |
| "LoopIteration", cobalt::trace_event::IN_SCOPE_DURATION, |
| "SubEventA", cobalt::trace_event::IN_SCOPE_DURATION, |
| "SubEventA", cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS, |
| "SubEventB", cobalt::trace_event::IN_SCOPE_DURATION) { |
| const int kRenderIterationCount = 40; |
| for (int i = 0; i < kRenderIterationCount; ++i) { |
| TRACE_EVENT0("SampleBenchmark", "LoopIteration"); |
| { |
| TRACE_EVENT0("SampleBenchmark", "SubEventA"); |
| usleep(10000); |
| } |
| { |
| TRACE_EVENT0("SampleBenchmark", "SubEventB"); |
| usleep(20000); |
| } |
| } |
| } |
| |
| // The following example demonstrates that the benchmarking system will track |
| // over flow/thread boundaries. Since "FlowInitiator"'s duration will always |
| // include the "HandleTask()" event as a child, "FlowInitiator"'s duration will |
| // always be greater than "HandleTask()"'s. In fact, as the worker thread |
| // gets more and more backed up dealing with HandleTask() tasks (which are |
| // being produced faster than they can be consumed), the time between when |
| // "FlowInitiator" starts and "HandleTask()" ends will increase as the |
| // test continues. |
| void HandleTask() { |
| TRACE_EVENT0("SampleBenchmark", "HandleTask()"); |
| usleep(10000); |
| } |
| |
| TRACE_EVENT_BENCHMARK4( |
| FlowExample, |
| "FlowInitiator", cobalt::trace_event::IN_SCOPE_DURATION, |
| "FlowInitiator", cobalt::trace_event::FLOW_DURATION, |
| "FlowInitiator", cobalt::trace_event::TIME_BETWEEN_EVENT_STARTS, |
| "HandleTask()", cobalt::trace_event::FLOW_DURATION) { |
| base::Thread thread("Worker"); |
| thread.Start(); |
| |
| const int kRenderIterationCount = 40; |
| for (int i = 0; i < kRenderIterationCount; ++i) { |
| usleep(2000); |
| TRACE_EVENT0("SampleBenchmark", "FlowInitiator"); |
| thread.message_loop()->PostTask(FROM_HERE, base::Bind(&HandleTask)); |
| usleep(5000); |
| } |
| } |
| |
| // A sample full benchmark where we have the ability to specify the analysis |
| // method (allowing for sophisticated metrics to be extracted) as well as |
| // the results compilation method which decides how to present the data |
| // to subsequent stages of the pipeline. |
| class SampleTestAdvancedBenchmark : public cobalt::trace_event::Benchmark { |
| public: |
| // This method will be executed in order to generate the trace results |
| // that will subsequently be analyzed. |
| void Experiment() OVERRIDE { |
| const int kRenderIterationCount = 100; |
| for (int i = 0; i < kRenderIterationCount; ++i) { |
| TRACE_EVENT0("SampleBenchmark", "LoopIteration"); |
| { |
| TRACE_EVENT0("SampleBenchmark", "SubEventA"); |
| usleep(10000); |
| } |
| { |
| TRACE_EVENT0("SampleBenchmark", "SubEventB"); |
| usleep(20000); |
| } |
| } |
| } |
| |
| // This method is called to allow the benchmark to handle a trace event |
| // occurring. This occurs when a TRACE_EVENT or TRACE_EVENT_FLOW |
| // call from above completes and all its child events and flows have also |
| // completed. |
| void AnalyzeTraceEvent(const scoped_refptr< |
| cobalt::trace_event::EventParser::ScopedEvent>& event) OVERRIDE { |
| if (event->name() == "LoopIteration") { |
| if (event->flow_duration()) { |
| loop_iteration_times_in_seconds_.push_back( |
| event->flow_duration()->InSecondsF()); |
| } |
| } else if (event->name() == "SubEventA") { |
| if (event->flow_duration()) { |
| sub_event_a_times_in_seconds_.push_back( |
| event->flow_duration()->InSecondsF()); |
| } |
| } else if (event->name() == "SubEventB") { |
| if (event->flow_duration()) { |
| sub_event_b_times_in_seconds_.push_back( |
| event->flow_duration()->InSecondsF()); |
| } |
| } |
| } |
| |
| // This is called after all events have been analyzed and it is time to |
| // produce results. All Result objects returned will be output as separate |
| // variables. |
| std::vector<Result> CompileResults() OVERRIDE { |
| std::vector<Result> results; |
| |
| results.push_back(Result("LoopIteration time in seconds", |
| loop_iteration_times_in_seconds_)); |
| results.push_back( |
| Result("SubEventA time in seconds", sub_event_a_times_in_seconds_)); |
| results.push_back( |
| Result("SubEventB time in seconds", sub_event_b_times_in_seconds_)); |
| |
| return results; |
| } |
| |
| private: |
| std::vector<double> loop_iteration_times_in_seconds_; |
| std::vector<double> sub_event_a_times_in_seconds_; |
| std::vector<double> sub_event_b_times_in_seconds_; |
| }; |
| TRACE_EVENT_REGISTER_BENCHMARK(SampleTestAdvancedBenchmark); |