• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2021-2023. All rights reserved.
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 #include "trace_file_writer.h"
16 
17 #include <cinttypes>
18 #include <fcntl.h>
19 #include <memory>
20 #include <sys/mman.h>
21 #include <sys/statvfs.h>
22 #include <unistd.h>
23 #include <cstdio>
24 
25 #include "common.h"
26 #ifdef LITE_PROTO
27 #include "common_types_lite.pb.h"
28 #else
29 #include "common_types.pb.h"
30 #endif
31 #include "logging.h"
32 
33 using CharPtr = std::unique_ptr<char>::pointer;
34 using ConstCharPtr = std::unique_ptr<const char>::pointer;
35 
36 namespace {
37 constexpr int MB_TO_BYTE = (1024 * 1024);
38 constexpr int GB_TO_BYTE = (1024 * 1024 * 1024);
39 constexpr int SPLIT_FILE_MIN_SIZE = 200;    // split file min size
40 constexpr int SPLIT_FILE_DEFAULT_NUM = 10;  // split file default num
41 constexpr size_t DEFULT_PAGES = 32 * 256; // 32M
42 constexpr int PIECE_HEAD_LEN = 4;
43 } // namespace
44 
TraceFileWriter(const std::string & path)45 TraceFileWriter::TraceFileWriter(const std::string& path) : TraceFileWriter(path, false, 0, 0) {}
46 
TraceFileWriter(int32_t fd)47 TraceFileWriter::TraceFileWriter(int32_t fd) : fd_(fd)
48 {
49     writeCtx_.write = this;
50     writeCtx_.ctx.getMemory = [](RandomWriteCtx* ctx, uint32_t size, uint8_t** memory, uint32_t* offset) -> bool {
51         TraceFileWriterCtx* writeCtx = reinterpret_cast<TraceFileWriterCtx*>(ctx);
52         return writeCtx->write->GetMemory(size, memory, offset);
53     };
54     writeCtx_.ctx.seek = [](RandomWriteCtx* ctx, uint32_t offset) -> bool {
55         TraceFileWriterCtx* writeCtx = reinterpret_cast<TraceFileWriterCtx*>(ctx);
56         return writeCtx->write->Seek(offset);
57     };
58 
59     CHECK_TRUE(fd_ != 0, NO_RETVAL, "only-nmd mode, no need to use TraceFileWriter");
60     if (write(fd_, &header_, sizeof(header_)) != sizeof(header_)) {
61         PROFILER_LOG_ERROR(LOG_CORE, "write initial header failed!, error: %s", strerror(errno));
62         return;
63     }
64     (void)FlushStream();
65     fileWriteLength_ = sizeof(header_);
66     mapOffset_ = sizeof(header_);
67     messageWriteOffset_ = PIECE_HEAD_LEN;
68     pageSize_ = static_cast<size_t>(sysconf(_SC_PAGE_SIZE));
69     fileLength_ = DEFULT_PAGES * pageSize_;
70 
71     if (fallocate(fd_, 0, 0, fileLength_) != 0) {
72         PROFILER_LOG_ERROR(LOG_CORE, "fallocate file(%zu) failed, error: %s", fileLength_, strerror(errno));
73         return;
74     }
75 
76     fileMapAddr_ = mmap(nullptr, fileLength_, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, fd_, 0);
77     if (fileMapAddr_ == MAP_FAILED) {
78         PROFILER_LOG_ERROR(LOG_CORE, "mmap file(%d) failed, error: %s", fd_, strerror(errno));
79         return;
80     }
81     mmapFileLength_ = fileLength_;
82 }
83 
TraceFileWriter(const std::string & path,bool splitFile,uint32_t splitFileMaxSizeMb,uint32_t splitFileMaxNum)84 TraceFileWriter::TraceFileWriter(const std::string& path, bool splitFile, uint32_t splitFileMaxSizeMb,
85     uint32_t splitFileMaxNum) : path_(path), isSplitFile_(splitFile)
86 {
87     splitFileMaxSize_ = (splitFileMaxSizeMb < SPLIT_FILE_MIN_SIZE) ? (SPLIT_FILE_MIN_SIZE * MB_TO_BYTE) :
88         (splitFileMaxSizeMb * MB_TO_BYTE);
89     splitFileMaxNum_ = (splitFileMaxNum == 0) ? SPLIT_FILE_DEFAULT_NUM : splitFileMaxNum;
90     oldPath_ = path;
91     fileNum_ = 1;
92 
93     WriteHeader();
94     (void)FlushStream();
95 }
96 
~TraceFileWriter()97 TraceFileWriter::~TraceFileWriter()
98 {
99     CHECK_TRUE(fd_ != 0, NO_RETVAL, "only-nmd mode, no need to use TraceFileWriter");
100     (void)FlushStream();
101     if (stream_.is_open()) {
102         stream_.close();
103     }
104     if (fileMapAddr_ != MAP_FAILED) {
105         munmap(fileMapAddr_, mmapFileLength_);
106     }
107 }
108 
Path() const109 std::string TraceFileWriter::Path() const
110 {
111     return path_;
112 }
113 
SetPluginConfig(const void * data,size_t size)114 bool TraceFileWriter::SetPluginConfig(const void* data, size_t size)
115 {
116     CHECK_TRUE(fd_ != 0, false, "SetPluginConfig, nmd mode no need to use TraceFileWriter");
117     if (isSplitFile_) {
118         std::vector<char> configVec;
119         auto configData = reinterpret_cast<ConstCharPtr>(data);
120         configVec.insert(configVec.end(), configData, configData + size);
121         pluginConfigsData_.push_back(std::move(configVec));
122     }
123 
124     Write(data, size);
125     return true;
126 }
127 
128 #ifdef LITE_PROTO
WriteStandalonePluginData(const std::string & pluginName,const std::string & data,const std::string & pluginVersion)129 void TraceFileWriter::WriteStandalonePluginData(
130     const std::string &pluginName, const std::string &data,
131     const std::string &pluginVersion)
132 {
133     CHECK_TRUE(fd_ != 0, NO_RETVAL, "WriteStandalonePluginData, nmd mode no need to use TraceFileWriter");
134     LITE::ProfilerPluginData pluginData;
135     pluginData.set_name(pluginName);
136     pluginData.set_data(data);
137     if (!pluginVersion.empty()) {
138         pluginData.set_version(pluginVersion);
139         pluginData.set_status(0);
140 
141         struct timespec ts = { 0, 0 };
142         clock_gettime(CLOCK_REALTIME, &ts);
143         pluginData.set_tv_sec(ts.tv_sec);
144         pluginData.set_tv_nsec(ts.tv_nsec);
145         pluginData.set_clock_id(LITE::ProfilerPluginData::CLOCKID_REALTIME);
146     }
147 
148     std::vector<char> msgData(pluginData.ByteSizeLong());
149     if (pluginData.SerializeToArray(msgData.data(), msgData.size()) <= 0) {
150         PROFILER_LOG_WARN(LOG_CORE, "%s StandalonePluginData SerializeToArray failed!", pluginName.c_str());
151     }
152 
153     Write(msgData.data(), msgData.size());
154 }
155 #endif
156 
SetTimeStamp()157 void TraceFileWriter::SetTimeStamp()
158 {
159     CHECK_TRUE(fd_ != 0, NO_RETVAL, "SetTimeStamp, nmd mode no need to use TraceFileWriter");
160     header_.data_.boottime = headerDataTime_.boottime;
161     header_.data_.realtime = headerDataTime_.realtime;
162     header_.data_.realtimeCoarse = headerDataTime_.realtimeCoarse;
163     header_.data_.monotonic = headerDataTime_.monotonic;
164     header_.data_.monotonicCoarse = headerDataTime_.monotonicCoarse;
165     header_.data_.monotonicRaw = headerDataTime_.monotonicRaw;
166     header_.data_.durationNs = headerDataTime_.durationNs;
167 }
168 
SetTimeSource()169 void TraceFileWriter::SetTimeSource()
170 {
171     CHECK_TRUE(fd_ != 0, NO_RETVAL, "SetTimeSource, nmd mode no need to use TraceFileWriter");
172     constexpr uint64_t nanoSeconds = 1000000000;
173     struct timespec ts;
174     clock_gettime(CLOCK_BOOTTIME, &ts);
175     headerDataTime_.boottime = static_cast<uint64_t>(ts.tv_sec) * nanoSeconds +
176         static_cast<uint64_t>(ts.tv_nsec);
177     clock_gettime(CLOCK_REALTIME, &ts);
178     headerDataTime_.realtime = static_cast<uint64_t>(ts.tv_sec) * nanoSeconds +
179         static_cast<uint64_t>(ts.tv_nsec);
180     clock_gettime(CLOCK_REALTIME_COARSE, &ts);
181     headerDataTime_.realtimeCoarse = static_cast<uint64_t>(ts.tv_sec) * nanoSeconds +
182         static_cast<uint64_t>(ts.tv_nsec);
183     clock_gettime(CLOCK_MONOTONIC, &ts);
184     headerDataTime_.monotonic = static_cast<uint64_t>(ts.tv_sec) * nanoSeconds +
185         static_cast<uint64_t>(ts.tv_nsec);
186     clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
187     headerDataTime_.monotonicCoarse = static_cast<uint64_t>(ts.tv_sec) * nanoSeconds +
188         static_cast<uint64_t>(ts.tv_nsec);
189     clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
190     headerDataTime_.monotonicRaw = static_cast<uint64_t>(ts.tv_sec) * nanoSeconds +
191         static_cast<uint64_t>(ts.tv_nsec);
192 }
193 
SetDurationTime()194 void TraceFileWriter::SetDurationTime()
195 {
196     CHECK_TRUE(fd_ != 0, NO_RETVAL, "SetDurationTime, nmd mode no need to use TraceFileWriter");
197     struct timespec ts;
198     clock_gettime(CLOCK_BOOTTIME, &ts);
199     constexpr uint64_t nanoSeconds = 1000000000;
200     auto currBoottime = static_cast<uint64_t>(ts.tv_sec) * nanoSeconds + static_cast<uint64_t>(ts.tv_nsec);
201     headerDataTime_.durationNs = currBoottime - headerDataTime_.boottime;
202 }
203 
WriteHeader()204 bool TraceFileWriter::WriteHeader()
205 {
206     CHECK_TRUE(fd_ != 0, false, "WriteHeader, nmd-only mode no need to use TraceFileWriter");
207     LogDiskUsage();
208     if (isSplitFile_) {
209         std::string timeStr = COMMON::GetTimeStr();
210         std::size_t pos = oldPath_.find_last_of('.');
211         if (pos != std::string::npos) {
212             path_ = oldPath_.substr(0, pos) + "_" + timeStr + "_" + std::to_string(fileNum_) +
213                 oldPath_.substr(pos, oldPath_.size());
214         } else {
215             path_ = oldPath_ + "_" + timeStr + "_" + std::to_string(fileNum_);
216         }
217         splitFilePaths_.push(path_);
218         DeleteOldSplitFile();
219     }
220 
221     stream_ = std::ofstream(path_, std::ios_base::out | std::ios_base::binary);
222     CHECK_TRUE(stream_.is_open(), false, "open %s failed, %d!", path_.c_str(), errno);
223 
224     // write initial header, makes file write position move forward
225     helper_ = {};
226     header_ = {};
227     stream_.write(reinterpret_cast<CharPtr>(&header_), sizeof(header_));
228     CHECK_TRUE(stream_, false, "write initial header to %s failed!", path_.c_str());
229     dataSize_ = header_.HEADER_SIZE;
230     PROFILER_LOG_INFO(LOG_CORE, "write file(%s) header end", path_.c_str());
231     return true;
232 }
233 
234 // delete first split file if split file num over max
DeleteOldSplitFile()235 void TraceFileWriter::DeleteOldSplitFile()
236 {
237     if (splitFilePaths_.size() <= splitFileMaxNum_) {
238         PROFILER_LOG_INFO(LOG_CORE, "splitFilePaths_ size %zu, no need to delete.", splitFilePaths_.size());
239         return;
240     }
241 
242     std::string splitFilePath = splitFilePaths_.front();
243     int ret = unlink(splitFilePath.c_str());
244     PROFILER_LOG_INFO(LOG_CORE, "DeleteOldSplitFile remove %s return %d. ", splitFilePath.c_str(), ret);
245     splitFilePaths_.pop();
246 }
247 
Write(const void * data,size_t size)248 long TraceFileWriter::Write(const void* data, size_t size)
249 {
250     CHECK_TRUE(fd_ != 0, 0, "Write, nmd-only mode no need to use TraceFileWriter");
251     if (isSplitFile_ && !isStop_) {
252         if (IsSplitFile(size)) {
253             return -1;
254         }
255     }
256 
257     uint32_t dataLen = size;
258     CHECK_TRUE(stream_.is_open(), 0, "binary file %s not open or open failed!", path_.c_str());
259 
260     // write 4B data length.
261     stream_.write(reinterpret_cast<CharPtr>(&dataLen), sizeof(dataLen));
262     CHECK_TRUE(stream_, 0, "binary file %s write raw buffer size failed!", path_.c_str());
263     CHECK_TRUE(helper_.AddSegment(reinterpret_cast<uint8_t*>(&dataLen), sizeof(dataLen)),
264         0, "Add payload for size %u FAILED!", dataLen);
265 
266     // write data bytes
267     stream_.write(reinterpret_cast<ConstCharPtr>(data), size);
268     CHECK_TRUE(stream_, 0, "binary file %s write raw buffer data failed!", path_.c_str());
269 
270     CHECK_TRUE(helper_.AddSegment(reinterpret_cast<uint8_t*>(const_cast<void*>(data)), size),
271         0, "Add payload for data bytes %zu FAILED!", size);
272 
273     uint64_t nbytes = sizeof(dataLen) + size;
274     writeBytes_ += nbytes;
275     ++writeCount_;
276     return nbytes;
277 }
278 
WriteStandalonePluginFile(const std::string & file,const std::string & name,const std::string & version,DataType type)279 long TraceFileWriter::WriteStandalonePluginFile(const std::string &file,
280                                                 const std::string &name,
281                                                 const std::string &version,
282                                                 DataType type)
283 {
284     CHECK_TRUE(fd_ != 0, 0, "WriteStandalonePluginFile, no need to use TraceFileWriter");
285     CHECK_TRUE(stream_.is_open(), 0, "binary file %s not open or open failed!", path_.c_str());
286     auto retFile = COMMON::CheckNotExistsFilePath(file);
287     if (!retFile.first) {
288         PROFILER_LOG_INFO(LOG_CORE, "%s:check file path %s fail", __func__, file.c_str());
289         return 0;
290     }
291     std::ifstream fsFile {}; // read data from file
292     fsFile.open(retFile.second, std::ios_base::in | std::ios_base::binary);
293     if (!fsFile.good()) {
294         PROFILER_LOG_ERROR(LOG_CORE, "open file(%s) failed: %d", file.c_str(), fsFile.rdstate());
295         return 0;
296     }
297     TraceFileHeader header {};
298     fsFile.seekg(0, std::ios_base::end);
299     uint64_t fileSize = static_cast<uint64_t>(fsFile.tellg());
300     header.data_.length += fileSize;
301     size_t size = name.size();
302     if (size > 0) {
303         if (size > PLUGIN_MODULE_NAME_MAX) {
304             PROFILER_LOG_ERROR(LOG_CORE, "standalonePluginName(%s) size(%zu) is greater than %d!",
305                 name.c_str(), size, PLUGIN_MODULE_NAME_MAX);
306         } else if (strncpy_s(header.data_.standalonePluginName, PLUGIN_MODULE_NAME_MAX, name.c_str(), size) != EOK) {
307             PROFILER_LOG_ERROR(LOG_CORE, "strncpy_s standalonePluginName(%s) error!", name.c_str());
308         }
309     }
310     size = version.size();
311     if (size > 0) {
312         if (size > PLUGIN_MODULE_VERSION_MAX) {
313             PROFILER_LOG_ERROR(LOG_CORE, "pluginVersion(%s) size(%zu) is greater than %d!",
314                 version.c_str(), size, PLUGIN_MODULE_VERSION_MAX);
315         } else if (strncpy_s(header.data_.pluginVersion, PLUGIN_MODULE_VERSION_MAX, version.c_str(), size) != EOK) {
316             PROFILER_LOG_ERROR(LOG_CORE, "strncpy_s pluginVersion(%s) error!", version.c_str());
317         }
318     }
319     header.data_.dataType = type;
320     stream_.write(reinterpret_cast<char*>(&header), sizeof(header));
321 
322     constexpr uint64_t readBufSize = 4 * 1024 * 1024;
323     std::vector<char> readBuf(readBufSize);
324     uint64_t readSize = 0;
325     fsFile.seekg(0);
326     while ((readSize = std::min(readBufSize, fileSize)) > 0) {
327         fsFile.read(readBuf.data(), readSize);
328         stream_.write(readBuf.data(), readSize);
329 
330         fileSize -= readSize;
331         writeBytes_ += readSize;
332         ++writeCount_;
333     }
334 
335     fsFile.close();
336     return fileSize;
337 }
338 
IsSplitFile(uint32_t size)339 bool TraceFileWriter::IsSplitFile(uint32_t size)
340 {
341     CHECK_TRUE(fd_ != 0, false, "IsSplitFile, nmd-only mode no need to use TraceFileWriter");
342     dataSize_ += sizeof(uint32_t) + size;
343     if (dataSize_ >= splitFileMaxSize_) {
344         PROFILER_LOG_INFO(LOG_CORE, "need to split the file(%s), data size:%d, size: %d, splitFileMaxSize_:%d",
345             path_.c_str(), dataSize_, size, splitFileMaxSize_);
346 
347         // update old file header
348         SetDurationTime();
349         Finish();
350         if (stream_.is_open()) {
351             stream_.close();
352         }
353         fileNum_++;
354 
355         // write header of the new file
356         if (!WriteHeader()) {
357             return false;
358         }
359         SetTimeSource();
360 
361         // write the plugin config of the new file
362         for (size_t i = 0; i < pluginConfigsData_.size(); i++) {
363             Write(pluginConfigsData_[i].data(), pluginConfigsData_[i].size());
364         }
365         Flush();
366         return true;
367     }
368     return false;
369 }
370 
Write(const MessageLite & message)371 long TraceFileWriter::Write(const MessageLite& message)
372 {
373     CHECK_TRUE(fd_ != 0, 0, "Write, nmd-only mode no need to use TraceFileWriter");
374     auto size = message.ByteSizeLong();
375     if (isSplitFile_ && !isStop_) {
376         if (IsSplitFile(size)) {
377             return -1;
378         }
379     }
380 
381     // serialize message to bytes array
382     std::vector<char> msgData(size);
383     CHECK_TRUE(message.SerializeToArray(msgData.data(), msgData.size()), 0, "SerializeToArray failed!");
384 
385     return Write(msgData.data(), msgData.size());
386 }
387 
Finish()388 bool TraceFileWriter::Finish()
389 {
390     CHECK_TRUE(fd_ != 0, false, "Finish(), nmd-only mode no need to use TraceFileWriter");
391     // update header info
392     helper_.Update(header_);
393     SetTimeStamp(); // add timestamp in header
394 
395     if (fd_ != -1) {
396         if (lseek(fd_, 0, SEEK_SET) == -1) {
397             return false;
398         }
399         auto ret = write(fd_, &header_, sizeof(header_));
400         CHECK_TRUE(ret == sizeof(header_), false, "write initial header failed!, error: %s", strerror(errno));
401         CHECK_TRUE(ftruncate(fd_, fileWriteLength_) == 0, false, "ftruncate(%u) failed, error: %s",
402             fileWriteLength_, strerror(errno));
403     } else {
404         long long filePos = stream_.tellp();
405         if (filePos == -1) { // -1 :file not open or error
406             return false;
407         }
408         // move write position to begin of file
409         CHECK_TRUE(stream_.is_open(), false, "binary file %s not open or open failed!", path_.c_str());
410         stream_.seekp(0);
411         CHECK_TRUE(stream_, false, "seek write position to head for %s failed!", path_.c_str());
412 
413         // write final header
414         stream_.write(reinterpret_cast<CharPtr>(&header_), sizeof(header_));
415         stream_.seekp(filePos);
416         CHECK_TRUE(stream_, false, "write final header to %s failed!", path_.c_str());
417         CHECK_TRUE(stream_.flush(), false, "binary file %s flush failed!", path_.c_str());
418         PROFILER_LOG_DEBUG(LOG_CORE, "Finish: %s, bytes: %" PRIu64 ", count: %" PRIu64, path_.c_str(), writeBytes_,
419                    writeCount_);
420     }
421     return true;
422 }
423 
UpdateSaFileHeader()424 bool TraceFileWriter::UpdateSaFileHeader()
425 {
426     CHECK_TRUE(fd_ != 0, false, "Finish(), nmd-only mode no need to use TraceFileWriter");
427     SetDurationTime();
428     // update header info
429     helper_.Update(header_);
430     SetTimeStamp(); // add timestamp in header
431     // get position of file pointer
432     int offsetCur = lseek(fd_, 0, SEEK_CUR);
433     if (offsetCur == -1) {
434         return false;
435     }
436     if (lseek(fd_, 0, SEEK_SET) == -1) {
437         return false;
438     }
439     auto ret = write(fd_, &header_, sizeof(header_));
440     CHECK_TRUE(ret == sizeof(header_), false, "write initial header failed!, error: %s", strerror(errno));
441     CHECK_TRUE(fileMapAddr_ != MAP_FAILED, false, "UpdateSaFileHeader() fileMapAddr not mapped!");
442     // restore
443     if (lseek(fd_, offsetCur, SEEK_SET) == -1) {
444         return false;
445     }
446     if ((msync(fileMapAddr_, mmapFileLength_, MS_SYNC)) == -1) {
447         PROFILER_LOG_INFO(LOG_CORE, "msync failed, error: %s", strerror(errno));
448     }
449     return true;
450 }
451 
Flush()452 bool TraceFileWriter::Flush()
453 {
454     CHECK_TRUE(fd_ != 0, false, "Finish(), nmd-only mode no need to use TraceFileWriter");
455     return FlushStream();
456 }
457 
FlushStream()458 bool TraceFileWriter::FlushStream()
459 {
460     if (fd_ == -1) {
461         CHECK_TRUE(stream_.is_open(), false, "binary file %s not open or open failed!", path_.c_str());
462         CHECK_TRUE(stream_.flush(), false, "binary file %s flush failed!", path_.c_str());
463     }
464     PROFILER_LOG_DEBUG(LOG_CORE, "flush: %s, bytes: %" PRIu64 ", count: %" PRIu64, path_.c_str(),
465                        writeBytes_, writeCount_);
466     return true;
467 }
468 
SetStopSplitFile(bool isStop)469 void TraceFileWriter::SetStopSplitFile(bool isStop)
470 {
471     isStop_ = isStop;
472 }
473 
LogDiskUsage()474 void TraceFileWriter::LogDiskUsage()
475 {
476     std::string diskPath = "/data/local/tmp/";
477     std::string::size_type pos = oldPath_.find_last_of('/');
478     if (pos != std::string::npos) {
479         diskPath = oldPath_.substr(0, pos);
480     }
481 
482     struct statvfs diskInfo;
483     int ret = statvfs(diskPath.c_str(), &diskInfo);
484     if (ret != 0) {
485         std::string errorMsg = COMMON::GetErrorMsg();
486         PROFILER_LOG_ERROR(LOG_CORE, "LogDiskUsage() return %d, path:%s, msg:%s",
487                            ret, diskPath.c_str(), errorMsg.c_str());
488         return;
489     }
490 
491     unsigned long long freeSize = static_cast<unsigned long long>(diskInfo.f_bsize) *
492         static_cast<unsigned long long>(diskInfo.f_bfree);
493     unsigned long long totalSize = static_cast<unsigned long long>(diskInfo.f_bsize) *
494         static_cast<unsigned long long>(diskInfo.f_blocks);
495     float freePercent = 0;
496     if (totalSize != 0) {
497         freePercent = static_cast<float>(freeSize) / static_cast<float>(totalSize);
498     }
499     uint32_t freeSizeGb = freeSize / GB_TO_BYTE;
500     // 100: in terms of percentage
501     PROFILER_LOG_INFO(LOG_CORE, "LogDiskUsage() freePercent:%.1f, freeSizeGb:%u", freePercent * 100, freeSizeGb);
502 }
503 
RemapFile()504 bool TraceFileWriter::RemapFile()
505 {
506     CHECK_TRUE(fileMapAddr_ != MAP_FAILED, false, "RemapFile() fileMapAddr not mapped!");
507     if (munmap(fileMapAddr_, mmapFileLength_) != 0) {
508         PROFILER_LOG_ERROR(LOG_CORE, "munmap file(%zu) failed, error: %s", fileLength_, strerror(errno));
509         return false;
510     }
511 
512     // file size increased by DEFULT_PAGES * pageSize_(32M)
513     size_t newLength = fileLength_ + DEFULT_PAGES * pageSize_;
514     if (fallocate(fd_, 0, fileLength_, DEFULT_PAGES * pageSize_) != 0) {
515         fileMapAddr_ = MAP_FAILED;
516         PROFILER_LOG_ERROR(LOG_CORE, "fallocate file(%zu) failed, error: %s", newLength, strerror(errno));
517         return false;
518     }
519 
520     size_t remapPos = fileWriteLength_ & ~(pageSize_ - 1);
521     if (newLength <= remapPos) {
522         fileMapAddr_ = MAP_FAILED;
523         PROFILER_LOG_ERROR(LOG_CORE, "RemapFile failed, newLength is less than remapPos");
524         return false;
525     }
526     fileMapAddr_ = mmap(nullptr, newLength - remapPos, PROT_WRITE | PROT_READ, MAP_SHARED | MAP_POPULATE,
527                         fd_, remapPos);
528     if (fileMapAddr_ == MAP_FAILED) {
529         PROFILER_LOG_ERROR(LOG_CORE, "remap(%zu:%zu) data file failed, error: %s", newLength, remapPos,
530                            strerror(errno));
531         return false;
532     }
533     mmapFileLength_ = newLength - remapPos;
534     mapOffset_ = fileWriteLength_ - remapPos;
535     fileLength_ = newLength;
536     PROFILER_LOG_INFO(LOG_CORE, "remap(%zu:%zu) data file(%zu) sucess", remapPos, mapOffset_, fileLength_);
537     return true;
538 }
539 
GetMemory(uint32_t size,uint8_t ** memory,uint32_t * offset)540 bool TraceFileWriter::GetMemory(uint32_t size, uint8_t** memory, uint32_t* offset)
541 {
542     if ((fileWriteLength_ + PIECE_HEAD_LEN + messageWriteOffset_ + size) >= fileLength_) {
543         if ((fileLength_ + DEFULT_PAGES * pageSize_) > GB_TO_BYTE) {
544             return false;
545         }
546 
547         if (!RemapFile()) {
548             return false;
549         }
550     }
551     if (fileMapAddr_ == MAP_FAILED) {
552         return false;
553     }
554     *memory = &reinterpret_cast<uint8_t*>(fileMapAddr_)[mapOffset_ + messageWriteOffset_];
555     *offset = messageWriteOffset_;
556     return true;
557 }
558 
Seek(uint32_t offset)559 bool TraceFileWriter::Seek(uint32_t offset)
560 {
561     messageWriteOffset_ = offset;
562     return true;
563 }
564 
FinishReport(int32_t size)565 void TraceFileWriter::FinishReport(int32_t size)
566 {
567     if (fileMapAddr_ == MAP_FAILED) {
568         return;
569     }
570     auto realSize = PIECE_HEAD_LEN + size;
571     CHECK_TRUE(helper_.AddSegment(nullptr, realSize), NO_RETVAL, "AddSegment(%d) failed, error: %s",
572         realSize, strerror(errno));
573 
574     // write data length
575     *(reinterpret_cast<int*>((&reinterpret_cast<uint8_t*>(fileMapAddr_)[mapOffset_]))) = size;
576     mapOffset_ += static_cast<uint64_t>(realSize);
577     fileWriteLength_ += static_cast<uint64_t>(realSize);
578     writeBytes_ += static_cast<uint64_t>(realSize);
579     ++writeCount_;
580 }
581 
ResetPos()582 void TraceFileWriter::ResetPos()
583 {
584     messageWriteOffset_ = PIECE_HEAD_LEN;
585 }