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