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