• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 #include "trace_file_writer.h"
16 
17 #include <cinttypes>
18 #include <memory>
19 
20 #include "logging.h"
21 
22 using CharPtr = std::unique_ptr<char>::pointer;
23 using ConstCharPtr = std::unique_ptr<const char>::pointer;
24 
25 namespace {
26 const int MB_TO_BYTE = 1024 * 1024;
27 const int MIN_BYTE = 200;
28 } // namespace
29 
TraceFileWriter(const std::string & path,bool splitFile,uint32_t singleFileMaxSizeMb)30 TraceFileWriter::TraceFileWriter(const std::string& path, bool splitFile, uint32_t singleFileMaxSizeMb)
31     : path_(path), writeBytes_(0)
32 {
33     isSplitFile_ = splitFile;
34     singleFileMaxSize_ = (singleFileMaxSizeMb < MIN_BYTE) ? (MIN_BYTE * MB_TO_BYTE) :
35         (singleFileMaxSizeMb * MB_TO_BYTE);
36     oldPath_ = path;
37     fileNum_ = 1;
38 
39     WriteHeader();
40     Flush();
41 }
42 
~TraceFileWriter()43 TraceFileWriter::~TraceFileWriter()
44 {
45     Flush();
46     if (stream_.is_open()) {
47         stream_.close();
48     }
49 }
50 
Path() const51 std::string TraceFileWriter::Path() const
52 {
53     return path_;
54 }
55 
SetPluginConfig(const void * data,size_t size)56 bool TraceFileWriter::SetPluginConfig(const void* data, size_t size)
57 {
58     if (isSplitFile_) {
59         std::vector<char> configVec;
60         auto configData = reinterpret_cast<ConstCharPtr>(data);
61         configVec.insert(configVec.end(), configData, configData + size);
62         pluginConfigsData_.push_back(std::move(configVec));
63     }
64 
65     Write(data, size);
66     return true;
67 }
68 
SetTimeStamp()69 void TraceFileWriter::SetTimeStamp()
70 {
71     constexpr uint64_t nanoSeconds = 1000000000;
72     struct timespec ts;
73     clock_gettime(CLOCK_BOOTTIME, &ts);
74     header_.data_.boottime = static_cast<uint64_t>(ts.tv_sec) * nanoSeconds +
75         static_cast<uint64_t>(ts.tv_nsec);
76     clock_gettime(CLOCK_REALTIME, &ts);
77     header_.data_.realtime = static_cast<uint64_t>(ts.tv_sec) * nanoSeconds +
78         static_cast<uint64_t>(ts.tv_nsec);
79     clock_gettime(CLOCK_REALTIME_COARSE, &ts);
80     header_.data_.realtimeCoarse = static_cast<uint64_t>(ts.tv_sec) * nanoSeconds +
81         static_cast<uint64_t>(ts.tv_nsec);
82     clock_gettime(CLOCK_MONOTONIC, &ts);
83     header_.data_.monotonic = static_cast<uint64_t>(ts.tv_sec) * nanoSeconds +
84         static_cast<uint64_t>(ts.tv_nsec);
85     clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
86     header_.data_.monotonicCoarse = static_cast<uint64_t>(ts.tv_sec) * nanoSeconds +
87         static_cast<uint64_t>(ts.tv_nsec);
88     clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
89     header_.data_.monotonicRaw = static_cast<uint64_t>(ts.tv_sec) * nanoSeconds +
90         static_cast<uint64_t>(ts.tv_nsec);
91 }
92 
GetCurrentTime()93 static std::string GetCurrentTime()
94 {
95     const int usMs = 1000;
96     struct timeval tv;
97     gettimeofday(&tv, NULL);
98     return std::to_string(tv.tv_sec * usMs + tv.tv_usec / usMs);
99 }
100 
WriteHeader()101 bool TraceFileWriter::WriteHeader()
102 {
103     if (isSplitFile_) {
104         std::string timeStr = GetCurrentTime();
105         int pos = static_cast<int>(oldPath_.find_last_of('.'));
106         if (pos != 0) {
107             path_ = oldPath_.substr(0, pos) + "_" + timeStr + "_" + std::to_string(fileNum_) +
108                 oldPath_.substr(pos, oldPath_.size());
109         } else {
110             path_ = oldPath_ + "_" + timeStr + "_" + std::to_string(fileNum_);
111         }
112     }
113 
114     stream_.open(path_, std::ios_base::out | std::ios_base::binary);
115     CHECK_TRUE(stream_.is_open(), false, "open %s failed, %d!", path_.c_str(), errno);
116 
117     // write initial header, makes file write position move forward
118     helper_ = {};
119     header_ = {};
120     stream_.write(reinterpret_cast<CharPtr>(&header_), sizeof(header_));
121     CHECK_TRUE(stream_, false, "write initial header to %s failed!", path_.c_str());
122     dataSize_ = header_.HEADER_SIZE;
123     HILOG_INFO(LOG_CORE, "write file(%s) header end", path_.c_str());
124     return true;
125 }
126 
Write(const void * data,size_t size)127 long TraceFileWriter::Write(const void* data, size_t size)
128 {
129     uint32_t dataLen = size;
130     CHECK_TRUE(stream_.is_open(), 0, "binary file %s not open or open failed!", path_.c_str());
131 
132     // write 4B data length.
133     stream_.write(reinterpret_cast<CharPtr>(&dataLen), sizeof(dataLen));
134     CHECK_TRUE(stream_, 0, "binary file %s write raw buffer size failed!", path_.c_str());
135     CHECK_TRUE(helper_.AddSegment(reinterpret_cast<uint8_t*>(&dataLen), sizeof(dataLen)),
136         0, "Add payload for size %u FAILED!", dataLen);
137 
138     // write data bytes
139     stream_.write(reinterpret_cast<ConstCharPtr>(data), size);
140     CHECK_TRUE(stream_, 0, "binary file %s write raw buffer data failed!", path_.c_str());
141     CHECK_TRUE(helper_.AddSegment(reinterpret_cast<uint8_t*>(const_cast<void*>(data)), size),
142         0, "Add payload for data bytes %zu FAILED!", size);
143 
144     long nbytes = sizeof(dataLen) + size;
145     writeBytes_ += nbytes;
146     ++writeCount_;
147     return nbytes;
148 }
149 
IsSplitFile(uint32_t size)150 bool TraceFileWriter::IsSplitFile(uint32_t size)
151 {
152     dataSize_ += sizeof(uint32_t) + size;
153     if (dataSize_ >= singleFileMaxSize_) {
154         HILOG_INFO(LOG_CORE, "need to split the file(%s), data size:%d, size: %d, singleFileMaxSize_:%d",
155             path_.c_str(), dataSize_, size, singleFileMaxSize_);
156 
157         // update old file header
158         Finish();
159         if (stream_.is_open()) {
160             stream_.close();
161         }
162         fileNum_++;
163 
164         // write header of the new file
165         WriteHeader();
166         // write the plugin config of the new file
167         for (size_t i = 0; i < pluginConfigsData_.size(); i++) {
168             Write(pluginConfigsData_[i].data(), pluginConfigsData_[i].size());
169         }
170         Flush();
171         return true;
172     }
173     return false;
174 }
175 
Write(const MessageLite & message)176 long TraceFileWriter::Write(const MessageLite& message)
177 {
178     auto size = message.ByteSizeLong();
179     if (isSplitFile_ && !isStop_) {
180         if (IsSplitFile(size)) {
181             return -1;
182         }
183     }
184 
185     // serialize message to bytes array
186     std::vector<char> msgData(size);
187     CHECK_TRUE(message.SerializeToArray(msgData.data(), msgData.size()), 0, "SerializeToArray failed!");
188 
189     return Write(msgData.data(), msgData.size());
190 }
191 
Finish()192 bool TraceFileWriter::Finish()
193 {
194     // update header info
195     helper_.Update(header_);
196 
197     // move write position to begin of file
198     CHECK_TRUE(stream_.is_open(), false, "binary file %s not open or open failed!", path_.c_str());
199     stream_.seekp(0);
200     CHECK_TRUE(stream_, false, "seek write position to head for %s failed!", path_.c_str());
201 
202     SetTimeStamp(); // add timestamp in header
203 
204     // write final header
205     stream_.write(reinterpret_cast<CharPtr>(&header_), sizeof(header_));
206     CHECK_TRUE(stream_, false, "write final header to %s failed!", path_.c_str());
207     CHECK_TRUE(stream_.flush(), false, "binary file %s flush failed!", path_.c_str());
208     return true;
209 }
210 
Flush()211 bool TraceFileWriter::Flush()
212 {
213     CHECK_TRUE(stream_.is_open(), false, "binary file %s not open or open failed!", path_.c_str());
214     CHECK_TRUE(stream_.flush(), false, "binary file %s flush failed!", path_.c_str());
215     HILOG_INFO(LOG_CORE, "flush: %s, bytes: %" PRIu64 ", count: %" PRIu64, path_.c_str(), writeBytes_, writeCount_);
216     return true;
217 }
218 
SetStopSplitFile(bool isStop)219 void TraceFileWriter::SetStopSplitFile(bool isStop)
220 {
221     isStop_ = isStop;
222 }