1 /**
2 * Copyright (c) 2021-2025 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 #ifndef PANDA_RUNTIME_TOOLING_SAMPLER_SAMPLE_READER_INL_H
16 #define PANDA_RUNTIME_TOOLING_SAMPLER_SAMPLE_READER_INL_H
17
18 #include <iostream>
19 #include <securec.h>
20 #include <string>
21
22 #include "libpandabase/utils/logger.h"
23
24 #include "runtime/tooling/sampler/sample_info.h"
25 #include "runtime/tooling/sampler/sample_reader.h"
26 #include "runtime/tooling/sampler/sample_writer.h"
27
28 namespace ark::tooling::sampler {
29
30 // -------------------------------------------------
31 // ------------- Format reader ---------------------
32 // -------------------------------------------------
33
34 /*
35 * Example for 64 bit architecture
36 *
37 * Thread id Thread status Stack Size Managed stack frame id
38 * Sample row |___________|______________|________________|_____________------___________|
39 * 32 bits 32 bits 64 bits (128 * <stack size>) bits
40 *
41 *
42 * 0xFF..FF pointer checksum name size module path (ASCII str)
43 * Module row |__________|__________|__________|___________|_____________------___________|
44 * 64 bits 64 bits 32 bits 64 bits (8 * <name size>) bits
45 */
46
47 // CC-OFFNXT(G.FUD.06) Splitting this function will degrade readability. Keyword "inline" needs to satisfy ODR rule.
SampleReader(const char * filename)48 inline SampleReader::SampleReader(const char *filename)
49 {
50 {
51 std::ifstream binFile(filename, std::ios::binary | std::ios::ate);
52 if (!binFile) {
53 LOG(FATAL, PROFILER) << "Unable to open file \"" << filename << "\"";
54 UNREACHABLE();
55 }
56 std::streamsize bufferSize = binFile.tellg();
57 binFile.seekg(0, std::ios::beg);
58
59 buffer_.resize(bufferSize);
60
61 if (!binFile.read(buffer_.data(), bufferSize)) {
62 LOG(FATAL, PROFILER) << "Unable to read sampler trace file";
63 UNREACHABLE();
64 }
65 binFile.close();
66 }
67
68 size_t bufferCounter = 0;
69 while (bufferCounter < buffer_.size()) {
70 if (ReadUintptrTBitMisaligned(&buffer_[bufferCounter]) == FileStreamWriter::MODULE_INDICATOR_VALUE) {
71 // This entry is panda file
72 size_t pfNameSize = ReadUintptrTBitMisaligned(&buffer_[bufferCounter + PANDA_FILE_NAME_SIZE_OFFSET]);
73 size_t nextModulePtrOffset = PANDA_FILE_NAME_OFFSET + pfNameSize * sizeof(char);
74
75 if (bufferCounter + nextModulePtrOffset > buffer_.size()) {
76 LOG(ERROR, PROFILER) << "ark sampling profiler drop last module, because of invalid trace file";
77 return;
78 }
79
80 moduleRowPtrs_.push_back(&buffer_[bufferCounter]);
81 bufferCounter += nextModulePtrOffset;
82 continue;
83 }
84
85 // buffer_counter now is entry of a sample, stack size lies after thread_id
86 size_t stackSize = ReadUintptrTBitMisaligned(&buffer_[bufferCounter + SAMPLE_STACK_SIZE_OFFSET]);
87 if (stackSize > SampleInfo::StackInfo::MAX_STACK_DEPTH) {
88 LOG(FATAL, PROFILER) << "ark sampling profiler trace file is invalid, stack_size > MAX_STACK_DEPTH";
89 UNREACHABLE();
90 }
91
92 size_t nextSamplePtrOffset = SAMPLE_STACK_OFFSET + stackSize * sizeof(SampleInfo::ManagedStackFrameId);
93 if (bufferCounter + nextSamplePtrOffset > buffer_.size()) {
94 LOG(ERROR, PROFILER) << "ark sampling profiler drop last samples, because of invalid trace file";
95 return;
96 }
97
98 sampleRowPtrs_.push_back(&buffer_[bufferCounter]);
99 bufferCounter += nextSamplePtrOffset;
100 }
101
102 if (bufferCounter != buffer_.size()) {
103 LOG(ERROR, PROFILER) << "ark sampling profiler trace file is invalid";
104 }
105 }
106
107 // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic)
108 // CC-OFFNXT(G.FUD.06) Splitting this function will degrade readability. Keyword "inline" needs to satisfy ODR rule.
GetNextSample(SampleInfo * sampleOut)109 inline bool SampleReader::GetNextSample(SampleInfo *sampleOut)
110 {
111 if (sampleRowPtrs_.size() <= sampleRowCounter_) {
112 return false;
113 }
114 const char *currentSamplePtr = sampleRowPtrs_[sampleRowCounter_];
115 sampleOut->threadInfo.threadId = ReadUint32TBitMisaligned(¤tSamplePtr[SAMPLE_THREAD_ID_OFFSET]);
116 sampleOut->threadInfo.threadStatus =
117 static_cast<SampleInfo::ThreadStatus>(ReadUint32TBitMisaligned(¤tSamplePtr[SAMPLE_THREAD_STATUS_OFFSET]));
118 sampleOut->stackInfo.managedStackSize = ReadUintptrTBitMisaligned(¤tSamplePtr[SAMPLE_STACK_SIZE_OFFSET]);
119
120 ASSERT(sampleOut->stackInfo.managedStackSize <= SampleInfo::StackInfo::MAX_STACK_DEPTH);
121 auto copySize = sampleOut->stackInfo.managedStackSize * sizeof(SampleInfo::ManagedStackFrameId);
122 [[maybe_unused]] int r =
123 memcpy_s(sampleOut->stackInfo.managedStack.data(), copySize, currentSamplePtr + SAMPLE_STACK_OFFSET, copySize);
124 ASSERT(r == 0);
125 ++sampleRowCounter_;
126 return true;
127 }
128
129 // CC-OFFNXT(G.FUD.06) Splitting this function will degrade readability. Keyword "inline" needs to satisfy ODR rule.
GetNextModule(FileInfo * moduleOut)130 inline bool SampleReader::GetNextModule(FileInfo *moduleOut)
131 {
132 if (moduleRowPtrs_.size() <= moduleRowCounter_) {
133 return false;
134 }
135
136 moduleOut->pathname.clear();
137
138 const char *currentModulePtr = moduleRowPtrs_[moduleRowCounter_];
139 moduleOut->ptr = ReadUintptrTBitMisaligned(¤tModulePtr[PANDA_FILE_POINTER_OFFSET]);
140 moduleOut->checksum = ReadUint32TBitMisaligned(¤tModulePtr[PANDA_FILE_CHECKSUM_OFFSET]);
141 size_t strSize = ReadUintptrTBitMisaligned(¤tModulePtr[PANDA_FILE_NAME_SIZE_OFFSET]);
142 const char *strPtr = ¤tModulePtr[PANDA_FILE_NAME_OFFSET];
143 moduleOut->pathname = std::string(strPtr, strSize);
144
145 ++moduleRowCounter_;
146 return true;
147 }
148 // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
149
150 } // namespace ark::tooling::sampler
151
152 #endif // PANDA_RUNTIME_TOOLING_SAMPLER_SAMPLE_READER_INL_H
153