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 }