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 }