• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 Huawei Device Co., Ltd.
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 "cpu_info.h"
17 
18 #include <string>
19 #include <regex>
20 #include <string_view>
21 #include <iomanip>
22 #include <unistd.h>
23 #include "sp_log.h"
24 namespace OHOS {
25 namespace SmartPerf {
ItemData()26 std::map<std::string, std::string> CPUInfo::ItemData()
27 {
28     Stop();
29     std::map<std::string, std::string> result;
30     std::istringstream stream(buffer_);
31     std::string line;
32     uint64_t cpu_cycles_total = 0;
33     uint64_t instructions_total = 0;
34     double cpi_total = 0.0;
35     size_t cpu_cycles_count = 0;
36     size_t instructions_count = 0;
37     size_t cpi_count = 0;
38     auto findData = [](const std::string& targetStr, auto& total, auto& count) {
39         size_t count_start = targetStr.find_first_not_of(" \t");
40         size_t count_end = targetStr.find(" ", count_start);
41         std::string number_str = targetStr.substr(count_start, count_end - count_start);
42         number_str.erase(std::remove(number_str.begin(), number_str.end(), ','), number_str.end());
43         total += SPUtilesTye::StringToSometype<uint64_t>(number_str);
44         ++count;
45     };
46     while (std::getline(stream, line)) {
47         if (line.find(SPUtils::GetProductName() + "-cpu-cycles") != std::string::npos) {
48             findData(line, cpu_cycles_total, cpu_cycles_count);
49         }
50         if (line.find(SPUtils::GetProductName() + "-instructions") != std::string::npos) {
51             findData(line, instructions_total, instructions_count);
52             CalculateCPIInfo(line, cpi_total, cpi_count);
53         }
54     }
55     cpu_cycles_count == 0 ? "" :
56         result[SPUtils::GetProductName() + "-cpu-cycles"] =
57             std::to_string(static_cast<double>(cpu_cycles_total) / cpu_cycles_count);
58     instructions_count == 0 ? "" :
59         result[SPUtils::GetProductName() + "-instructions"] =
60             std::to_string(static_cast<double>(instructions_total) / instructions_count);
61     cpi_count == 0 ? "" : result["cycles per instruction"] = std::to_string(cpi_total / cpi_count);
62     Start();
63     LOGI("CPUInfo:ItemData map size(%u)", result.size());
64     return result;
65 }
66 
CalculateCPIInfo(const std::string line,double & cpiTotal,size_t & cpiCount)67 void CPUInfo::CalculateCPIInfo(const std::string line, double &cpiTotal, size_t &cpiCount)
68 {
69     auto trim = [](std::string& s) {
70         s.erase(0, s.find_first_not_of(" \t"));
71         s.erase(s.find_last_not_of(" \t") + 1);
72     };
73     size_t comment_pos = line.find("|");
74     if (comment_pos != std::string::npos) {
75         std::string comment = line.substr(comment_pos + 1);
76         trim(comment);
77         size_t cpi_pos = comment.find("cycles per instruction");
78         if (cpi_pos != std::string::npos) {
79             size_t number_end = comment.find(" ", 0);
80             std::string cpi_str = comment.substr(0, number_end);
81             cpiTotal += SPUtilesTye::StringToSometype<double>(cpi_str);
82             ++cpiCount;
83         }
84     }
85 }
86 
StartExecutionOnce(bool isPause)87 void CPUInfo::StartExecutionOnce(bool isPause)
88 {
89     (void)isPause;
90     Stop();
91     if (pids_.empty()) {
92         hiperfCmd_ += "-a";
93     } else {
94         hiperfCmd_ += "-p " + pids_[0];
95     }
96 
97     running_ = true;
98     th_ = std::thread([this]() {
99         while (running_) {
100             buffer_.clear();
101             std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(hiperfCmd_.c_str(), "r"), pclose);
102             constexpr int lineSize = 1024;
103             std::array<char, lineSize> chunk;
104             while (fgets(chunk.data(), chunk.size(), pipe.get()) != nullptr) {
105                 buffer_.append(chunk.data());
106             }
107 
108             if (!running_) {
109                 return;
110             }
111             std::unique_lock<std::mutex> lock(mtx_);
112             cond_.wait(lock);
113         }
114     });
115     sleep(1);
116 }
117 
FinishtExecutionOnce(bool isPause)118 void CPUInfo::FinishtExecutionOnce(bool isPause)
119 {
120     (void)isPause;
121     running_ = false;
122     Stop();
123     cond_.notify_all();
124     if (th_.joinable()) {
125         th_.join();
126     }
127 }
128 
SetPids(const std::string & pids)129 void CPUInfo::SetPids(const std::string& pids)
130 {
131     pids_.clear();
132     SPUtils::StrSplit(pids, " ", pids_);
133 }
134 
Start()135 void CPUInfo::Start()
136 {
137     cond_.notify_all();
138 }
139 
Stop()140 void CPUInfo::Stop()
141 {
142     std::system("killall hiperf > /data/local/tmp/cpu_temp_error 2>&1");
143     std::remove("/data/local/tmp/cpu_temp_error");
144 }
145 }
146 }