xref: /aosp_15_r20/external/ruy/ruy/profiler/profiler.cc (revision bb86c7ed5fb1b98a7eac808e443a46cc8b90dfc0)
1 /* Copyright 2020 Google LLC. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7     http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 
16 #include "ruy/profiler/profiler.h"
17 
18 #ifdef RUY_PROFILER
19 #include <atomic>
20 #include <chrono>  // NOLINT
21 #include <cstdio>
22 #include <cstdlib>
23 #include <thread>  // NOLINT
24 #include <vector>
25 #endif
26 
27 #include "ruy/profiler/instrumentation.h"
28 #include "ruy/profiler/treeview.h"
29 
30 namespace ruy {
31 namespace profiler {
32 
33 #ifdef RUY_PROFILER
34 
ScopeProfile()35 ScopeProfile::ScopeProfile() { Start(); }
ScopeProfile(bool enable)36 ScopeProfile::ScopeProfile(bool enable) {
37   if (enable) {
38     Start();
39   }
40 }
~ScopeProfile()41 ScopeProfile::~ScopeProfile() {
42   if (!thread_) {
43     return;
44   }
45   finishing_.store(true);
46   thread_->join();
47   Finish();
48 }
49 
Start()50 void ScopeProfile::Start() {
51   {
52     std::lock_guard<std::mutex> lock(*detail::GlobalsMutex());
53     if (detail::GlobalIsProfilerRunning()) {
54       fprintf(stderr, "FATAL: profiler already running!\n");
55       abort();
56     }
57     detail::GlobalIsProfilerRunning() = true;
58   }
59   finishing_ = false;
60   thread_.reset(new std::thread(&ScopeProfile::ThreadFunc, this));
61 }
62 
ThreadFunc()63 void ScopeProfile::ThreadFunc() {
64   while (!finishing_.load()) {
65     std::this_thread::sleep_for(std::chrono::milliseconds(1));
66     std::lock_guard<std::mutex> lock(*detail::GlobalsMutex());
67     auto* thread_stacks = detail::GlobalAllThreadStacks();
68     for (detail::ThreadStack* thread_stack : *thread_stacks) {
69       Sample(*thread_stack);
70     }
71   }
72 }
73 
Sample(const detail::ThreadStack & thread_stack)74 void ScopeProfile::Sample(const detail::ThreadStack& thread_stack) {
75   std::lock_guard<std::mutex> lock(thread_stack.Mutex());
76   // Drop empty stacks.
77   // This ensures that profiles aren't polluted by uninteresting threads.
78   if (thread_stack.stack().size == 0) {
79     return;
80   }
81   int sample_size = detail::GetBufferSize(thread_stack.stack());
82   int old_buf_size = samples_buf_.size();
83   samples_buf_.resize(old_buf_size + sample_size);
84   detail::CopyToBuffer(thread_stack.stack(),
85                        samples_buf_.data() + old_buf_size);
86 }
87 
Finish()88 void ScopeProfile::Finish() {
89   {
90     std::lock_guard<std::mutex> lock(*detail::GlobalsMutex());
91     if (!detail::GlobalIsProfilerRunning()) {
92       fprintf(stderr, "FATAL: profiler is not running!\n");
93       abort();
94     }
95     detail::GlobalIsProfilerRunning() = false;
96   }
97   if (user_treeview_) {
98     user_treeview_->Populate(samples_buf_);
99   } else {
100     TreeView treeview;
101     treeview.Populate(samples_buf_);
102     Print(treeview);
103   }
104 }
105 
106 #endif  // RUY_PROFILER
107 
108 }  // namespace profiler
109 }  // namespace ruy
110