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