050b5b16356ded0a234adcab56165a1286749bfe
[platform/core/ml/nnfw.git] / runtime / libs / benchmark / src / MemoryPoller.cpp
1 /*
2  * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "benchmark/MemoryPoller.h"
18 #include "benchmark/Types.h"
19 #include "benchmark/MemoryInfo.h"
20
21 #include <vector>
22 #include <stdexcept>
23 #include <cassert>
24 #include <iostream>
25
26 namespace benchmark
27 {
28
29 MemoryPoller::MemoryPoller(std::chrono::milliseconds duration, bool gpu_poll)
30     : _duration(duration), _run(false), _term(false), _gpu_poll(gpu_poll)
31 {
32   if (prepareMemoryPolling() == false)
33     throw std::runtime_error("failed to prepare memory pooling");
34
35   _thread = std::thread{&MemoryPoller::process, this};
36 }
37
38 bool MemoryPoller::start(PhaseEnum phase)
39 {
40   if (std::find(_phases.begin(), _phases.end(), phase) != _phases.end())
41   {
42     std::cerr << getPhaseString(phase) << " is already processing/processed..." << std::endl;
43     return false;
44   }
45
46   {
47     std::lock_guard<std::mutex> lock(_mutex);
48     _phases.emplace_back(phase);
49     _rss_map[phase] = 0;
50     _hwm_map[phase] = 0;
51     _pss_map[phase] = 0;
52   }
53
54   _run = true;
55   _cond_var_started.notify_all();
56   return true;
57 }
58
59 bool MemoryPoller::end(PhaseEnum phase)
60 {
61   if (std::find(_phases.begin(), _phases.end(), phase) == _phases.end())
62   {
63     std::cerr << getPhaseString(phase) << " is not started..." << std::endl;
64     return false;
65   }
66
67   uint32_t mem = 0;
68   bool stop = false;
69   {
70     std::lock_guard<std::mutex> lock(_mutex);
71     _phases.remove(phase);
72     stop = (_phases.size() == 0);
73   }
74
75   mem = getVmRSS();
76   if (_gpu_poll)
77   {
78     mem += getGpuMemory(_process_name);
79   }
80   if (mem > _rss_map[phase])
81     _rss_map[phase] = mem;
82
83   mem = getVmHWM();
84   if (_gpu_poll)
85   {
86     mem += getGpuMemory(_process_name);
87   }
88   _hwm_map[phase] = mem;
89
90   mem = getPssSum();
91   if (mem > _pss_map[phase])
92     _pss_map[phase] = mem;
93
94   if (stop)
95   {
96     _run = false;
97     _cond_var_started.notify_all();
98   }
99
100   return true;
101 }
102
103 void MemoryPoller::process()
104 {
105   std::unique_lock<std::mutex> lock_started(_mutex_started);
106   while (true)
107   {
108     _cond_var_started.wait(lock_started, [&]() { return _run || _term; });
109     if (_term)
110       break;
111
112     std::unique_lock<std::mutex> lock(_mutex);
113
114     uint32_t cur_rss = getVmRSS();
115     uint32_t cur_hwm = getVmHWM();
116     if (_gpu_poll)
117     {
118       auto gpu_mem = getGpuMemory(_process_name);
119       cur_rss += gpu_mem;
120       cur_hwm += gpu_mem;
121     }
122     uint32_t cur_pss = getPssSum();
123
124     for (auto &phase : _phases)
125     {
126       auto &rss = _rss_map.at(phase);
127       if (rss < cur_rss)
128         rss = cur_rss;
129       // hwm is gradually increasing
130       auto &hwm = _hwm_map.at(phase);
131       hwm = cur_hwm;
132       auto &pss = _pss_map.at(phase);
133       if (pss < cur_pss)
134         pss = cur_pss;
135     }
136
137     lock.unlock();
138
139     std::this_thread::sleep_for(std::chrono::milliseconds(_duration));
140   }
141 }
142
143 bool MemoryPoller::prepareMemoryPolling()
144 {
145   // VmRSS
146   if (!prepareVmRSS())
147   {
148     std::cerr << "failed to prepare parsing vmrss" << std::endl;
149     return false;
150   }
151
152   // (Additionally) GpuMemory
153   if (_gpu_poll)
154   {
155     if (!prepareGpuMemory())
156     {
157       std::cerr << "failed to prepare parsing gpu memory" << std::endl;
158       return false;
159     }
160
161     // Needs process name
162     _process_name = getProcessName();
163   }
164
165   // PSS
166   if (!preparePssSum())
167   {
168     std::cerr << "failed to prepare parsing pss sum" << std::endl;
169     return false;
170   }
171
172   return true;
173 }
174
175 } // namespace benchmark