1 /*
2 * Copyright (c) 2023-2024 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 "common_utils.h"
17
18 #include <cinttypes>
19 #include <unistd.h>
20 #include <cstdio>
21 #include <fstream>
22 #include <fcntl.h>
23 #include <sstream>
24 #include "cJSON.h"
25 #include "securec.h"
26
27 namespace OHOS {
28 namespace HiviewDFX {
29 namespace Hitrace {
30 namespace {
31 const std::string CPUFREQ_PREFIX = "/sys/devices/system/cpu/cpu";
32 const std::string CPUFREQ_AFTERFIX = "/cpufreq/scaling_cur_freq";
33 }
34
CanonicalizeSpecPath(const char* src)35 std::string CanonicalizeSpecPath(const char* src)
36 {
37 if (src == nullptr || strlen(src) >= PATH_MAX) {
38 HILOG_ERROR(LOG_CORE, "CanonicalizeSpecPath: %{pubilc}s failed.", src);
39 return "";
40 }
41 char resolvedPath[PATH_MAX] = { 0 };
42
43 if (access(src, F_OK) == 0) {
44 if (realpath(src, resolvedPath) == nullptr) {
45 HILOG_ERROR(LOG_CORE, "CanonicalizeSpecPath: realpath %{pubilc}s failed.", src);
46 return "";
47 }
48 } else {
49 std::string fileName(src);
50 if (fileName.find("..") == std::string::npos) {
51 if (sprintf_s(resolvedPath, PATH_MAX, "%s", src) == -1) {
52 HILOG_ERROR(LOG_CORE, "CanonicalizeSpecPath: sprintf_s %{pubilc}s failed.", src);
53 return "";
54 }
55 } else {
56 HILOG_ERROR(LOG_CORE, "CanonicalizeSpecPath: find .. src failed.");
57 return "";
58 }
59 }
60
61 std::string res(resolvedPath);
62 return res;
63 }
64
MarkClockSync(const std::string& traceRootPath)65 bool MarkClockSync(const std::string& traceRootPath)
66 {
67 constexpr unsigned int bufferSize = 128;
68 char buffer[bufferSize] = { 0 };
69 std::string traceMarker = "trace_marker";
70 std::string resolvedPath = CanonicalizeSpecPath((traceRootPath + traceMarker).c_str());
71 int fd = open(resolvedPath.c_str(), O_WRONLY);
72 if (fd == -1) {
73 HILOG_ERROR(LOG_CORE, "MarkClockSync: oepn %{public}s fail, errno(%{public}d)", resolvedPath.c_str(), errno);
74 return false;
75 }
76
77 // write realtime_ts
78 struct timespec rts = {0, 0};
79 if (clock_gettime(CLOCK_REALTIME, &rts) == -1) {
80 HILOG_ERROR(LOG_CORE, "MarkClockSync: get realtime error, errno(%{public}d)", errno);
81 close(fd);
82 return false;
83 }
84 constexpr unsigned int nanoSeconds = 1000000000; // seconds converted to nanoseconds
85 constexpr unsigned int nanoToMill = 1000000; // millisecond converted to nanoseconds
86 int len = snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1,
87 "trace_event_clock_sync: realtime_ts=%" PRId64 "\n",
88 static_cast<int64_t>((rts.tv_sec * nanoSeconds + rts.tv_nsec) / nanoToMill));
89 if (len < 0) {
90 HILOG_ERROR(LOG_CORE, "MarkClockSync: entering realtime_ts into buffer error, errno(%{public}d)", errno);
91 close(fd);
92 return false;
93 }
94
95 if (write(fd, buffer, len) < 0) {
96 HILOG_ERROR(LOG_CORE, "MarkClockSync: writing realtime error, errno(%{public}d)", errno);
97 }
98
99 // write parent_ts
100 struct timespec mts = {0, 0};
101 if (clock_gettime(CLOCK_MONOTONIC, &mts) == -1) {
102 HILOG_ERROR(LOG_CORE, "MarkClockSync: get parent_ts error, errno(%{public}d)", errno);
103 close(fd);
104 return false;
105 }
106 constexpr float nanoToSecond = 1000000000.0f; // consistent with the ftrace timestamp format
107 len = snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, "trace_event_clock_sync: parent_ts=%f\n",
108 static_cast<float>(((static_cast<float>(mts.tv_sec)) * nanoSeconds + mts.tv_nsec) / nanoToSecond));
109 if (len < 0) {
110 HILOG_ERROR(LOG_CORE, "MarkClockSync: entering parent_ts into buffer error, errno(%{public}d)", errno);
111 close(fd);
112 return false;
113 }
114 if (write(fd, buffer, len) < 0) {
115 HILOG_ERROR(LOG_CORE, "MarkClockSync: writing parent_ts error, errno(%{public}d)", errno);
116 }
117 close(fd);
118 return true;
119 }
120
ParseJsonFromFile(const std::string& filePath)121 static cJSON* ParseJsonFromFile(const std::string& filePath)
122 {
123 std::ifstream inFile(filePath, std::ios::in);
124 if (!inFile.is_open()) {
125 HILOG_ERROR(LOG_CORE, "ParseJsonFromFile: %{public}s is not existed.", filePath.c_str());
126 return nullptr;
127 }
128 std::string fileContent((std::istreambuf_iterator<char>(inFile)), std::istreambuf_iterator<char>());
129 cJSON* root = cJSON_Parse(fileContent.c_str());
130 if (root == nullptr) {
131 HILOG_ERROR(LOG_CORE, "ParseJsonFromFile: %{public}s is not in JSON format.", filePath.c_str());
132 }
133 inFile.close();
134 return root;
135 }
136
ParseSysFiles(cJSON *tags, TagCategory& tagCategory)137 static void ParseSysFiles(cJSON *tags, TagCategory& tagCategory)
138 {
139 cJSON *sysFiles = cJSON_GetObjectItem(tags, "sysFiles");
140 if (sysFiles != nullptr && cJSON_IsArray(sysFiles)) {
141 cJSON *sysFile = nullptr;
142 cJSON_ArrayForEach(sysFile, sysFiles) {
143 if (cJSON_IsString(sysFile)) {
144 tagCategory.sysFiles.push_back(sysFile->valuestring);
145 }
146 }
147 }
148 }
149
ParseTagCategory(cJSON* tagCategoryNode, std::map<std::string, TagCategory>& allTags)150 static bool ParseTagCategory(cJSON* tagCategoryNode, std::map<std::string, TagCategory>& allTags)
151 {
152 cJSON* tags = nullptr;
153 cJSON_ArrayForEach(tags, tagCategoryNode) {
154 if (tags == nullptr || tags->string == nullptr) {
155 continue;
156 }
157 TagCategory tagCategory;
158 cJSON* description = cJSON_GetObjectItem(tags, "description");
159 if (description != nullptr && cJSON_IsString(description)) {
160 tagCategory.description = description->valuestring;
161 }
162 cJSON* tagOffset = cJSON_GetObjectItem(tags, "tag_offset");
163 if (tagOffset != nullptr && cJSON_IsNumber(tagOffset)) {
164 tagCategory.tag = 1ULL << tagOffset->valueint;
165 }
166 cJSON* type = cJSON_GetObjectItem(tags, "type");
167 if (type != nullptr && cJSON_IsNumber(type)) {
168 tagCategory.type = type->valueint;
169 }
170 ParseSysFiles(tags, tagCategory);
171 allTags.insert(std::pair<std::string, TagCategory>(tags->string, tagCategory));
172 }
173 return true;
174 }
175
ParseTagGroups(cJSON* tagGroupsNode, std::map<std::string, std::vector<std::string>> &tagGroupTable)176 static bool ParseTagGroups(cJSON* tagGroupsNode, std::map<std::string, std::vector<std::string>> &tagGroupTable)
177 {
178 cJSON* tagGroup = nullptr;
179 cJSON_ArrayForEach(tagGroup, tagGroupsNode) {
180 if (tagGroup == nullptr || tagGroup->string == nullptr) {
181 continue;
182 }
183 std::string tagGroupName = tagGroup->string;
184 std::vector<std::string> tagList;
185 cJSON* tag = nullptr;
186 cJSON_ArrayForEach(tag, tagGroup) {
187 if (cJSON_IsString(tag)) {
188 tagList.push_back(tag->valuestring);
189 }
190 }
191 tagGroupTable.insert(std::pair<std::string, std::vector<std::string>>(tagGroupName, tagList));
192 }
193 return true;
194 }
195
ParseTagInfo(std::map<std::string, TagCategory> &allTags, std::map<std::string, std::vector<std::string>> &tagGroupTable)196 bool ParseTagInfo(std::map<std::string, TagCategory> &allTags,
197 std::map<std::string, std::vector<std::string>> &tagGroupTable)
198 {
199 std::string traceUtilsPath = "/system/etc/hiview/hitrace_utils.json";
200 cJSON* root = ParseJsonFromFile(traceUtilsPath);
201 if (root == nullptr) {
202 return false;
203 }
204 cJSON* tagCategory = cJSON_GetObjectItem(root, "tag_category");
205 if (tagCategory == nullptr) {
206 HILOG_ERROR(LOG_CORE, "ParseTagInfo: %{public}s is not contain tag_category node.", traceUtilsPath.c_str());
207 cJSON_Delete(root);
208 return false;
209 }
210 if (!ParseTagCategory(tagCategory, allTags)) {
211 cJSON_Delete(root);
212 return false;
213 }
214 cJSON* tagGroups = cJSON_GetObjectItem(root, "tag_groups");
215 if (tagGroups == nullptr) {
216 HILOG_ERROR(LOG_CORE, "ParseTagInfo: %{public}s is not contain tag_groups node.", traceUtilsPath.c_str());
217 cJSON_Delete(root);
218 return false;
219 }
220 if (!ParseTagGroups(tagGroups, tagGroupTable)) {
221 cJSON_Delete(root);
222 return false;
223 }
224 cJSON_Delete(root);
225 HILOG_INFO(LOG_CORE, "ParseTagInfo: parse done.");
226 return true;
227 }
228
IsNumber(const std::string &str)229 bool IsNumber(const std::string &str)
230 {
231 if (str.empty()) {
232 return false;
233 }
234 for (auto c : str) {
235 if (!isdigit(c)) {
236 return false;
237 }
238 }
239 return true;
240 }
241
GetCpuProcessors()242 int GetCpuProcessors()
243 {
244 int processors = 0;
245 processors = sysconf(_SC_NPROCESSORS_CONF);
246 return (processors == 0) ? 1 : processors;
247 }
248
ReadCurrentCpuFrequencies(std::string& freqs)249 void ReadCurrentCpuFrequencies(std::string& freqs)
250 {
251 int cpuNum = GetCpuProcessors();
252 std::ifstream file;
253 std::string line;
254 for (int i = 0; i < cpuNum; ++i) {
255 std::string freq = "0";
256 std::string cpuFreqPath = CPUFREQ_PREFIX + std::to_string(i) + CPUFREQ_AFTERFIX;
257 file.open(cpuFreqPath);
258 if (file.is_open()) {
259 if (std::getline(file, line)) {
260 std::istringstream iss(line);
261 iss >> freq;
262 }
263 file.close();
264 }
265 freqs += "cpu_id=" + std::to_string(i) + " state=" + freq;
266 if (i != cpuNum - 1) {
267 freqs += ",";
268 }
269 }
270 }
271 } // namespace Hitrace
272 } // namespace HiviewDFX
273 } // namespace OHOS
274