• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
16 #ifndef PANDA_RUNTIME_TOOLING_SAMPLER_SAMPLE_WRITER_H
17 #define PANDA_RUNTIME_TOOLING_SAMPLER_SAMPLE_WRITER_H
18 
19 #include <iostream>
20 #include <string>
21 #include <fstream>
22 
23 #include "libpandabase/os/thread.h"
24 
25 #include "runtime/tooling/sampler/sample_info.h"
26 #include "runtime/tooling/sampler/samples_record.h"
27 
28 #include <unordered_set>
29 
30 namespace ark::tooling::sampler {
31 
32 class StreamWriter {
33 public:
34     StreamWriter() = default;
35     virtual ~StreamWriter() = default;
36     NO_COPY_SEMANTIC(StreamWriter);
37     NO_MOVE_SEMANTIC(StreamWriter);
38 
39     virtual void WriteModule(const FileInfo &moduleInfo) = 0;
40     virtual void WriteSample(const SampleInfo &sample) const = 0;
41     virtual bool IsModuleWritten(const FileInfo &moduleInfo) const = 0;
42 };
43 
44 /*
45  * =======================================================
46  * =============  Sampler binary format ==================
47  * =======================================================
48  *
49  * Writing with the fasters and more convenient format .aspt
50  * Then it should be converted to flamegraph
51  *
52  * .aspt - ark sampling profiler trace file, binary format
53  *
54  * .aspt consists of 2 type information:
55  *   - module row (panda file and its pointer)
56  *   - sample row (sample information)
57  *
58  * module row for 64-bits:
59  *   first 8 byte is 0xFFFFFFFF (to recognize that it's not a sample row)
60  *   next 8 byte is pointer module
61  *   next 8 byte is size of panda file name
62  *   next bytes is panda file name in ASCII symbols
63  *
64  * sample row for 64-bits:
65  *   first 4 bytes is thread id of thread from sample was obtained
66  *   next 4 bytes is thread status of thread from sample was obtained
67  *   next 8 bytes is stack size
68  *   next bytes is stack frame
69  *   one stack frame is panda file ptr and file id
70  *
71  * Example for 64-bit architecture:
72  *
73  *            Thread id   Thread status    Stack Size      Managed stack frame id
74  * Sample row |___________|___________|________________|_____________------___________|
75  *              32 bits      32 bits        64 bits       (128 * <stack size>) bits
76  *
77  *              0xFF..FF    pointer   checksum   name size     module path (ASCII str)
78  * Module row |__________|__________|__________|___________|_____________------___________|
79  *              64 bits    64 bits    32 bits    64 bits       (8 * <name size>) bits
80  */
81 class FileStreamWriter final : public StreamWriter {
82 public:
FileStreamWriter(const std::string & filename)83     explicit FileStreamWriter(const std::string &filename)
84     {
85         /*
86          * This class instance should be used only from one thread
87          * It may lead to format invalidation
88          * This class wasn't made thread safe for performance reason
89          */
90         std::string finalFileName;
91         if (filename.empty()) {
92             std::time_t currentTime = std::time(nullptr);
93             std::tm *localTime = std::localtime(&currentTime);
94             finalFileName = std::to_string(localTime->tm_hour) + "-" + std::to_string(localTime->tm_min) + "-" +
95                             std::to_string(localTime->tm_sec) + ".aspt";
96         } else {
97             finalFileName = filename;
98         }
99         writeStreamPtr_ = std::make_unique<std::ofstream>(finalFileName.c_str(), std::ios::binary);
100         ASSERT(writeStreamPtr_ != nullptr);
101     }
102 
~FileStreamWriter()103     ~FileStreamWriter() override
104     {
105         if (writeStreamPtr_ && writeStreamPtr_->is_open()) {
106             writeStreamPtr_->flush();
107         }
108     };
109 
110     PANDA_PUBLIC_API void WriteModule(const FileInfo &moduleInfo) override;
111     PANDA_PUBLIC_API void WriteSample(const SampleInfo &sample) const override;
112 
IsModuleWritten(const FileInfo & moduleInfo)113     bool IsModuleWritten(const FileInfo &moduleInfo) const override
114     {
115         return writtenModules_.find(moduleInfo) != writtenModules_.end();
116     }
117 
118     NO_COPY_SEMANTIC(FileStreamWriter);
119     NO_MOVE_SEMANTIC(FileStreamWriter);
120 
121     static constexpr uintptr_t MODULE_INDICATOR_VALUE = 0xFFFFFFFF;
122 
123 private:
124     std::unique_ptr<std::ofstream> writeStreamPtr_;
125     std::unordered_set<FileInfo> writtenModules_;
126 };
127 
128 class InspectorStreamWriter final : public StreamWriter {
129 public:
InspectorStreamWriter(std::shared_ptr<SamplesRecord> samplesRecord)130     explicit InspectorStreamWriter(std::shared_ptr<SamplesRecord> samplesRecord)
131         : samplesRecord_(std::move(samplesRecord))
132     {
133     }
~InspectorStreamWriter()134     ~InspectorStreamWriter() override
135     {
136         samplesRecord_.reset();
137     }
WriteModule(const FileInfo & moduleInfo)138     PANDA_PUBLIC_API void WriteModule(const FileInfo &moduleInfo) override
139     {
140         UNUSED_VAR(moduleInfo);
141     }
WriteSample(const SampleInfo & sample)142     PANDA_PUBLIC_API void WriteSample(const SampleInfo &sample) const override
143     {
144         samplesRecord_->AddSampleInfo(sample.threadInfo.threadId, std::make_unique<SampleInfo>(sample));
145     }
IsModuleWritten(const FileInfo & moduleInfo)146     bool IsModuleWritten(const FileInfo &moduleInfo) const override
147     {
148         UNUSED_VAR(moduleInfo);
149         return true;
150     }
151     NO_COPY_SEMANTIC(InspectorStreamWriter);
152     NO_MOVE_SEMANTIC(InspectorStreamWriter);
153 
154 private:
155     std::shared_ptr<SamplesRecord> samplesRecord_ = nullptr;
156 };
157 
158 }  // namespace ark::tooling::sampler
159 
160 #endif  // PANDA_RUNTIME_TOOLING_SAMPLER_SAMPLE_WRITER_H
161