1 /**
2 * Copyright (c) 2021-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 "runtime/profilesaver/profile_dump_info.h"
17
18 #include <sys/file.h>
19 #include <sys/stat.h>
20 #include <sys/uio.h>
21
22 #include <cerrno>
23 #include <climits>
24 #include <cstring>
25
26 #include "libpandabase/os/failure_retry.h"
27 #include "trace/trace.h"
28
29 #ifndef PATH_MAX
30 constexpr uint16_t PATH_MAX = 1024;
31 #endif
32
33 namespace ark {
34 static constexpr size_t K_BITS_PER_BYTE = 8;
35
36 static constexpr size_t K_LINE_HEADER_SIZE = 3 * sizeof(uint32_t) + sizeof(uint16_t);
37 static constexpr size_t K_METHOD_BYTES = 4;
38 static constexpr size_t K_CLASS_BYTES = 4;
39
40 const uint8_t ProfileDumpInfo::kProfileMagic[] = {'p', 'r', 'o', 'f', '\0'}; // NOLINT
41 const uint8_t ProfileDumpInfo::kProfileVersion[] = {'0', '1', '\0'}; // NOLINT
42
43 static constexpr uint16_t K_MAX_FILE_KEY_LENGTH = PATH_MAX; // NOLINT
44
WriteBuffer(int fd,const uint8_t * buffer,size_t byteCount)45 static bool WriteBuffer(int fd, const uint8_t *buffer, size_t byteCount)
46 { // NOLINT
47 while (byteCount > 0) {
48 int bytesWritten = write(fd, buffer, byteCount); // real place to write
49 if (bytesWritten == -1) {
50 return false;
51 }
52 byteCount -= static_cast<size_t>(bytesWritten);
53 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
54 buffer += static_cast<size_t>(bytesWritten);
55 }
56 return true;
57 }
58
AddStringToBuffer(PandaVector<uint8_t> * buffer,const PandaString & value)59 static void AddStringToBuffer(PandaVector<uint8_t> *buffer, const PandaString &value)
60 { // NOLINT
61 buffer->insert(buffer->end(), value.begin(), value.end());
62 }
63
64 template <typename T>
AddUintToBuffer(PandaVector<uint8_t> * buffer,T value)65 static void AddUintToBuffer(PandaVector<uint8_t> *buffer, T value)
66 {
67 for (size_t i = 0; i < sizeof(T); i++) {
68 buffer->push_back((value >> (i * K_BITS_PER_BYTE)) & 0xff); // NOLINT
69 }
70 }
71
72 /*
73 * Tests for EOF by trying to read 1 byte from the descriptor.
74 * Returns:
75 * 0 if the descriptor is at the EOF,
76 * -1 if there was an IO error
77 * 1 if the descriptor has more content to read
78 */
79 // NOLINTNEXTLINE(readability-identifier-naming)
testEOF(int fd)80 static int testEOF(int fd)
81 {
82 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
83 uint8_t buffer[1];
84 return read(fd, buffer, 1);
85 }
86
GetFileSizeBytes(const PandaString & filename)87 int64_t GetFileSizeBytes(const PandaString &filename)
88 {
89 struct stat statBuf {};
90 int rc = stat(filename.c_str(), &statBuf);
91 return (rc == 0) ? statBuf.st_size : -1;
92 }
93
FillFromFd(int fd,const PandaString & source,PandaString * error)94 ProfileDumpInfo::ProfileLoadSatus ProfileDumpInfo::SerializerBuffer::FillFromFd(int fd, const PandaString &source,
95 PandaString *error)
96 {
97 size_t byteCount = ptrEnd_ - ptrCurrent_;
98 uint8_t *buffer = ptrCurrent_;
99 while (byteCount > 0) {
100 int bytesRead = read(fd, buffer, byteCount);
101 if (bytesRead == 0) { // NOLINT
102 *error += "Profile EOF reached prematurely for " + source;
103 return PROFILE_LOAD_BAD_DATA;
104 } else if (bytesRead < 0) { // NOLINT
105 *error += "Profile IO error for " + source + ConvertToString(os::Error(errno).ToString());
106 return PROFILE_LOAD_IO_ERROR;
107 }
108 byteCount -= static_cast<size_t>(bytesRead);
109 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
110 buffer += static_cast<size_t>(bytesRead);
111 }
112 return PROFILE_LOAD_SUCCESS;
113 }
114
115 template <typename T>
ReadUintAndAdvance()116 T ProfileDumpInfo::SerializerBuffer::ReadUintAndAdvance()
117 {
118 static_assert(std::is_unsigned<T>::value, "Type is not unsigned");
119 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
120 ASSERT(ptrCurrent_ + sizeof(T) <= ptrEnd_);
121 T value = 0;
122 for (size_t i = 0; i < sizeof(T); i++) {
123 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
124 value += ptrCurrent_[i] << (i * K_BITS_PER_BYTE);
125 }
126 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
127 ptrCurrent_ += sizeof(T);
128 return value;
129 }
130
CompareAndAdvance(const uint8_t * data,size_t dataSize)131 bool ProfileDumpInfo::SerializerBuffer::CompareAndAdvance(const uint8_t *data, size_t dataSize)
132 {
133 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
134 if (ptrCurrent_ + dataSize > ptrEnd_) {
135 return false;
136 }
137 if (memcmp(ptrCurrent_, data, dataSize) == 0) {
138 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
139 ptrCurrent_ += dataSize;
140 return true;
141 }
142 return false;
143 }
144
MergeWith(const ProfileDumpInfo & other)145 bool ProfileDumpInfo::MergeWith(const ProfileDumpInfo &other)
146 {
147 for (const auto &otherIt : other.dumpInfo_) {
148 auto infoIt = dumpInfo_.find(otherIt.first);
149 if ((infoIt != dumpInfo_.end()) && (infoIt->second.checksum != otherIt.second.checksum)) {
150 LOG(INFO, RUNTIME) << "info_it->second.checksum" << infoIt->second.checksum;
151 LOG(INFO, RUNTIME) << "other_it->second.checksum" << otherIt.second.checksum;
152 LOG(INFO, RUNTIME) << "Checksum mismatch" << otherIt.first;
153 return false;
154 }
155 }
156 LOG(INFO, RUNTIME) << "All checksums match";
157
158 for (const auto &otherIt : other.dumpInfo_) {
159 const PandaString &otherProfileLocation = otherIt.first;
160 const ProfileLineData &otherProfileData = otherIt.second;
161 auto infoIt = dumpInfo_.find(otherProfileLocation);
162 if (infoIt == dumpInfo_.end()) {
163 auto ret =
164 dumpInfo_.insert(std::make_pair(otherProfileLocation, ProfileLineData(otherProfileData.checksum)));
165 ASSERT(ret.second);
166 infoIt = ret.first;
167 }
168 infoIt->second.methodWrapperSet.insert(otherProfileData.methodWrapperSet.begin(),
169 otherProfileData.methodWrapperSet.end());
170 infoIt->second.classWrapperSet.insert(otherProfileData.classWrapperSet.begin(),
171 otherProfileData.classWrapperSet.end());
172 }
173 return true;
174 }
175
AddMethodsAndClasses(const PandaVector<ExtractedMethod> & methods,const PandaSet<ExtractedResolvedClasses> & resolvedClasses)176 bool ProfileDumpInfo::AddMethodsAndClasses(const PandaVector<ExtractedMethod> &methods,
177 const PandaSet<ExtractedResolvedClasses> &resolvedClasses)
178 {
179 for (const ExtractedMethod &method : methods) {
180 if (!AddMethodWrapper(ConvertToString(method.pandaFile->GetFilename()), method.pandaFile->GetHeader()->checksum,
181 MethodWrapper(method.fileId.GetOffset()))) {
182 return false;
183 }
184 }
185
186 for (const ExtractedResolvedClasses &classResolved : resolvedClasses) {
187 if (!AddResolvedClasses(classResolved)) {
188 return false;
189 }
190 }
191 return true;
192 }
193
GetNumberOfMethods() const194 uint64_t ProfileDumpInfo::GetNumberOfMethods() const
195 {
196 uint64_t total = 0;
197 for (const auto &it : dumpInfo_) {
198 total += it.second.methodWrapperSet.size();
199 }
200 return total;
201 }
202
GetNumberOfResolvedClasses() const203 uint64_t ProfileDumpInfo::GetNumberOfResolvedClasses() const
204 {
205 uint64_t total = 0;
206 for (const auto &it : dumpInfo_) {
207 total += it.second.classWrapperSet.size();
208 }
209 return total;
210 }
211
ContainsMethod(const ExtractedMethod & methodRef) const212 bool ProfileDumpInfo::ContainsMethod(const ExtractedMethod &methodRef) const
213 {
214 auto infoIt = dumpInfo_.find(ConvertToString(methodRef.pandaFile->GetFilename()));
215 if (infoIt != dumpInfo_.end()) {
216 if (methodRef.pandaFile->GetHeader()->checksum != infoIt->second.checksum) {
217 return false;
218 }
219 const PandaSet<MethodWrapper> &methods = infoIt->second.methodWrapperSet;
220 return methods.find(MethodWrapper(methodRef.fileId.GetOffset())) != methods.end();
221 }
222 return false;
223 }
224
ContainsClass(const panda_file::File & pandafile,uint32_t classDefIdx) const225 bool ProfileDumpInfo::ContainsClass(const panda_file::File &pandafile, uint32_t classDefIdx) const
226 {
227 auto infoIt = dumpInfo_.find(ConvertToString(pandafile.GetFilename()));
228 if (infoIt != dumpInfo_.end()) {
229 if (pandafile.GetHeader()->checksum != infoIt->second.checksum) {
230 return false;
231 }
232 const PandaSet<ClassWrapper> &classes = infoIt->second.classWrapperSet;
233 return classes.find(ClassWrapper(classDefIdx)) != classes.end();
234 }
235 return false;
236 }
237
AddMethodWrapper(const PandaString & pandaFileLocation,uint32_t checksum,const ProfileDumpInfo::MethodWrapper & methodToAdd)238 bool ProfileDumpInfo::AddMethodWrapper(const PandaString &pandaFileLocation, uint32_t checksum,
239 const ProfileDumpInfo::MethodWrapper &methodToAdd)
240 {
241 ProfileLineData *const data = GetOrAddProfileLineData(pandaFileLocation, checksum);
242 if (data == nullptr) {
243 return false;
244 }
245 data->methodWrapperSet.insert(methodToAdd);
246 return true;
247 }
248
AddClassWrapper(const PandaString & pandaFileLocation,uint32_t checksum,const ProfileDumpInfo::ClassWrapper & classToAdd)249 bool ProfileDumpInfo::AddClassWrapper(const PandaString &pandaFileLocation, uint32_t checksum,
250 const ProfileDumpInfo::ClassWrapper &classToAdd)
251 {
252 ProfileLineData *const data = GetOrAddProfileLineData(pandaFileLocation, checksum);
253 if (data == nullptr) {
254 return false;
255 }
256 data->classWrapperSet.insert(classToAdd);
257 return true;
258 }
259
AddResolvedClasses(const ExtractedResolvedClasses & classes)260 bool ProfileDumpInfo::AddResolvedClasses(const ExtractedResolvedClasses &classes)
261 { // NOLINT(readability-identifier-naming)
262 const PandaString panda_file_location = classes.GetPandaFileLocation(); // NOLINT(readability-identifier-naming)
263 const uint32_t checksum = classes.GetPandaFileChecksum(); // NOLINT(readability-identifier-naming)
264 ProfileLineData *const data = GetOrAddProfileLineData(panda_file_location, checksum);
265 if (data == nullptr) {
266 return false;
267 }
268 for (auto const &i : classes.GetClasses()) {
269 data->classWrapperSet.insert(ClassWrapper(i));
270 }
271 return true;
272 }
273
GetOrAddProfileLineData(const PandaString & pandaFileLocation,uint32_t checksum)274 ProfileDumpInfo::ProfileLineData *ProfileDumpInfo::GetOrAddProfileLineData(const PandaString &pandaFileLocation,
275 uint32_t checksum)
276 {
277 auto infoIt = dumpInfo_.find(pandaFileLocation);
278 if (infoIt == dumpInfo_.end()) {
279 auto ret = dumpInfo_.insert(std::make_pair(pandaFileLocation, ProfileLineData(checksum)));
280 ASSERT(ret.second);
281 infoIt = ret.first;
282 }
283 if (infoIt->second.checksum != checksum) {
284 LOG(INFO, RUNTIME) << "Checksum mismatch" << pandaFileLocation;
285 return nullptr;
286 }
287 return &(infoIt->second);
288 }
289
Save(int fd)290 bool ProfileDumpInfo::Save(int fd)
291 {
292 ASSERT(fd >= 0);
293 trace::ScopedTrace scopedTrace(__PRETTY_FUNCTION__);
294
295 static constexpr size_t K_MAX_BUFFER_SIZE = 8 * 1024;
296 PandaVector<uint8_t> buffer; // each element 1 byte
297
298 WriteBuffer(fd, kProfileMagic, sizeof(kProfileMagic));
299 WriteBuffer(fd, kProfileVersion, sizeof(kProfileVersion));
300 AddUintToBuffer(&buffer, static_cast<uint32_t>(dumpInfo_.size()));
301
302 for (const auto &it : dumpInfo_) {
303 if (buffer.size() > K_MAX_BUFFER_SIZE) {
304 if (!WriteBuffer(fd, buffer.data(), buffer.size())) {
305 return false;
306 }
307 buffer.clear();
308 }
309 const PandaString &fileLocation = it.first;
310 const ProfileLineData &fileData = it.second;
311
312 if (fileLocation.size() >= K_MAX_FILE_KEY_LENGTH) {
313 LOG(INFO, RUNTIME) << "PandaFileKey exceeds allocated limit";
314 return false;
315 }
316
317 size_t requiredCapacity = buffer.size() + K_LINE_HEADER_SIZE + fileLocation.size() +
318 K_METHOD_BYTES * fileData.methodWrapperSet.size() +
319 K_CLASS_BYTES * fileData.classWrapperSet.size();
320 buffer.reserve(requiredCapacity);
321
322 ASSERT(fileLocation.size() <= std::numeric_limits<uint16_t>::max());
323 ASSERT(fileData.methodWrapperSet.size() <= std::numeric_limits<uint32_t>::max());
324 ASSERT(fileData.classWrapperSet.size() <= std::numeric_limits<uint32_t>::max());
325
326 AddUintToBuffer(&buffer, static_cast<uint16_t>(fileLocation.size()));
327 AddUintToBuffer(&buffer, static_cast<uint32_t>(fileData.methodWrapperSet.size()));
328 AddUintToBuffer(&buffer, static_cast<uint32_t>(fileData.classWrapperSet.size()));
329 AddUintToBuffer(&buffer, fileData.checksum);
330 AddStringToBuffer(&buffer, fileLocation);
331
332 if (UNLIKELY(fileData.empty())) {
333 LOG(INFO, RUNTIME) << "EMPTY FILE DATA, WERIED!";
334 }
335
336 for (auto methodIt : fileData.methodWrapperSet) {
337 AddUintToBuffer(&buffer, methodIt.methodId);
338 }
339 for (auto classIt : fileData.classWrapperSet) {
340 AddUintToBuffer(&buffer, classIt.classId);
341 }
342 ASSERT(requiredCapacity == buffer.size());
343 }
344 return WriteBuffer(fd, buffer.data(), buffer.size());
345 }
346
Load(int fd)347 bool ProfileDumpInfo::Load(int fd)
348 {
349 trace::ScopedTrace scopedTrace(__PRETTY_FUNCTION__);
350 PandaString error;
351 ProfileLoadSatus status = LoadInternal(fd, &error);
352 if (status == PROFILE_LOAD_SUCCESS) {
353 return true;
354 }
355 LOG(INFO, RUNTIME) << "Error when reading profile " << error;
356 return false;
357 }
358
LoadInternal(int fd,PandaString * error)359 ProfileDumpInfo::ProfileLoadSatus ProfileDumpInfo::LoadInternal(int fd, PandaString *error)
360 {
361 ASSERT(fd >= 0);
362 trace::ScopedTrace scopedTrace(__PRETTY_FUNCTION__);
363
364 struct stat statBuffer {};
365 if (fstat(fd, &statBuffer) != 0) {
366 return PROFILE_LOAD_IO_ERROR;
367 }
368
369 if (statBuffer.st_size == 0) {
370 LOG(INFO, RUNTIME) << "empty file";
371 return PROFILE_LOAD_EMPTYFILE;
372 }
373
374 uint32_t numberOfLines;
375 ProfileLoadSatus status = ReadProfileHeader(fd, &numberOfLines, error);
376 if (status != PROFILE_LOAD_SUCCESS) {
377 return status;
378 }
379 LOG(INFO, RUNTIME) << "number of profile items = " << numberOfLines;
380
381 while (numberOfLines > 0) {
382 ProfileLineHeader lineHeader;
383 status = ReadProfileLineHeader(fd, &lineHeader, error);
384 if (status != PROFILE_LOAD_SUCCESS) {
385 return status;
386 }
387
388 status = ReadProfileLine(fd, lineHeader, error);
389 if (status != PROFILE_LOAD_SUCCESS) {
390 return status;
391 }
392 numberOfLines--;
393 }
394
395 int result = testEOF(fd);
396 if (result == 0) {
397 return PROFILE_LOAD_SUCCESS;
398 }
399
400 if (result < 0) {
401 return PROFILE_LOAD_IO_ERROR;
402 }
403
404 *error = "Unexpected content in the profile file";
405 return PROFILE_LOAD_BAD_DATA;
406 }
407
ReadProfileHeader(int fd,uint32_t * numberOfLines,PandaString * error)408 ProfileDumpInfo::ProfileLoadSatus ProfileDumpInfo::ReadProfileHeader(int fd, uint32_t *numberOfLines,
409 PandaString *error)
410 {
411 const size_t kMagicVersionSize = sizeof(kProfileMagic) + sizeof(kProfileVersion) + sizeof(uint32_t);
412
413 SerializerBuffer safeBuffer(kMagicVersionSize);
414
415 ProfileLoadSatus status = safeBuffer.FillFromFd(fd, "ReadProfileHeader", error);
416 if (status != PROFILE_LOAD_SUCCESS) {
417 return status;
418 }
419
420 if (!safeBuffer.CompareAndAdvance(kProfileMagic, sizeof(kProfileMagic))) {
421 *error = "Profile missing magic";
422 return PROFILE_LOAD_VERSION_MISMATCH;
423 }
424 if (!safeBuffer.CompareAndAdvance(kProfileVersion, sizeof(kProfileVersion))) {
425 *error = "Profile version mismatch";
426 return PROFILE_LOAD_VERSION_MISMATCH;
427 }
428
429 *numberOfLines = safeBuffer.ReadUintAndAdvance<uint32_t>();
430 return PROFILE_LOAD_SUCCESS;
431 }
432
ReadProfileLineHeader(int fd,ProfileLineHeader * lineHeader,PandaString * error)433 ProfileDumpInfo::ProfileLoadSatus ProfileDumpInfo::ReadProfileLineHeader(int fd, ProfileLineHeader *lineHeader,
434 PandaString *error)
435 {
436 SerializerBuffer headerBuffer(K_LINE_HEADER_SIZE);
437 ProfileLoadSatus status = headerBuffer.FillFromFd(fd, "ReadProfileLineHeader", error);
438 if (status != PROFILE_LOAD_SUCCESS) {
439 return status;
440 }
441
442 auto pandaLocationSize = headerBuffer.ReadUintAndAdvance<uint16_t>(); // max chars in location, 4096 = 2 ^ 12
443 lineHeader->methodSetSize = headerBuffer.ReadUintAndAdvance<uint32_t>();
444 lineHeader->classSetSize = headerBuffer.ReadUintAndAdvance<uint32_t>();
445 lineHeader->checksum = headerBuffer.ReadUintAndAdvance<uint32_t>();
446
447 if (pandaLocationSize == 0 || pandaLocationSize > K_MAX_FILE_KEY_LENGTH) {
448 *error = "PandaFileKey has an invalid size: " + std::to_string(pandaLocationSize);
449 return PROFILE_LOAD_BAD_DATA;
450 }
451
452 SerializerBuffer locationBuffer(pandaLocationSize);
453 // Read the binary data: location string
454 status = locationBuffer.FillFromFd(fd, "ReadProfileLineHeader", error);
455 if (status != PROFILE_LOAD_SUCCESS) {
456 return status;
457 }
458 lineHeader->pandaFileLocation.assign(reinterpret_cast<char *>(locationBuffer.Get()), pandaLocationSize);
459 return PROFILE_LOAD_SUCCESS;
460 }
461
ReadProfileLine(int fd,const ProfileLineHeader & lineHeader,PandaString * error)462 ProfileDumpInfo::ProfileLoadSatus ProfileDumpInfo::ReadProfileLine(int fd, const ProfileLineHeader &lineHeader,
463 PandaString *error)
464 {
465 static constexpr uint32_t K_MAX_NUMBER_OF_ENTRIES_TO_READ = 8000; // ~8 kb
466 uint32_t methodsLeftToRead = lineHeader.methodSetSize;
467 uint32_t classesLeftToRead = lineHeader.classSetSize;
468
469 while ((methodsLeftToRead > 0) || (classesLeftToRead > 0)) {
470 uint32_t methodsToRead = std::min(K_MAX_NUMBER_OF_ENTRIES_TO_READ, methodsLeftToRead);
471 uint32_t maxClassesToRead = K_MAX_NUMBER_OF_ENTRIES_TO_READ - methodsToRead; // >=0
472 uint32_t classesToRead = std::min(maxClassesToRead, classesLeftToRead);
473
474 size_t lineSize = K_METHOD_BYTES * methodsToRead + K_CLASS_BYTES * classesToRead;
475 SerializerBuffer lineBuffer(lineSize);
476
477 ProfileLoadSatus status = lineBuffer.FillFromFd(fd, "ReadProfileLine", error);
478 if (status != PROFILE_LOAD_SUCCESS) {
479 return status;
480 }
481 if (!ProcessLine(lineBuffer, methodsToRead, classesToRead, lineHeader.checksum, lineHeader.pandaFileLocation)) {
482 *error = "Error when reading profile file line";
483 return PROFILE_LOAD_BAD_DATA;
484 }
485
486 methodsLeftToRead -= methodsToRead;
487 classesLeftToRead -= classesToRead;
488 }
489 return PROFILE_LOAD_SUCCESS;
490 }
491
492 // NOLINTNEXTLINE(google-runtime-references)
ProcessLine(SerializerBuffer & lineBuffer,uint32_t methodSetSize,uint32_t classSetSize,uint32_t checksum,const PandaString & pandaFileLocation)493 bool ProfileDumpInfo::ProcessLine(SerializerBuffer &lineBuffer, uint32_t methodSetSize, uint32_t classSetSize,
494 uint32_t checksum, const PandaString &pandaFileLocation)
495 {
496 for (uint32_t i = 0; i < methodSetSize; i++) {
497 // NB! Read the method info from buffer...
498 auto methodIdx = lineBuffer.ReadUintAndAdvance<uint32_t>();
499 if (!AddMethodWrapper(pandaFileLocation, checksum, MethodWrapper(methodIdx))) {
500 return false;
501 }
502 }
503
504 for (uint32_t i = 0; i < classSetSize; i++) {
505 auto classDefIdx = lineBuffer.ReadUintAndAdvance<uint32_t>();
506 if (!AddClassWrapper(pandaFileLocation, checksum, ClassWrapper(classDefIdx))) {
507 return false;
508 }
509 }
510 return true;
511 }
512
Save(const PandaString & filename,uint64_t * bytesWritten,int fd)513 bool ProfileDumpInfo::Save(const PandaString &filename, uint64_t *bytesWritten, int fd)
514 {
515 bool result = Save(fd);
516 if (result) {
517 if (bytesWritten != nullptr) {
518 LOG(INFO, RUNTIME) << " Profile Saver Bingo! and bytes written = " << bytesWritten;
519 *bytesWritten = GetFileSizeBytes(filename);
520 }
521 } else {
522 LOG(ERROR, RUNTIME) << "Failed to save profile info to " << filename;
523 }
524 return result;
525 }
526
MergeAndSave(const PandaString & filename,uint64_t * bytesWritten,bool force)527 bool ProfileDumpInfo::MergeAndSave(const PandaString &filename, uint64_t *bytesWritten, bool force)
528 {
529 // NB! we using READWRITE mode to leave the creation job to framework layer.
530 ark::os::unix::file::File myfile = ark::os::file::Open(filename, ark::os::file::Mode::READWRITE);
531 if (!myfile.IsValid()) {
532 LOG(ERROR, RUNTIME) << "Cannot open the profile file" << filename;
533 return false;
534 }
535 ark::os::file::FileHolder fholder(myfile);
536 int fd = myfile.GetFd();
537
538 LOG(INFO, RUNTIME) << " Step3.2: starting merging ***";
539 PandaString error;
540 ProfileDumpInfo fileDumpInfo;
541 ProfileLoadSatus status = fileDumpInfo.LoadInternal(fd, &error);
542 if (status == PROFILE_LOAD_SUCCESS || status == PROFILE_LOAD_EMPTYFILE) {
543 bool isMergeWith = MergeWith(fileDumpInfo);
544 if (isMergeWith && dumpInfo_ == fileDumpInfo.dumpInfo_) {
545 if (bytesWritten != nullptr) {
546 *bytesWritten = 0;
547 }
548 LOG(INFO, RUNTIME) << " No Saving as no change byte_written = 0";
549 if (status != PROFILE_LOAD_EMPTYFILE) {
550 return true;
551 }
552 } else if (!isMergeWith) {
553 LOG(INFO, RUNTIME) << " No Saving as Could not merge previous profile data from file " << filename;
554 if (!force) {
555 return false;
556 }
557 }
558 } else if (force && ((status == PROFILE_LOAD_VERSION_MISMATCH) || (status == PROFILE_LOAD_BAD_DATA))) {
559 LOG(INFO, RUNTIME) << " Clearing bad or mismatch version profile data from file " << filename << ": " << error;
560 } else {
561 LOG(INFO, RUNTIME) << " No Saving as Could not load profile data from file " << filename << ": " << error;
562 return false;
563 }
564
565 LOG(INFO, RUNTIME) << " Step3.3: starting Saving ***";
566 LOG(INFO, RUNTIME) << " clear file data firstly";
567 if (!myfile.ClearData()) {
568 LOG(INFO, RUNTIME) << "Could not clear profile file: " << filename;
569 return false;
570 }
571
572 return Save(filename, bytesWritten, fd);
573 }
574
575 } // namespace ark
576