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