diff options
Diffstat (limited to 'runtime/libs/benchmark')
-rw-r--r-- | runtime/libs/benchmark/include/benchmark/MemoryInfo.h | 40 | ||||
-rw-r--r-- | runtime/libs/benchmark/include/benchmark/MemoryPoller.h | 4 | ||||
-rw-r--r-- | runtime/libs/benchmark/include/benchmark/Phases.h | 5 | ||||
-rw-r--r-- | runtime/libs/benchmark/include/benchmark/Result.h | 2 | ||||
-rw-r--r-- | runtime/libs/benchmark/src/MemoryInfo.cpp | 169 | ||||
-rw-r--r-- | runtime/libs/benchmark/src/MemoryPoller.cpp | 163 | ||||
-rw-r--r-- | runtime/libs/benchmark/src/Phases.cpp | 8 | ||||
-rw-r--r-- | runtime/libs/benchmark/src/Result.cpp | 12 |
8 files changed, 248 insertions, 155 deletions
diff --git a/runtime/libs/benchmark/include/benchmark/MemoryInfo.h b/runtime/libs/benchmark/include/benchmark/MemoryInfo.h new file mode 100644 index 000000000..6e8e12ba4 --- /dev/null +++ b/runtime/libs/benchmark/include/benchmark/MemoryInfo.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. 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. + */ + +#ifndef __NNFW_BENCHMARK_MEMORY_INFO_H__ +#define __NNFW_BENCHMARK_MEMORY_INFO_H__ + +#include <cstdint> +#include <string> + +namespace benchmark +{ + +bool prepareVmRSS(); +bool prepareVmHWM(); +bool prepareGpuMemory(); +bool preparePssSum(); + +uint32_t getVmRSS(); +uint32_t getVmHWM(); +uint32_t getGpuMemory(const std::string &process_name); +uint32_t getPssSum(); + +std::string getProcessName(); + +} // namespace benchmark + +#endif // __NNFW_BENCHMARK_MEMORY_INFO_H__ diff --git a/runtime/libs/benchmark/include/benchmark/MemoryPoller.h b/runtime/libs/benchmark/include/benchmark/MemoryPoller.h index 48caa3b3a..47db3fd77 100644 --- a/runtime/libs/benchmark/include/benchmark/MemoryPoller.h +++ b/runtime/libs/benchmark/include/benchmark/MemoryPoller.h @@ -57,10 +57,6 @@ public: private: void process(); bool prepareMemoryPolling(); - uint32_t getVmRSS(); - uint32_t getVmHWM(); - uint32_t getGpuMemory(); - uint32_t getPssSum(); private: std::chrono::milliseconds _duration; diff --git a/runtime/libs/benchmark/include/benchmark/Phases.h b/runtime/libs/benchmark/include/benchmark/Phases.h index 936a89742..7d642782a 100644 --- a/runtime/libs/benchmark/include/benchmark/Phases.h +++ b/runtime/libs/benchmark/include/benchmark/Phases.h @@ -50,6 +50,9 @@ public: const MemoryPoller &mem_poll() const { return *_mem_poll; } const Phase &at(const std::string &tag) const { return _phases.at(tag); } + uint32_t mem_before_init() const { return _mem_before_init; } + uint32_t mem_after_run() const { return _mem_after_run; } + private: void run(const std::string &tag, const PhaseFunc &exec, const PhaseFunc *post, uint32_t loop_num, bool option_disable); @@ -58,6 +61,8 @@ private: const PhaseOption _option; std::unordered_map<std::string, Phase> _phases; std::unique_ptr<MemoryPoller> _mem_poll; + uint32_t _mem_before_init; + uint32_t _mem_after_run; }; } // namespace benchmark diff --git a/runtime/libs/benchmark/include/benchmark/Result.h b/runtime/libs/benchmark/include/benchmark/Result.h index 69084b300..7604aa904 100644 --- a/runtime/libs/benchmark/include/benchmark/Result.h +++ b/runtime/libs/benchmark/include/benchmark/Result.h @@ -34,6 +34,8 @@ public: double time[PhaseEnum::END_OF_PHASE][FigureType::END_OF_FIG_TYPE]; uint32_t memory[PhaseEnum::END_OF_PHASE][MemoryType::END_OF_MEM_TYPE]; bool print_memory = false; + uint32_t init_memory = 0; + uint32_t peak_memory = 0; }; // TODO Support not only stdout but also ostream diff --git a/runtime/libs/benchmark/src/MemoryInfo.cpp b/runtime/libs/benchmark/src/MemoryInfo.cpp new file mode 100644 index 000000000..20d262961 --- /dev/null +++ b/runtime/libs/benchmark/src/MemoryInfo.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. 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 "benchmark/MemoryInfo.h" + +#include <vector> +#include <algorithm> +#include <fstream> +#include <sstream> +#include <cassert> +#include <sys/time.h> +#include <sys/resource.h> + +namespace +{ + +const std::string proc_status_path("/proc/self/status"); +const std::string gpu_memory_path("/sys/kernel/debug/mali0/gpu_memory"); +const std::string proc_smaps_path("/proc/self/smaps"); + +bool isStrNumber(const std::string &s) +{ + return !s.empty() && + std::find_if(s.begin(), s.end(), [](char c) { return !std::isdigit(c); }) == s.end(); +} + +std::vector<std::string> splitLine(std::string line, std::string delimiters = " \n\t") +{ + std::vector<std::string> words; + size_t prev = 0, pos; + + while ((pos = line.find_first_of(delimiters, prev)) != std::string::npos) + { + if (pos > prev) + words.emplace_back(line.substr(prev, pos - prev)); + prev = pos + 1; + } + + if (prev < line.length()) + words.emplace_back(line.substr(prev, std::string::npos)); + + return words; +} + +std::vector<std::string> getValueFromFileStatus(const std::string &file, const std::string &key) +{ + std::ifstream ifs(file); + assert(ifs.is_open()); + + std::string line; + std::vector<std::string> val; + + bool found = false; + while (std::getline(ifs, line)) + { + if (line.find(key) != std::string::npos) + { + found = true; + break; + } + } + ifs.close(); + + if (!found) + { + // NOTE. the process which uses gpu resources cannot be there yet at the model-load phase. + // At that time, just return empty. + return val; + } + + val = splitLine(line); + return val; +} + +// Because of smaps' structure, returns sum value as uint32_t +uint32_t getSumValueFromFileSmaps(const std::string &file, const std::string &key) +{ + std::ifstream ifs(file); + assert(ifs.is_open()); + + std::string line; + uint32_t sum = 0; + while (std::getline(ifs, line)) + { + if (line.find(key) != std::string::npos) + { + // an example by splitLine() + // `Pss: 0 kB` + // val[0]: "Pss:", val[1]: "0" val[2]: "kB" + auto val = splitLine(line); + assert(val.size() != 0); + // SwapPss could show so that check where Pss is at the beginning + if (val[0].find("Pss") != 0) + { + continue; + } + sum += std::stoul(val[1]); + } + } + + return sum; +} + +} // namespace + +namespace benchmark +{ + +bool prepareVmRSS() { return std::ifstream(proc_status_path).is_open(); } + +bool prepareVmHWM() { return std::ifstream(proc_status_path).is_open(); } + +bool prepareGpuMemory() { return std::ifstream(gpu_memory_path).is_open(); } + +bool preparePssSum() { return std::ifstream(proc_smaps_path).is_open(); } + +uint32_t getVmRSS() +{ + auto val = getValueFromFileStatus(proc_status_path, "VmRSS"); + if (val.size() == 0) + return 0; + assert(isStrNumber(val[1])); + return std::stoul(val[1]); +} + +uint32_t getVmHWM() +{ + auto val = getValueFromFileStatus(proc_status_path, "VmHWM"); + if (val.size() == 0) + return 0; + // key: value + assert(isStrNumber(val[1])); + return std::stoul(val[1]); +} + +uint32_t getGpuMemory(const std::string &process_name) +{ + assert(!process_name.empty()); + auto val = getValueFromFileStatus(gpu_memory_path, process_name); + if (val.size() == 0) + return 0; + // process_name -> pid -> gpu_mem -> max_gpu_mem + assert(isStrNumber(val[2])); + return std::stoul(val[2]); +} + +uint32_t getPssSum() { return getSumValueFromFileSmaps(proc_smaps_path, "Pss"); } + +std::string getProcessName() +{ + auto val = getValueFromFileStatus(proc_status_path, "Name"); + assert(val.size() >= 2); + return val[1]; +} + +} // namespace benchmark diff --git a/runtime/libs/benchmark/src/MemoryPoller.cpp b/runtime/libs/benchmark/src/MemoryPoller.cpp index 61fdecd46..050b5b163 100644 --- a/runtime/libs/benchmark/src/MemoryPoller.cpp +++ b/runtime/libs/benchmark/src/MemoryPoller.cpp @@ -16,106 +16,13 @@ #include "benchmark/MemoryPoller.h" #include "benchmark/Types.h" +#include "benchmark/MemoryInfo.h" #include <vector> -#include <fstream> -#include <sstream> #include <stdexcept> #include <cassert> #include <iostream> -namespace -{ - -const std::string proc_status_path("/proc/self/status"); -const std::string gpu_memory_path("/sys/kernel/debug/mali0/gpu_memory"); -const std::string proc_smaps_path("/proc/self/smaps"); - -bool isStrNumber(const std::string &s) -{ - return !s.empty() && - std::find_if(s.begin(), s.end(), [](char c) { return !std::isdigit(c); }) == s.end(); -} - -std::vector<std::string> splitLine(std::string line, std::string delimiters = " \n\t") -{ - std::vector<std::string> words; - size_t prev = 0, pos; - - while ((pos = line.find_first_of(delimiters, prev)) != std::string::npos) - { - if (pos > prev) - words.emplace_back(line.substr(prev, pos - prev)); - prev = pos + 1; - } - - if (prev < line.length()) - words.emplace_back(line.substr(prev, std::string::npos)); - - return words; -} - -std::vector<std::string> getValueFromFileStatus(const std::string &file, const std::string &key) -{ - std::ifstream ifs(file); - assert(ifs.is_open()); - - std::string line; - std::vector<std::string> val; - - bool found = false; - while (std::getline(ifs, line)) - { - if (line.find(key) != std::string::npos) - { - found = true; - break; - } - } - ifs.close(); - - if (!found) - { - // NOTE. the process which uses gpu resources cannot be there yet at the model-load phase. - // At that time, just return empty. - return val; - } - - val = splitLine(line); - return val; -} - -// Because of smaps' structure, returns sum value as uint32_t -uint32_t getSumValueFromFileSmaps(const std::string &file, const std::string &key) -{ - std::ifstream ifs(file); - assert(ifs.is_open()); - - std::string line; - uint32_t sum = 0; - while (std::getline(ifs, line)) - { - if (line.find(key) != std::string::npos) - { - // an example by splitLine() - // `Pss: 0 kB` - // val[0]: "Pss:", val[1]: "0" val[2]: "kB" - auto val = splitLine(line); - assert(val.size() != 0); - // SwapPss could show so that check where Pss is at the beginning - if (val[0].find("Pss") != 0) - { - continue; - } - sum += std::stoul(val[1]); - } - } - - return sum; -} - -} // namespace - namespace benchmark { @@ -168,7 +75,7 @@ bool MemoryPoller::end(PhaseEnum phase) mem = getVmRSS(); if (_gpu_poll) { - mem += getGpuMemory(); + mem += getGpuMemory(_process_name); } if (mem > _rss_map[phase]) _rss_map[phase] = mem; @@ -176,7 +83,7 @@ bool MemoryPoller::end(PhaseEnum phase) mem = getVmHWM(); if (_gpu_poll) { - mem += getGpuMemory(); + mem += getGpuMemory(_process_name); } _hwm_map[phase] = mem; @@ -208,7 +115,7 @@ void MemoryPoller::process() uint32_t cur_hwm = getVmHWM(); if (_gpu_poll) { - auto gpu_mem = getGpuMemory(); + auto gpu_mem = getGpuMemory(_process_name); cur_rss += gpu_mem; cur_hwm += gpu_mem; } @@ -236,77 +143,33 @@ void MemoryPoller::process() bool MemoryPoller::prepareMemoryPolling() { // VmRSS + if (!prepareVmRSS()) { - std::ifstream ifs(proc_status_path); - if (!ifs.is_open()) - { - std::cerr << "failed to open " << proc_status_path << std::endl; - return false; - } - ifs.close(); + std::cerr << "failed to prepare parsing vmrss" << std::endl; + return false; } // (Additionally) GpuMemory if (_gpu_poll) { - std::ifstream ifs(gpu_memory_path); - if (!ifs.is_open()) + if (!prepareGpuMemory()) { - std::cerr << "failed to open " << gpu_memory_path << std::endl; + std::cerr << "failed to prepare parsing gpu memory" << std::endl; return false; } - ifs.close(); // Needs process name - auto val = getValueFromFileStatus(proc_status_path, "Name"); - assert(val.size() != 0); - _process_name = val[1]; + _process_name = getProcessName(); } // PSS + if (!preparePssSum()) { - std::ifstream ifs(proc_smaps_path); - if (!ifs.is_open()) - { - std::cerr << "failed to open " << proc_smaps_path << std::endl; - return false; - } - ifs.close(); + std::cerr << "failed to prepare parsing pss sum" << std::endl; + return false; } return true; } -uint32_t MemoryPoller::getVmRSS() -{ - auto val = getValueFromFileStatus(proc_status_path, "VmRSS"); - if (val.size() == 0) - return 0; - assert(isStrNumber(val[1])); - return std::stoul(val[1]); -} - -uint32_t MemoryPoller::getVmHWM() -{ - auto val = getValueFromFileStatus(proc_status_path, "VmHWM"); - if (val.size() == 0) - return 0; - // key: value - assert(isStrNumber(val[1])); - return std::stoul(val[1]); -} - -uint32_t MemoryPoller::getGpuMemory() -{ - assert(!_process_name.empty()); - auto val = getValueFromFileStatus(gpu_memory_path, _process_name); - if (val.size() == 0) - return 0; - // process_name -> pid -> gpu_mem -> max_gpu_mem - assert(isStrNumber(val[2])); - return std::stoul(val[2]); -} - -uint32_t MemoryPoller::getPssSum() { return getSumValueFromFileSmaps(proc_smaps_path, "Pss"); } - } // namespace benchmark diff --git a/runtime/libs/benchmark/src/Phases.cpp b/runtime/libs/benchmark/src/Phases.cpp index 9ab67cfd9..897b943d3 100644 --- a/runtime/libs/benchmark/src/Phases.cpp +++ b/runtime/libs/benchmark/src/Phases.cpp @@ -17,6 +17,7 @@ #include "benchmark/Phases.h" #include "benchmark/Types.h" +#include "benchmark/MemoryInfo.h" #include <cassert> #include <chrono> @@ -46,8 +47,11 @@ void SleepForMicros(uint64_t micros) namespace benchmark { -Phases::Phases(const PhaseOption &option) : _option(option) +Phases::Phases(const PhaseOption &option) : _option(option), _mem_before_init(0), _mem_after_run(0) { + assert(prepareVmRSS()); + _mem_before_init = getVmHWM(); + if (_option.memory) { _mem_poll = std::make_unique<MemoryPoller>(std::chrono::milliseconds(option.memory_interval), @@ -93,6 +97,8 @@ void Phases::run(const std::string &tag, const PhaseFunc &exec, const PhaseFunc } } + _mem_after_run = getVmHWM(); + if (p == PhaseEnum::END_OF_PHASE) { return; diff --git a/runtime/libs/benchmark/src/Result.cpp b/runtime/libs/benchmark/src/Result.cpp index df573da92..e6cafb91c 100644 --- a/runtime/libs/benchmark/src/Result.cpp +++ b/runtime/libs/benchmark/src/Result.cpp @@ -141,6 +141,15 @@ void printResultMemory(const uint32_t memory[benchmark::PhaseEnum::END_OF_PHASE] } } +void printUsedPeakMemory(uint32_t init_memory, uint32_t peak_memory) +{ + uint32_t used_peak_memory = peak_memory - init_memory; + std::cout << "Used Peak Memory : " << used_peak_memory << " kb" << std::endl; + std::cout << "- HWM after run : " << peak_memory << " kb" << std::endl; + std::cout << "- HWM before init: " << init_memory << " kb" << std::endl; + std::cout << "===================================" << std::endl; +} + } // namespace namespace benchmark @@ -175,6 +184,8 @@ Result::Result(const Phases &phases) } } } + init_memory = phases.mem_before_init(); + peak_memory = phases.mem_after_run(); } void printResult(const Result &result) @@ -185,6 +196,7 @@ void printResult(const Result &result) return; printResultMemory(result.memory); + printUsedPeakMemory(result.init_memory, result.peak_memory); } // TODO There are necessary for a kind of output data file so that it doesn't have to be csv file |