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 27namespace OHOS { 28namespace HiviewDFX { 29namespace Hitrace { 30namespace { 31const std::string CPUFREQ_PREFIX = "/sys/devices/system/cpu/cpu"; 32const std::string CPUFREQ_AFTERFIX = "/cpufreq/scaling_cur_freq"; 33} 34 35std::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 65bool 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 121static 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 137static 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 150static 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 176static 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 196bool 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 229bool 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 242int GetCpuProcessors() 243{ 244 int processors = 0; 245 processors = sysconf(_SC_NPROCESSORS_CONF); 246 return (processors == 0) ? 1 : processors; 247} 248 249void 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