1 /*
2 * Copyright (c) 2022 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 "agent/tracing_impl.h"
17
18 #include "tooling/base/pt_events.h"
19 #include "protocol_channel.h"
20
21 #include "ecmascript/napi/include/dfx_jsnapi.h"
22
23 namespace panda::ecmascript::tooling {
Dispatch(const DispatchRequest & request)24 void TracingImpl::DispatcherImpl::Dispatch(const DispatchRequest &request)
25 {
26 static std::unordered_map<std::string, AgentHandler> dispatcherTable {
27 { "end", &TracingImpl::DispatcherImpl::End },
28 { "getCategories", &TracingImpl::DispatcherImpl::GetCategories },
29 { "recordClockSyncMarker", &TracingImpl::DispatcherImpl::RecordClockSyncMarker },
30 { "requestMemoryDump", &TracingImpl::DispatcherImpl::RequestMemoryDump },
31 { "start", &TracingImpl::DispatcherImpl::Start }
32 };
33
34 const std::string &method = request.GetMethod();
35 LOG_DEBUGGER(DEBUG) << "dispatch [" << method << "] to TracingImpl";
36 auto entry = dispatcherTable.find(method);
37 if (entry != dispatcherTable.end() && entry->second != nullptr) {
38 (this->*(entry->second))(request);
39 } else {
40 SendResponse(request, DispatchResponse::Fail("Unknown method: " + method));
41 }
42 }
43
End(const DispatchRequest & request)44 void TracingImpl::DispatcherImpl::End(const DispatchRequest &request)
45 {
46 auto traceEvents = tracing_->End();
47 if (traceEvents == nullptr) {
48 LOG_DEBUGGER(ERROR) << "Transfer DFXJSNApi::StopTracing is failure";
49 SendResponse(request, DispatchResponse::Fail("Stop is failure"));
50 return;
51 }
52 SendResponse(request, DispatchResponse::Ok());
53
54 tracing_->frontend_.DataCollected(std::move(traceEvents));
55 tracing_->frontend_.TracingComplete();
56 }
57
GetCategories(const DispatchRequest & request)58 void TracingImpl::DispatcherImpl::GetCategories(const DispatchRequest &request)
59 {
60 std::vector<std::string> categories;
61 DispatchResponse response = tracing_->GetCategories(categories);
62 SendResponse(request, response);
63 }
64
RecordClockSyncMarker(const DispatchRequest & request)65 void TracingImpl::DispatcherImpl::RecordClockSyncMarker(const DispatchRequest &request)
66 {
67 std::string syncId;
68 DispatchResponse response = tracing_->RecordClockSyncMarker(syncId);
69 SendResponse(request, response);
70 }
71
RequestMemoryDump(const DispatchRequest & request)72 void TracingImpl::DispatcherImpl::RequestMemoryDump(const DispatchRequest &request)
73 {
74 std::unique_ptr<RequestMemoryDumpParams> params =
75 RequestMemoryDumpParams::Create(request.GetParams());
76 std::string dumpGuid;
77 bool success = false;
78 DispatchResponse response = tracing_->RequestMemoryDump(std::move(params), dumpGuid, success);
79 SendResponse(request, response);
80 }
81
Start(const DispatchRequest & request)82 void TracingImpl::DispatcherImpl::Start(const DispatchRequest &request)
83 {
84 std::unique_ptr<StartParams> params =
85 StartParams::Create(request.GetParams());
86 DispatchResponse response = tracing_->Start(std::move(params));
87 SendResponse(request, response);
88 }
89
AllowNotify() const90 bool TracingImpl::Frontend::AllowNotify() const
91 {
92 return channel_ != nullptr;
93 }
94
BufferUsage(double percentFull,int32_t eventCount,double value)95 void TracingImpl::Frontend::BufferUsage(double percentFull, int32_t eventCount, double value)
96 {
97 if (!AllowNotify()) {
98 return;
99 }
100
101 tooling::BufferUsage bufferUsage;
102 bufferUsage.SetPercentFull(percentFull).SetEventCount(eventCount).SetValue(value);
103 channel_->SendNotification(bufferUsage);
104 }
105
DataCollected(std::unique_ptr<std::vector<TraceEvent>> traceEvents)106 void TracingImpl::Frontend::DataCollected(std::unique_ptr<std::vector<TraceEvent>> traceEvents)
107 {
108 if (!AllowNotify()) {
109 return;
110 }
111
112 tooling::DataCollected dataCollected;
113 dataCollected.SetTraceEvents(std::move(traceEvents));
114
115 channel_->SendNotification(dataCollected);
116 }
117
TracingComplete()118 void TracingImpl::Frontend::TracingComplete()
119 {
120 if (!AllowNotify()) {
121 return;
122 }
123
124 tooling::TracingComplete tracingComplete;
125 channel_->SendNotification(tracingComplete);
126 }
127
End()128 std::unique_ptr<std::vector<TraceEvent>> TracingImpl::End()
129 {
130 #if defined(ECMASCRIPT_SUPPORT_TRACING)
131 uv_timer_stop(&handle_);
132 #endif
133 auto traceEvents = panda::DFXJSNApi::StopTracing(vm_);
134 return traceEvents;
135 }
136
GetCategories(std::vector<std::string> categories)137 DispatchResponse TracingImpl::GetCategories([[maybe_unused]] std::vector<std::string> categories)
138 {
139 return DispatchResponse::Fail("GetCategories not support now.");
140 }
141
RecordClockSyncMarker(std::string syncId)142 DispatchResponse TracingImpl::RecordClockSyncMarker([[maybe_unused]] std::string syncId)
143 {
144 return DispatchResponse::Fail("RecordClockSyncMarker not support now.");
145 }
146
RequestMemoryDump(std::unique_ptr<RequestMemoryDumpParams> params,std::string dumpGuid,bool success)147 DispatchResponse TracingImpl::RequestMemoryDump([[maybe_unused]] std::unique_ptr<RequestMemoryDumpParams> params,
148 [[maybe_unused]] std::string dumpGuid, [[maybe_unused]] bool success)
149 {
150 return DispatchResponse::Fail("RequestMemoryDump not support now.");
151 }
152
Start(std::unique_ptr<StartParams> params)153 DispatchResponse TracingImpl::Start(std::unique_ptr<StartParams> params)
154 {
155 std::string categories = params->GetCategories();
156 if (!panda::DFXJSNApi::StartTracing(vm_, categories)) {
157 return DispatchResponse::Fail("Start tracing failed");
158 }
159
160 #if defined(ECMASCRIPT_SUPPORT_TRACING)
161 if (params->HasBufferUsageReportingInterval()) {
162 LOG_DEBUGGER(ERROR) << "HasBufferUsageReportingInterval " << params->GetBufferUsageReportingInterval();
163 if (uv_is_active(reinterpret_cast<uv_handle_t*>(&handle_))) {
164 LOG_DEBUGGER(ERROR) << "uv_is_active!!!";
165 return DispatchResponse::Ok();
166 }
167
168 uv_loop_t *loop = reinterpret_cast<uv_loop_t *>(vm_->GetLoop());
169 if (loop == nullptr) {
170 return DispatchResponse::Fail("Loop is nullptr");
171 }
172 uv_timer_init(loop, &handle_);
173 handle_.data = this;
174 uv_timer_start(&handle_, TracingBufferUsageReport, 0, params->GetBufferUsageReportingInterval());
175
176 uv_work_t *work = new uv_work_t;
177 uv_queue_work(loop, work, [](uv_work_t *) { }, [](uv_work_t *work, int32_t) { delete work; });
178 }
179 #endif
180 return DispatchResponse::Ok();
181 }
182
183 #if defined(ECMASCRIPT_SUPPORT_TRACING)
TracingBufferUsageReport(uv_timer_t * handle)184 void TracingImpl::TracingBufferUsageReport(uv_timer_t* handle)
185 {
186 TracingImpl *tracing = static_cast<TracingImpl *>(handle->data);
187 if (tracing == nullptr) {
188 LOG_DEBUGGER(ERROR) << "tracing == nullptr";
189 return;
190 }
191
192 double percentFull = 0.0;
193 uint32_t eventCount = 0;
194 double value = 0.0;
195 panda::DFXJSNApi::GetTracingBufferUseage(tracing->vm_, percentFull, eventCount, value);
196 tracing->frontend_.BufferUsage(percentFull, eventCount, value);
197 }
198 #endif
199 } // namespace panda::ecmascript::tooling