1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
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 "ffrt_profiler_handle.h"
17
18 namespace {
19 constexpr uint8_t FLUSH_INTERVAL = 10;
20 }
21
22 namespace OHOS::Developtools::Profiler {
FfrtProfilerHandle(uint32_t bufferSize,bool isProtobufSerialize)23 FfrtProfilerHandle::FfrtProfilerHandle(uint32_t bufferSize, bool isProtobufSerialize)
24 : isProtobufSerialize_(isProtobufSerialize), bufferSize_(bufferSize)
25 {
26 if (isProtobufSerialize_) {
27 buffer_ = std::make_unique<uint8_t[]>(bufferSize);
28 }
29 }
30
~FfrtProfilerHandle()31 FfrtProfilerHandle::~FfrtProfilerHandle()
32 {
33 std::visit([&](auto& protoData) {
34 FlushData(protoData);
35 }, protoData_);
36 }
37
SetWriter(const std::shared_ptr<Writer> & writer)38 void FfrtProfilerHandle::SetWriter(const std::shared_ptr<Writer>& writer)
39 {
40 writer_ = writer;
41 protoData_ = ::FfrtProfilerResult();
42 }
43
SetWriter(const WriterStructPtr & writer)44 void FfrtProfilerHandle::SetWriter(const WriterStructPtr& writer)
45 {
46 writerStruct_ = writer;
47 auto ctx = writerStruct_->startReport(writerStruct_);
48 if (ctx == nullptr) {
49 PROFILER_LOG_ERROR(LOG_CORE, "%s: get RandomWriteCtx FAILED!", __func__);
50 return;
51 }
52 protoData_ = ProtoEncoder::FfrtProfilerResult(ctx);
53 }
54
SerializeData(const int8_t data[],uint32_t size)55 void FfrtProfilerHandle::SerializeData(const int8_t data[], uint32_t size)
56 {
57 std::visit([&](auto& protoData) {
58 if (size < sizeof(FfrtResultBase)) {
59 PROFILER_LOG_ERROR(LOG_CORE, "%s the size=%d is too small", __FUNCTION__, size);
60 return;
61 }
62 SerializeDataImpl(protoData, data, size);
63 FlushCheck(protoData);
64 }, protoData_);
65 }
66
67 template <typename T>
SerializeDataImpl(T & protoData,const int8_t data[],uint32_t size)68 void FfrtProfilerHandle::SerializeDataImpl(T& protoData, const int8_t data[], uint32_t size)
69 {
70 if (size < sizeof(FfrtResultBase)) {
71 PROFILER_LOG_ERROR(LOG_CORE, "%s the size=%d is too small", __FUNCTION__, size);
72 return;
73 }
74 FfrtResultBase* baseData = reinterpret_cast<FfrtResultBase*>(const_cast<int8_t*>(data));
75 if (baseData->type == static_cast<int32_t>(EventType::INVALID)) {
76 PROFILER_LOG_ERROR(LOG_CORE, "%s type is invalid", __FUNCTION__);
77 return;
78 }
79 ReportCommonData(protoData, baseData);
80 if (baseData->type == TRACE_DATA) {
81 SerializeTraceData(protoData, data, size);
82 } else {
83 SerializeRawData(protoData, data, size);
84 }
85 }
86
87 template <typename T>
ReportCommonData(T & protoData,FfrtResultBase * base)88 void FfrtProfilerHandle::ReportCommonData(T& protoData, FfrtResultBase* base)
89 {
90 if (base == nullptr || strlen(base->threadName) == 0) {
91 return;
92 }
93 FlushData(protoData);
94 auto baseDataProto = protoData.add_ffrt_event();
95 SerializeBaseData(baseDataProto, reinterpret_cast<const int8_t*>(base));
96
97 if (reportProcessName_) {
98 baseDataProto->set_process_name(processName_.c_str(), processName_.size());
99 reportProcessName_ = false;
100 }
101
102 baseDataProto->set_thread_name(base->threadName, strlen(base->threadName));
103 FlushData(protoData);
104 }
105
106 template <typename T>
SerializeBaseData(T & baseDataProto,const int8_t * data)107 void FfrtProfilerHandle::SerializeBaseData(T& baseDataProto, const int8_t* data)
108 {
109 FfrtResultBase* baseData = reinterpret_cast<FfrtResultBase*>(const_cast<int8_t*>(data));
110
111 baseDataProto->set_tv_sec(baseData->ts.tv_sec);
112 baseDataProto->set_tv_nsec(baseData->ts.tv_nsec);
113 baseDataProto->set_pid(pid_);
114 baseDataProto->set_tid(baseData->tid);
115 }
116
117 template <typename T>
SerializeTraceData(T & protoData,const int8_t data[],uint32_t size)118 void FfrtProfilerHandle::SerializeTraceData(T& protoData, const int8_t data[], uint32_t size)
119 {
120 FfrtTraceEvent* traceData = reinterpret_cast<FfrtTraceEvent*>(const_cast<int8_t*>(data));
121 auto ffrtEvent = protoData.add_ffrt_event();
122 SerializeBaseData(ffrtEvent, data);
123
124 auto trace = ffrtEvent->mutable_trace();
125 trace->set_cpu(traceData->cpu);
126 trace->set_trace_type(static_cast<const void*>(&(traceData->traceType)), 1);
127 trace->set_cookie(traceData->cookie);
128
129 size_t traceDataSize = sizeof(FfrtTraceEvent);
130 if (size > traceDataSize) {
131 trace->set_label(data + traceDataSize, strlen(reinterpret_cast<const char*>(data + traceDataSize)));
132 }
133 }
134
135 template <typename T>
SerializeRawData(T & protoData,const int8_t data[],uint32_t size)136 void FfrtProfilerHandle::SerializeRawData(T& protoData, const int8_t data[], uint32_t size)
137 {
138 FfrtResultBase* baseData = reinterpret_cast<FfrtResultBase*>(const_cast<int8_t*>(data));
139 auto ffrtEvent = protoData.add_ffrt_event();
140 SerializeBaseData(ffrtEvent, data);
141
142 size_t baseDataSize = sizeof(FfrtResultBase);
143 if (size > baseDataSize) {
144 auto rawEvent = ffrtEvent->mutable_raw();
145 rawEvent->set_type(baseData->type);
146 rawEvent->set_payload(data + baseDataSize, size - baseDataSize);
147 }
148 }
149
150 template <typename T>
FlushCheck(T & protoData)151 void FfrtProfilerHandle::FlushCheck(T& protoData)
152 {
153 if ((++flushCount_ & FLUSH_INTERVAL) != 0) {
154 return;
155 }
156 FlushData(protoData);
157 }
158
FlushData(::FfrtProfilerResult & data)159 void FfrtProfilerHandle::FlushData(::FfrtProfilerResult& data)
160 {
161 size_t length = data.ByteSizeLong();
162 if (length < bufferSize_) {
163 data.SerializeToArray(buffer_.get(), length);
164 if (buffer_.get() == nullptr) {
165 PROFILER_LOG_ERROR(LOG_CORE, "Flush src is nullptr");
166 return;
167 }
168
169 if (writer_ == nullptr) {
170 PROFILER_LOG_ERROR(LOG_CORE, "Flush writer_ is nullptr");
171 return;
172 }
173 writer_->Write(buffer_.get(), length);
174 writer_->Flush();
175 std::get<::FfrtProfilerResult>(protoData_).clear_ffrt_event();
176 }
177 }
178
FlushData(ProtoEncoder::FfrtProfilerResult & data)179 void FfrtProfilerHandle::FlushData(ProtoEncoder::FfrtProfilerResult& data)
180 {
181 if (data.Size() == 0) {
182 return;
183 }
184
185 int messageLen = data.Finish();
186
187 RandomWriteCtx* ctx = nullptr;
188 writerStruct_->finishReport(writerStruct_, messageLen);
189 writerStruct_->flush(writerStruct_);
190 ctx = writerStruct_->startReport(writerStruct_);
191 if (ctx == nullptr) {
192 PROFILER_LOG_ERROR(LOG_CORE, "%s: get RandomWriteCtx FAILED!", __func__);
193 return;
194 }
195 protoData_ = ProtoEncoder::FfrtProfilerResult(ctx);
196 }
197 }