1 /*
2 * Copyright (c) 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 "rs_profiler_utils.h"
17
18 #include <chrono>
19 #include <fcntl.h>
20 #include <filesystem>
21 #include <fstream>
22 #include <regex>
23 #include <sstream>
24 #include <string>
25 #ifndef RENDER_PROFILER_APPLICATION
26 #include <dirent.h>
27 #include <sched.h>
28 #include <securec.h>
29 #include <unistd.h>
30
31 #include "directory_ex.h"
32 #include "rs_profiler_log.h"
33 #else
34 #include "rs_adapt.h"
35 #endif
36
37 namespace OHOS::Rosen {
38
39 // Time routines
Now()40 uint64_t Utils::Now()
41 {
42 return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now().time_since_epoch())
43 .count();
44 }
45
ToSeconds(uint64_t nano)46 double Utils::ToSeconds(uint64_t nano)
47 {
48 constexpr double nanoToSeconds = 1e-9;
49 return nano * nanoToSeconds;
50 }
51
ToNanoseconds(double seconds)52 uint64_t Utils::ToNanoseconds(double seconds)
53 {
54 constexpr double secondsToNano = 1e9;
55 return seconds * secondsToNano;
56 }
57
58 #ifdef RENDER_PROFILER_APPLICATION
59 // Cpu routines
GetCpuId()60 int32_t Utils::GetCpuId()
61 {
62 return 0;
63 }
64
SetCpuAffinity(uint32_t cpu)65 void Utils::SetCpuAffinity(uint32_t cpu) {}
66
GetCpuAffinity(uint32_t cpu)67 bool Utils::GetCpuAffinity(uint32_t cpu)
68 {
69 return false; // NOLINT
70 }
71
72 // Process routines
GetPid()73 pid_t Utils::GetPid()
74 {
75 return _getpid();
76 }
77 #else
78 // Cpu routines
GetCpuId()79 int32_t Utils::GetCpuId()
80 {
81 return sched_getcpu();
82 }
83
SetCpuAffinity(uint32_t cpu)84 void Utils::SetCpuAffinity(uint32_t cpu)
85 {
86 cpu_set_t set = {};
87 CPU_ZERO(&set);
88 CPU_SET(cpu, &set); // NOLINT
89 sched_setaffinity(getpid(), sizeof(set), &set);
90 }
91
GetCpuAffinity(uint32_t cpu)92 bool Utils::GetCpuAffinity(uint32_t cpu)
93 {
94 cpu_set_t mask = {};
95 return (sched_getaffinity(0, sizeof(cpu_set_t), &mask) != -1) && CPU_ISSET(cpu, &mask); // NOLINT
96 }
97
98 // Process routines
GetPid()99 pid_t Utils::GetPid()
100 {
101 return getpid();
102 }
103 #endif
104
105 // String routines
Split(const std::string& string)106 std::vector<std::string> Utils::Split(const std::string& string)
107 {
108 std::istringstream stream(string);
109 std::vector<std::string> parts { std::istream_iterator<std::string> { stream },
110 std::istream_iterator<std::string> {} };
111 return parts;
112 }
113
Replace(const std::string& susbtring, std::string& string)114 void Utils::Replace(const std::string& susbtring, std::string& string)
115 {
116 std::string::size_type position = string.find(susbtring);
117 while (position != string.npos) {
118 string.replace(position, 1, "");
119 position = string.find(susbtring);
120 }
121 }
122
ExtractNumber(const std::string& string)123 std::string Utils::ExtractNumber(const std::string& string)
124 {
125 return std::regex_replace(string, std::regex("[^0-9]*([0-9]+).*"), std::string("$1"));
126 }
127
ToInt8(const std::string& string)128 int8_t Utils::ToInt8(const std::string& string)
129 {
130 return static_cast<int8_t>(ToInt32(string));
131 }
132
ToInt16(const std::string& string)133 int16_t Utils::ToInt16(const std::string& string)
134 {
135 return static_cast<int16_t>(ToInt32(string));
136 }
137
ToInt32(const std::string& string)138 int32_t Utils::ToInt32(const std::string& string)
139 {
140 return static_cast<int32_t>(std::atol(string.data()));
141 }
142
ToInt64(const std::string& string)143 int64_t Utils::ToInt64(const std::string& string)
144 {
145 return std::atoll(string.data());
146 }
147
ToUint8(const std::string& string)148 uint8_t Utils::ToUint8(const std::string& string)
149 {
150 return ToUint32(string);
151 }
152
ToUint16(const std::string& string)153 uint16_t Utils::ToUint16(const std::string& string)
154 {
155 return ToUint32(string);
156 }
157
ToUint32(const std::string& string)158 uint32_t Utils::ToUint32(const std::string& string)
159 {
160 return ToUint64(string);
161 }
162
ToUint64(const std::string& string)163 uint64_t Utils::ToUint64(const std::string& string)
164 {
165 constexpr int32_t base = 10;
166 char* end = const_cast<char*>(string.data()) + string.size();
167 return std::strtoull(string.data(), &end, base);
168 }
169
ToFp32(const std::string& string)170 float Utils::ToFp32(const std::string& string)
171 {
172 return static_cast<float>(ToFp64(string));
173 }
174
ToFp64(const std::string& string)175 double Utils::ToFp64(const std::string& string)
176 {
177 char* end = const_cast<char*>(string.data()) + string.size();
178 return std::strtod(string.data(), &end);
179 }
180
ToNumber(const std::string& string, int8_t& number)181 void Utils::ToNumber(const std::string& string, int8_t& number)
182 {
183 number = ToInt8(string);
184 }
185
ToNumber(const std::string& string, int16_t& number)186 void Utils::ToNumber(const std::string& string, int16_t& number)
187 {
188 number = ToInt16(string);
189 }
190
ToNumber(const std::string& string, int32_t& number)191 void Utils::ToNumber(const std::string& string, int32_t& number)
192 {
193 number = ToInt32(string);
194 }
195
ToNumber(const std::string& string, int64_t& number)196 void Utils::ToNumber(const std::string& string, int64_t& number)
197 {
198 number = ToInt64(string);
199 }
200
ToNumber(const std::string& string, uint8_t& number)201 void Utils::ToNumber(const std::string& string, uint8_t& number)
202 {
203 number = ToUint8(string);
204 }
205
ToNumber(const std::string& string, uint16_t& number)206 void Utils::ToNumber(const std::string& string, uint16_t& number)
207 {
208 number = ToUint16(string);
209 }
210
ToNumber(const std::string& string, uint32_t& number)211 void Utils::ToNumber(const std::string& string, uint32_t& number)
212 {
213 number = ToUint32(string);
214 }
215
ToNumber(const std::string& string, uint64_t& number)216 void Utils::ToNumber(const std::string& string, uint64_t& number)
217 {
218 number = ToUint64(string);
219 }
220
ToNumber(const std::string& string, float& number)221 void Utils::ToNumber(const std::string& string, float& number)
222 {
223 number = ToFp32(string);
224 }
225
ToNumber(const std::string& string, double& number)226 void Utils::ToNumber(const std::string& string, double& number)
227 {
228 number = ToFp64(string);
229 }
230
231 // Memory routines
Move(void* destination, size_t destinationSize, const void* source, size_t size)232 bool Utils::Move(void* destination, size_t destinationSize, const void* source, size_t size)
233 {
234 return memmove_s(destination, destinationSize, source, size) == EOK;
235 }
236
Set(void* data, size_t size, int32_t value, size_t count)237 bool Utils::Set(void* data, size_t size, int32_t value, size_t count)
238 {
239 return memset_s(data, size, value, count) == EOK;
240 }
241
242 // File system routines
GetRealPath(const std::string& path)243 std::string Utils::GetRealPath(const std::string& path)
244 {
245 std::string realPath;
246 if (!PathToRealPath(path, realPath)) {
247 HRPE("PathToRealPath fails on %s !", path.data());
248 realPath.clear();
249 }
250 return realPath;
251 }
252
MakePath(const std::string& directory, const std::string& file)253 std::string Utils::MakePath(const std::string& directory, const std::string& file)
254 {
255 return NormalizePath(directory) + file;
256 }
257
NormalizePath(const std::string& path)258 std::string Utils::NormalizePath(const std::string& path)
259 {
260 return (path.rfind('/') != path.size() - 1) ? path + "/" : path;
261 }
262
GetFileName(const std::string& path)263 std::string Utils::GetFileName(const std::string& path)
264 {
265 #ifdef RENDER_PROFILER_APPLICATION
266 return std::filesystem::path(path).filename().string();
267 #else
268 std::string filename;
269 const size_t lastSlashIdx = path.rfind('/');
270 if (std::string::npos != lastSlashIdx) {
271 filename = path.substr(lastSlashIdx + 1);
272 }
273 return filename;
274 #endif
275 }
276
GetDirectory(const std::string& path)277 std::string Utils::GetDirectory(const std::string& path)
278 {
279 #ifdef RENDER_PROFILER_APPLICATION
280 return std::filesystem::path(path).parent_path().string();
281 #else
282 std::string directory;
283 const size_t lastSlashIdx = path.rfind('/');
284 if (std::string::npos != lastSlashIdx) {
285 directory = path.substr(0, lastSlashIdx);
286 }
287 return directory;
288 #endif
289 }
290
IsDirectory(const std::string& path)291 bool Utils::IsDirectory(const std::string& path)
292 {
293 #ifdef RENDER_PROFILER_APPLICATION
294 return std::filesystem::is_directory(path);
295 #else
296 struct stat st {};
297 return (stat(path.data(), &st) == 0) && S_ISDIR(st.st_mode);
298 #endif
299 }
300
IterateDirectory(const std::string& path, std::vector<std::string>& files)301 void Utils::IterateDirectory(const std::string& path, std::vector<std::string>& files)
302 {
303 const std::string realPath = GetRealPath(path);
304 if (realPath.empty()) {
305 return;
306 }
307
308 #ifdef RENDER_PROFILER_APPLICATION
309 for (auto const& entry : std::filesystem::recursive_directory_iterator(path)) {
310 if (entry.is_directory()) {
311 IterateDirectory(entry.path().string(), files);
312 } else {
313 files.push_back(entry.path().string());
314 }
315 }
316 #else
317 DIR* directory = opendir(realPath.data());
318 if (!directory) {
319 return;
320 }
321
322 while (struct dirent* entry = readdir(directory)) {
323 const std::string entryName(entry->d_name);
324 if ((entryName == ".") || (entryName == "..")) {
325 continue;
326 }
327 const std::string entryPath = NormalizePath(realPath) + entryName;
328 if (entry->d_type == DT_DIR) {
329 IterateDirectory(entryPath, files);
330 } else {
331 files.push_back(entryPath);
332 }
333 }
334 closedir(directory);
335 #endif
336 }
337
LoadLine(const std::string& path, std::string& line)338 void Utils::LoadLine(const std::string& path, std::string& line)
339 {
340 line.clear();
341
342 const std::string realPath = GetRealPath(path);
343 if (realPath.empty()) {
344 return;
345 }
346
347 std::ifstream file(realPath);
348 if (file) {
349 std::getline(file, line);
350 }
351 }
352
LoadLines(const std::string& path, std::vector<std::string>& lines)353 void Utils::LoadLines(const std::string& path, std::vector<std::string>& lines)
354 {
355 lines.clear();
356
357 const std::string realPath = GetRealPath(path);
358 if (realPath.empty()) {
359 return;
360 }
361
362 std::ifstream file(realPath);
363 if (file) {
364 std::string line;
365 while (std::getline(file, line)) {
366 lines.emplace_back(line);
367 }
368 }
369 }
370
LoadContent(const std::string& path, std::string& content)371 void Utils::LoadContent(const std::string& path, std::string& content)
372 {
373 content.clear();
374
375 const std::string realPath = GetRealPath(path);
376 if (realPath.empty()) {
377 return;
378 }
379
380 std::ifstream file(realPath);
381 if (file) {
382 copy(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>(), std::back_inserter(content));
383 Replace("\r", content);
384 Replace("\n", content);
385 }
386 }
387
388 static std::stringstream g_recordInMemory(std::ios::in | std::ios::out | std::ios::binary);
389 static FILE* g_recordInMemoryFile = reinterpret_cast<FILE*>(1);
390
IsRecordInMemoryFile(const std::string& path)391 static bool IsRecordInMemoryFile(const std::string& path)
392 {
393 return path == "RECORD_IN_MEMORY";
394 }
395
HasWriteFlag(const std::string& options)396 static bool HasWriteFlag(const std::string& options)
397 {
398 return options.find('w') != std::string::npos;
399 }
400
HasAppendFlag(const std::string& options)401 static bool HasAppendFlag(const std::string& options)
402 {
403 return options.find('a') != std::string::npos;
404 }
405
ShouldFileBeCreated(const std::string& options)406 static bool ShouldFileBeCreated(const std::string& options)
407 {
408 return HasWriteFlag(options) || HasAppendFlag(options);
409 }
410
FileExists(const std::string& path)411 bool Utils::FileExists(const std::string& path)
412 {
413 if (IsRecordInMemoryFile(path)) {
414 return true;
415 }
416 #ifdef RENDER_PROFILER_APPLICATION
417 return std::filesystem::exists(path);
418 #else
419 struct stat st {};
420 return (stat(path.data(), &st) == 0) && S_ISREG(st.st_mode);
421 #endif
422 }
423
FileDelete(const std::string& path)424 bool Utils::FileDelete(const std::string& path)
425 {
426 if (IsRecordInMemoryFile(path)) {
427 g_recordInMemory = std::stringstream(std::ios::in | std::ios::out | std::ios::binary);
428 return true;
429 }
430
431 const std::string realPath = GetRealPath(path);
432 if (!FileExists(realPath)) {
433 return false;
434 }
435
436 return std::filesystem::remove(realPath);
437 }
438
FileOpen(const std::string& path, const std::string& options)439 FILE* Utils::FileOpen(const std::string& path, const std::string& options)
440 {
441 if (IsRecordInMemoryFile(path)) {
442 g_recordInMemory.seekg(0, std::ios_base::beg);
443 g_recordInMemory.seekp(0, std::ios_base::beg);
444 return g_recordInMemoryFile;
445 }
446
447 const std::string realPath = GetRealPath(path);
448 if (realPath.empty()) {
449 HRPE("FileOpen: '%s' is invalid!", path.data()); // NOLINT
450 return nullptr;
451 }
452
453 #ifndef RENDER_PROFILER_APPLICATION
454 if (ShouldFileBeCreated(options) && !FileExists(realPath)) {
455 auto file = open(realPath.data(), O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
456 if (file != -1) {
457 close(file);
458 }
459 }
460 #endif
461
462 auto file = fopen(realPath.data(), options.data());
463 if (!IsFileValid(file)) {
464 HRPE("FileOpen: Cannot open '%s' with options '%s'!", realPath.data(), options.data()); // NOLINT
465 }
466 return file;
467 }
468
FileClose(FILE* file)469 void Utils::FileClose(FILE* file)
470 {
471 if (file == g_recordInMemoryFile) {
472 g_recordInMemory.seekg(0, std::ios_base::beg);
473 g_recordInMemory.seekp(0, std::ios_base::beg);
474 return;
475 }
476 if (fflush(file) != 0) {
477 HRPE("File flush failed"); // NOLINT
478 }
479 if (fclose(file) != 0) {
480 HRPE("File close failed"); // NOLINT
481 }
482 }
483
IsFileValid(FILE* file)484 bool Utils::IsFileValid(FILE* file)
485 {
486 return file != nullptr;
487 }
488
FileSize(FILE* file)489 size_t Utils::FileSize(FILE* file)
490 {
491 if (file == g_recordInMemoryFile) {
492 const auto position = g_recordInMemory.tellg();
493 g_recordInMemory.seekg(0, std::ios_base::end);
494 const auto size = g_recordInMemory.tellg();
495 if (size == -1) {
496 g_recordInMemory.seekg(0, std::ios_base::beg);
497 return 0;
498 }
499 g_recordInMemory.seekg(position, std::ios_base::beg);
500 return static_cast<size_t>(size);
501 }
502 if (!IsFileValid(file)) {
503 return 0;
504 }
505
506 const auto position = ftell(file);
507 if (position == -1) {
508 return 0;
509 }
510 FileSeek(file, 0, SEEK_END);
511 const auto size = ftell(file);
512 FileSeek(file, position, SEEK_SET);
513 return static_cast<size_t>(size);
514 }
515
FileTell(FILE* file)516 size_t Utils::FileTell(FILE* file)
517 {
518 if (file == g_recordInMemoryFile) {
519 return g_recordInMemory.tellg();
520 }
521 if (!IsFileValid(file)) {
522 return 0;
523 }
524
525 return ftell(file);
526 }
527
FileSeek(FILE* file, int64_t offset, int origin)528 void Utils::FileSeek(FILE* file, int64_t offset, int origin)
529 {
530 if (file == g_recordInMemoryFile) {
531 if (origin == SEEK_SET) {
532 g_recordInMemory.seekg(offset, std::ios_base::beg);
533 g_recordInMemory.seekp(offset, std::ios_base::beg);
534 } else if (origin == SEEK_CUR) {
535 g_recordInMemory.seekg(offset, std::ios_base::cur);
536 g_recordInMemory.seekp(offset, std::ios_base::cur);
537 } else if (origin == SEEK_END) {
538 g_recordInMemory.seekg(offset, std::ios_base::end);
539 g_recordInMemory.seekp(offset, std::ios_base::end);
540 }
541 return;
542 }
543 if (fseek(file, offset, origin) != 0) {
544 HRPE("Failed fseek in file"); // NOLINT
545 }
546 }
547
FileRead(FILE* file, void* data, size_t size)548 void Utils::FileRead(FILE* file, void* data, size_t size)
549 {
550 if (!data) {
551 HRPE("FileRead: Data is null"); // NOLINT
552 return;
553 }
554
555 if (file == g_recordInMemoryFile) {
556 g_recordInMemory.read(reinterpret_cast<char*>(data), size);
557 g_recordInMemory.seekp(g_recordInMemory.tellg());
558 return;
559 }
560 if (fread(data, size, 1, file) < 1) {
561 HRPE("FileRead: Error while reading from file"); // NOLINT
562 }
563 }
564
FileWrite(FILE* file, const void* data, size_t size)565 void Utils::FileWrite(FILE* file, const void* data, size_t size)
566 {
567 const size_t maxDataSize = 2'000'000'000; // To make sure size is a valid value
568 if (!data || (size == 0) || (size > maxDataSize)) {
569 HRPE("FileWrite: data or size is invalid, size %zu", size); // NOLINT
570 return;
571 }
572
573 if (file == g_recordInMemoryFile) {
574 g_recordInMemory.write(reinterpret_cast<const char*>(data), size);
575 g_recordInMemory.seekg(g_recordInMemory.tellp());
576 return;
577 }
578 if (fwrite(data, size, 1, file) < 1) {
579 HRPE("FileWrite: Error while writing to file"); // NOLINT
580 }
581 }
582
583 // deprecated
584 void Utils::FileRead(void* data, size_t size, size_t count, FILE* file)
585 {
586 FileRead(file, data, size * count);
587 }
588
589 // deprecated
590 void Utils::FileWrite(const void* data, size_t size, size_t count, FILE* file)
591 {
592 FileWrite(file, data, size * count);
593 }
594
595 } // namespace OHOS::Rosen