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 #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 */
SampleReader(const char * filename)46 inline SampleReader::SampleReader(const char *filename)
47 {
48 {
49 std::ifstream binFile(filename, std::ios::binary | std::ios::ate);
50 if (!binFile) {
51 LOG(FATAL, PROFILER) << "Unable to open file \"" << filename << "\"";
52 UNREACHABLE();
53 }
54 std::streamsize bufferSize = binFile.tellg();
55 binFile.seekg(0, std::ios::beg);
56
57 buffer_.resize(bufferSize);
58
59 if (!binFile.read(buffer_.data(), bufferSize)) {
60 LOG(FATAL, PROFILER) << "Unable to read sampler trace file";
61 UNREACHABLE();
62 }
63 binFile.close();
64 }
65
66 size_t bufferCounter = 0;
67 while (bufferCounter < buffer_.size()) {
68 if (ReadUintptrTBitMisaligned(&buffer_[bufferCounter]) == StreamWriter::MODULE_INDICATOR_VALUE) {
69 // This entry is panda file
70 size_t pfNameSize = ReadUintptrTBitMisaligned(&buffer_[bufferCounter + PANDA_FILE_NAME_SIZE_OFFSET]);
71 size_t nextModulePtrOffset = PANDA_FILE_NAME_OFFSET + pfNameSize * sizeof(char);
72
73 if (bufferCounter + nextModulePtrOffset > buffer_.size()) {
74 LOG(ERROR, PROFILER) << "ark sampling profiler drop last module, because of invalid trace file";
75 return;
76 }
77
78 moduleRowPtrs_.push_back(&buffer_[bufferCounter]);
79 bufferCounter += nextModulePtrOffset;
80 continue;
81 }
82
83 // buffer_counter now is entry of a sample, stack size lies after thread_id
84 size_t stackSize = ReadUintptrTBitMisaligned(&buffer_[bufferCounter + SAMPLE_STACK_SIZE_OFFSET]);
85 if (stackSize > SampleInfo::StackInfo::MAX_STACK_DEPTH) {
86 LOG(FATAL, PROFILER) << "ark sampling profiler trace file is invalid, stack_size > MAX_STACK_DEPTH";
87 UNREACHABLE();
88 }
89
90 size_t nextSamplePtrOffset = SAMPLE_STACK_OFFSET + stackSize * sizeof(SampleInfo::ManagedStackFrameId);
91 if (bufferCounter + nextSamplePtrOffset > buffer_.size()) {
92 LOG(ERROR, PROFILER) << "ark sampling profiler drop last samples, because of invalid trace file";
93 return;
94 }
95
96 sampleRowPtrs_.push_back(&buffer_[bufferCounter]);
97 bufferCounter += nextSamplePtrOffset;
98 }
99
100 if (bufferCounter != buffer_.size()) {
101 LOG(ERROR, PROFILER) << "ark sampling profiler trace file is invalid";
102 }
103 }
104
105 // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic)
GetNextSample(SampleInfo * sampleOut)106 inline bool SampleReader::GetNextSample(SampleInfo *sampleOut)
107 {
108 if (sampleRowPtrs_.size() <= sampleRowCounter_) {
109 return false;
110 }
111 const char *currentSamplePtr = sampleRowPtrs_[sampleRowCounter_];
112 sampleOut->threadInfo.threadId = ReadUint32TBitMisaligned(¤tSamplePtr[SAMPLE_THREAD_ID_OFFSET]);
113 sampleOut->threadInfo.threadStatus =
114 static_cast<SampleInfo::ThreadStatus>(ReadUint32TBitMisaligned(¤tSamplePtr[SAMPLE_THREAD_STATUS_OFFSET]));
115 sampleOut->stackInfo.managedStackSize = ReadUintptrTBitMisaligned(¤tSamplePtr[SAMPLE_STACK_SIZE_OFFSET]);
116
117 ASSERT(sampleOut->stackInfo.managedStackSize <= SampleInfo::StackInfo::MAX_STACK_DEPTH);
118 auto copySize = sampleOut->stackInfo.managedStackSize * sizeof(SampleInfo::ManagedStackFrameId);
119 [[maybe_unused]] int r =
120 memcpy_s(sampleOut->stackInfo.managedStack.data(), copySize, currentSamplePtr + SAMPLE_STACK_OFFSET, copySize);
121 ASSERT(r == 0);
122 ++sampleRowCounter_;
123 return true;
124 }
125
GetNextModule(FileInfo * moduleOut)126 inline bool SampleReader::GetNextModule(FileInfo *moduleOut)
127 {
128 if (moduleRowPtrs_.size() <= moduleRowCounter_) {
129 return false;
130 }
131
132 moduleOut->pathname.clear();
133
134 const char *currentModulePtr = moduleRowPtrs_[moduleRowCounter_];
135 moduleOut->ptr = ReadUintptrTBitMisaligned(¤tModulePtr[PANDA_FILE_POINTER_OFFSET]);
136 moduleOut->checksum = ReadUint32TBitMisaligned(¤tModulePtr[PANDA_FILE_CHECKSUM_OFFSET]);
137 size_t strSize = ReadUintptrTBitMisaligned(¤tModulePtr[PANDA_FILE_NAME_SIZE_OFFSET]);
138 const char *strPtr = ¤tModulePtr[PANDA_FILE_NAME_OFFSET];
139 moduleOut->pathname = std::string(strPtr, strSize);
140
141 ++moduleRowCounter_;
142 return true;
143 }
144 // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
145
146 } // namespace ark::tooling::sampler
147
148 #endif // PANDA_RUNTIME_TOOLING_SAMPLER_SAMPLE_READER_INL_H
149