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