14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License.
54514f5e3Sopenharmony_ci * You may obtain a copy of the License at
64514f5e3Sopenharmony_ci *
74514f5e3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84514f5e3Sopenharmony_ci *
94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and
134514f5e3Sopenharmony_ci * limitations under the License.
144514f5e3Sopenharmony_ci */
154514f5e3Sopenharmony_ci
164514f5e3Sopenharmony_ci#include "ecmascript/dfx/tracing/tracing.h"
174514f5e3Sopenharmony_ci#include "ecmascript/debugger/js_debugger_manager.h"
184514f5e3Sopenharmony_ci
194514f5e3Sopenharmony_cinamespace panda::ecmascript {
204514f5e3Sopenharmony_ciuint64_t TraceEvent::GetEventBufferSize()
214514f5e3Sopenharmony_ci{
224514f5e3Sopenharmony_ci    uint64_t size = sizeof(*this) + cat_.size() + name_.size() + ph_.size() + args_.size() + s_.size() + id_.size();
234514f5e3Sopenharmony_ci    if (cpuProfileArgs_.has_value()) {
244514f5e3Sopenharmony_ci        size += cpuProfileArgs_.value().nodes.size() * sizeof(int);
254514f5e3Sopenharmony_ci        size += cpuProfileArgs_.value().samples.size() * sizeof(int);
264514f5e3Sopenharmony_ci        size += cpuProfileArgs_.value().timeDeltas.size() * sizeof(int);
274514f5e3Sopenharmony_ci    }
284514f5e3Sopenharmony_ci    return size;
294514f5e3Sopenharmony_ci}
304514f5e3Sopenharmony_ci
314514f5e3Sopenharmony_ciTracing::Tracing(const EcmaVM *vm) : vm_(vm)
324514f5e3Sopenharmony_ci{
334514f5e3Sopenharmony_ci    traceEvents_ = std::make_unique<std::vector<TraceEvent>>();
344514f5e3Sopenharmony_ci    traceEventsCpuProfiler_ = std::make_unique<std::vector<TraceEvent>>();
354514f5e3Sopenharmony_ci}
364514f5e3Sopenharmony_ci
374514f5e3Sopenharmony_ciTracing::~Tracing()
384514f5e3Sopenharmony_ci{
394514f5e3Sopenharmony_ci}
404514f5e3Sopenharmony_ci
414514f5e3Sopenharmony_civoid Tracing::StartTracing(std::string &categories)
424514f5e3Sopenharmony_ci{
434514f5e3Sopenharmony_ci    if (isTracing_) {
444514f5e3Sopenharmony_ci        return;
454514f5e3Sopenharmony_ci    }
464514f5e3Sopenharmony_ci
474514f5e3Sopenharmony_ci    categories_ = categories;
484514f5e3Sopenharmony_ci    if (categories_.find("cpu_profiler") != std::string::npos) {
494514f5e3Sopenharmony_ci        panda::JSNApi::SetProfilerState(vm_, true);
504514f5e3Sopenharmony_ci        panda::DFXJSNApi::StartCpuProfilerForInfo(vm_);
514514f5e3Sopenharmony_ci    }
524514f5e3Sopenharmony_ci
534514f5e3Sopenharmony_ci    tid_ = static_cast<pthread_t>(syscall(SYS_gettid));
544514f5e3Sopenharmony_ci    isTracing_ = true;
554514f5e3Sopenharmony_ci    vm_->GetJsDebuggerManager()->GetNotificationManager()->AddListener(this);
564514f5e3Sopenharmony_ci    vm_->GetJSThread()->SetIsTracing(true);
574514f5e3Sopenharmony_ci
584514f5e3Sopenharmony_ci    TraceEventRecordTracingStart();
594514f5e3Sopenharmony_ci    return;
604514f5e3Sopenharmony_ci}
614514f5e3Sopenharmony_ci
624514f5e3Sopenharmony_cistd::unique_ptr<std::vector<TraceEvent>> Tracing::StopTracing()
634514f5e3Sopenharmony_ci{
644514f5e3Sopenharmony_ci    isTracing_ = false;
654514f5e3Sopenharmony_ci    vm_->GetJsDebuggerManager()->GetNotificationManager()->RemoveListener(this);
664514f5e3Sopenharmony_ci    if (categories_.find("cpu_profiler") != std::string::npos) {
674514f5e3Sopenharmony_ci        std::unique_ptr<ProfileInfo> profileInfo = panda::DFXJSNApi::StopCpuProfilerForInfo(vm_);
684514f5e3Sopenharmony_ci        panda::JSNApi::SetProfilerState(vm_, false);
694514f5e3Sopenharmony_ci        if (profileInfo) {
704514f5e3Sopenharmony_ci            TraceEventUpdateCpuProfiler(profileInfo.get());
714514f5e3Sopenharmony_ci        }
724514f5e3Sopenharmony_ci    }
734514f5e3Sopenharmony_ci    vm_->GetJSThread()->SetIsTracing(false);
744514f5e3Sopenharmony_ci    return std::move(traceEvents_);
754514f5e3Sopenharmony_ci}
764514f5e3Sopenharmony_ci
774514f5e3Sopenharmony_ciuint64_t Tracing::GetTimeStamp()
784514f5e3Sopenharmony_ci{
794514f5e3Sopenharmony_ci    const int USEC_PER_SEC = 1000 * 1000;
804514f5e3Sopenharmony_ci    const int NSEC_PER_USEC = 1000;
814514f5e3Sopenharmony_ci    struct timespec time;
824514f5e3Sopenharmony_ci    clock_gettime(CLOCK_MONOTONIC, &time);
834514f5e3Sopenharmony_ci    return time.tv_sec * USEC_PER_SEC + time.tv_nsec / NSEC_PER_USEC;
844514f5e3Sopenharmony_ci}
854514f5e3Sopenharmony_ci
864514f5e3Sopenharmony_civoid Tracing::RecordTraceEvent(TraceEvent &event)
874514f5e3Sopenharmony_ci{
884514f5e3Sopenharmony_ci    bufferSize_ += event.GetEventBufferSize();
894514f5e3Sopenharmony_ci
904514f5e3Sopenharmony_ci    std::lock_guard<std::mutex> lock(lock_);
914514f5e3Sopenharmony_ci    traceEvents_->emplace_back(event);
924514f5e3Sopenharmony_ci}
934514f5e3Sopenharmony_ci
944514f5e3Sopenharmony_civoid Tracing::TraceEventRecordTracingStart()
954514f5e3Sopenharmony_ci{
964514f5e3Sopenharmony_ci    int64_t ts = static_cast<int64_t>(GetTimeStamp());
974514f5e3Sopenharmony_ci    std::string args = "{\"data\":{\"frameTreeNodeId\":1,\"frames\":[{";
984514f5e3Sopenharmony_ci    args += "\"frame\":\"0\",\"name\":\"\",";
994514f5e3Sopenharmony_ci    args += "\"processId\":" + std::to_string(getpid()) + ",";
1004514f5e3Sopenharmony_ci    args += "\"url\":\"https://url not exist/\"}],";
1014514f5e3Sopenharmony_ci    args += "\"persistentIds\":true}}";
1024514f5e3Sopenharmony_ci
1034514f5e3Sopenharmony_ci    TraceEvent event("disabled-by-default-devtools.timeline", "TracingStartedInBrowser", "I", getpid(), tid_);
1044514f5e3Sopenharmony_ci    event.SetTs(ts);
1054514f5e3Sopenharmony_ci    event.SetTts(ts);
1064514f5e3Sopenharmony_ci    event.SetS("t");
1074514f5e3Sopenharmony_ci    event.SetArgs(args);
1084514f5e3Sopenharmony_ci
1094514f5e3Sopenharmony_ci    RecordTraceEvent(event);
1104514f5e3Sopenharmony_ci}
1114514f5e3Sopenharmony_ci
1124514f5e3Sopenharmony_civoid Tracing::TraceEventRecordMemory()
1134514f5e3Sopenharmony_ci{
1144514f5e3Sopenharmony_ci    if (!isTracing_) {
1154514f5e3Sopenharmony_ci        return;
1164514f5e3Sopenharmony_ci    }
1174514f5e3Sopenharmony_ci
1184514f5e3Sopenharmony_ci    int64_t ts = static_cast<int64_t>(GetTimeStamp());
1194514f5e3Sopenharmony_ci    TraceEvent event("disabled-by-default-devtools.timeline", "UpdateCounters", "I", getpid(), tid_);
1204514f5e3Sopenharmony_ci    event.SetTs(ts);
1214514f5e3Sopenharmony_ci    event.SetTts(ts);
1224514f5e3Sopenharmony_ci    event.SetS("t");
1234514f5e3Sopenharmony_ci    std::string args = "{\"data\":{\"jsHeapSizeUsed\":" + std::to_string(DFXJSNApi::GetHeapUsedSize(vm_)) + "}}";
1244514f5e3Sopenharmony_ci    event.SetArgs(args);
1254514f5e3Sopenharmony_ci
1264514f5e3Sopenharmony_ci    RecordTraceEvent(event);
1274514f5e3Sopenharmony_ci}
1284514f5e3Sopenharmony_ci
1294514f5e3Sopenharmony_civoid Tracing::TraceEventRecordCpuProfilerStart(struct ProfileInfo* profileInfo)
1304514f5e3Sopenharmony_ci{
1314514f5e3Sopenharmony_ci    int64_t ts = static_cast<int64_t>(GetTimeStamp());
1324514f5e3Sopenharmony_ci    std::string args = "{\"data\":{\"startTime\":" + std::to_string(profileInfo->startTime) + "}}";
1334514f5e3Sopenharmony_ci    TraceEvent event("disabled-by-default-v8.cpu_profiler", "Profile", "P", getpid(), tid_);
1344514f5e3Sopenharmony_ci    event.SetTs(ts);
1354514f5e3Sopenharmony_ci    event.SetTts(ts);
1364514f5e3Sopenharmony_ci    event.SetId("0x1");
1374514f5e3Sopenharmony_ci    event.SetArgs(args);
1384514f5e3Sopenharmony_ci
1394514f5e3Sopenharmony_ci    bufferSize_ += event.GetEventBufferSize();
1404514f5e3Sopenharmony_ci    traceEventsCpuProfiler_->emplace_back(event);
1414514f5e3Sopenharmony_ci}
1424514f5e3Sopenharmony_ci
1434514f5e3Sopenharmony_civoid Tracing::TraceEventRecordCpuProfiler(struct ProfileInfo* profileInfo, int &nodePos, uint32_t &samplePos)
1444514f5e3Sopenharmony_ci{
1454514f5e3Sopenharmony_ci    if (!isTracing_) {
1464514f5e3Sopenharmony_ci        return;
1474514f5e3Sopenharmony_ci    }
1484514f5e3Sopenharmony_ci
1494514f5e3Sopenharmony_ci    int64_t ts = static_cast<int64_t>(GetTimeStamp());
1504514f5e3Sopenharmony_ci    TraceEvent event("disabled-by-default-v8.cpu_profiler", "ProfileChunk", "P", getpid(), tid_);
1514514f5e3Sopenharmony_ci    event.SetTs(ts);
1524514f5e3Sopenharmony_ci    event.SetTts(ts);
1534514f5e3Sopenharmony_ci    event.SetId("0x1");
1544514f5e3Sopenharmony_ci
1554514f5e3Sopenharmony_ci    struct TraceEventCpuProfileArg args;
1564514f5e3Sopenharmony_ci    if (nodePos >= 0 && profileInfo->nodeCount > nodePos) {
1574514f5e3Sopenharmony_ci        for (int i = nodePos; i < profileInfo->nodeCount; ++i) {
1584514f5e3Sopenharmony_ci            args.nodes.emplace_back(profileInfo->nodes[i].id);
1594514f5e3Sopenharmony_ci        }
1604514f5e3Sopenharmony_ci        nodePos = profileInfo->nodeCount;
1614514f5e3Sopenharmony_ci    }
1624514f5e3Sopenharmony_ci
1634514f5e3Sopenharmony_ci    std::copy(profileInfo->samples.begin() + samplePos, profileInfo->samples.end(),
1644514f5e3Sopenharmony_ci        std::back_inserter(args.samples));
1654514f5e3Sopenharmony_ci    std::copy(profileInfo->timeDeltas.begin() + samplePos, profileInfo->timeDeltas.end(),
1664514f5e3Sopenharmony_ci        std::back_inserter(args.timeDeltas));
1674514f5e3Sopenharmony_ci    samplePos = profileInfo->samples.size();
1684514f5e3Sopenharmony_ci
1694514f5e3Sopenharmony_ci    event.SetCpuProfileArgs(args);
1704514f5e3Sopenharmony_ci
1714514f5e3Sopenharmony_ci    bufferSize_ += event.GetEventBufferSize();
1724514f5e3Sopenharmony_ci    traceEventsCpuProfiler_->emplace_back(event);
1734514f5e3Sopenharmony_ci}
1744514f5e3Sopenharmony_ci
1754514f5e3Sopenharmony_civoid Tracing::TraceEventUpdateCpuProfiler(struct ProfileInfo *profileInfo)
1764514f5e3Sopenharmony_ci{
1774514f5e3Sopenharmony_ci    for (auto &event : *traceEventsCpuProfiler_) {
1784514f5e3Sopenharmony_ci        if (!event.cpuProfileArgs_.has_value()) {
1794514f5e3Sopenharmony_ci            traceEvents_->emplace_back(event);
1804514f5e3Sopenharmony_ci            continue;
1814514f5e3Sopenharmony_ci        }
1824514f5e3Sopenharmony_ci
1834514f5e3Sopenharmony_ci        struct TraceEventCpuProfileArg &cpuProfileArg = event.cpuProfileArgs_.value();
1844514f5e3Sopenharmony_ci        std::string args = "{\"data\":{\"cpuProfile\":{";
1854514f5e3Sopenharmony_ci        // nodes
1864514f5e3Sopenharmony_ci        if (cpuProfileArg.nodes.size() > 0) {
1874514f5e3Sopenharmony_ci            args += "\"nodes\": [";
1884514f5e3Sopenharmony_ci            for (auto &nodeId : cpuProfileArg.nodes) {
1894514f5e3Sopenharmony_ci                struct CpuProfileNode &nodeInfo = profileInfo->nodes[nodeId - 1];
1904514f5e3Sopenharmony_ci                args += "{\"callFrame\":{\"codeType\":\"JS\",";
1914514f5e3Sopenharmony_ci                if (nodeInfo.codeEntry.columnNumber != -1) {
1924514f5e3Sopenharmony_ci                    args += "\"columnNumber\":" + std::to_string(nodeInfo.codeEntry.columnNumber) + ",";
1934514f5e3Sopenharmony_ci                }
1944514f5e3Sopenharmony_ci                args += "\"functionName\":\"" + nodeInfo.codeEntry.functionName + "\",";
1954514f5e3Sopenharmony_ci                if (nodeInfo.codeEntry.lineNumber != -1) {
1964514f5e3Sopenharmony_ci                    args += "\"lineNumber\":" + std::to_string(nodeInfo.codeEntry.lineNumber) + ",";
1974514f5e3Sopenharmony_ci                }
1984514f5e3Sopenharmony_ci                args += "\"scriptId\":" + std::to_string(nodeInfo.codeEntry.scriptId) + ",";
1994514f5e3Sopenharmony_ci                if (nodeInfo.codeEntry.scriptId != 0) {
2004514f5e3Sopenharmony_ci                    args += "\"url\":\"" + nodeInfo.codeEntry.url + "\"";
2014514f5e3Sopenharmony_ci                } else {
2024514f5e3Sopenharmony_ci                    args.pop_back();
2034514f5e3Sopenharmony_ci                }
2044514f5e3Sopenharmony_ci                args += "},";
2054514f5e3Sopenharmony_ci                args += "\"id\":" + std::to_string(nodeInfo.id) + ",";
2064514f5e3Sopenharmony_ci                if (nodeInfo.parentId != 0) {
2074514f5e3Sopenharmony_ci                    args += "\"parent\":" + std::to_string(nodeInfo.parentId) + ",";
2084514f5e3Sopenharmony_ci                }
2094514f5e3Sopenharmony_ci                args += "\"hitCount\":" + std::to_string(nodeInfo.hitCount) + ",";
2104514f5e3Sopenharmony_ci                args += "\"children\":[";
2114514f5e3Sopenharmony_ci                for (auto &it : nodeInfo.children) {
2124514f5e3Sopenharmony_ci                    args += std::to_string(it) + ",";
2134514f5e3Sopenharmony_ci                }
2144514f5e3Sopenharmony_ci                if (nodeInfo.children.size() != 0) {
2154514f5e3Sopenharmony_ci                    args.pop_back();
2164514f5e3Sopenharmony_ci                }
2174514f5e3Sopenharmony_ci                args += "]},";
2184514f5e3Sopenharmony_ci            }
2194514f5e3Sopenharmony_ci            args.pop_back();
2204514f5e3Sopenharmony_ci            args += "],";
2214514f5e3Sopenharmony_ci        }
2224514f5e3Sopenharmony_ci
2234514f5e3Sopenharmony_ci        // samples
2244514f5e3Sopenharmony_ci        args += "\"samples\": [";
2254514f5e3Sopenharmony_ci        for (auto sample : cpuProfileArg.samples) {
2264514f5e3Sopenharmony_ci            args += std::to_string(sample) + ",";
2274514f5e3Sopenharmony_ci        }
2284514f5e3Sopenharmony_ci        args.pop_back();
2294514f5e3Sopenharmony_ci        args += "]},";
2304514f5e3Sopenharmony_ci
2314514f5e3Sopenharmony_ci        // lines
2324514f5e3Sopenharmony_ci        args += "\"lines\": [";
2334514f5e3Sopenharmony_ci        for (auto sample : cpuProfileArg.samples) {
2344514f5e3Sopenharmony_ci            args += std::to_string(profileInfo->nodes[profileInfo->samples[sample - 1]].codeEntry.lineNumber + 1) + ",";
2354514f5e3Sopenharmony_ci        }
2364514f5e3Sopenharmony_ci        args.pop_back();
2374514f5e3Sopenharmony_ci        args += "],";
2384514f5e3Sopenharmony_ci
2394514f5e3Sopenharmony_ci        // timeDeltas
2404514f5e3Sopenharmony_ci        args += "\"timeDeltas\": [";
2414514f5e3Sopenharmony_ci        for (auto timeDelta : cpuProfileArg.timeDeltas) {
2424514f5e3Sopenharmony_ci            args += std::to_string(timeDelta) + ",";
2434514f5e3Sopenharmony_ci        }
2444514f5e3Sopenharmony_ci        args.pop_back();
2454514f5e3Sopenharmony_ci        args += "]}}";
2464514f5e3Sopenharmony_ci
2474514f5e3Sopenharmony_ci        event.SetArgs(args);
2484514f5e3Sopenharmony_ci        traceEvents_->emplace_back(event);
2494514f5e3Sopenharmony_ci    }
2504514f5e3Sopenharmony_ci}
2514514f5e3Sopenharmony_ci
2524514f5e3Sopenharmony_civoid Tracing::TraceEventRecordCpuProfilerEnd(struct ProfileInfo* profileInfo)
2534514f5e3Sopenharmony_ci{
2544514f5e3Sopenharmony_ci    int64_t ts = static_cast<int64_t>(GetTimeStamp());
2554514f5e3Sopenharmony_ci    std::string args = "{\"data\":{\"endTime\":" + std::to_string(profileInfo->stopTime) + "}}";
2564514f5e3Sopenharmony_ci    TraceEvent event("disabled-by-default-v8.cpu_profiler", "ProfileChunk", "P", getpid(), tid_);
2574514f5e3Sopenharmony_ci    event.SetTs(ts);
2584514f5e3Sopenharmony_ci    event.SetTts(ts);
2594514f5e3Sopenharmony_ci    event.SetId("0x1");
2604514f5e3Sopenharmony_ci    event.SetArgs(args);
2614514f5e3Sopenharmony_ci
2624514f5e3Sopenharmony_ci    bufferSize_ += event.GetEventBufferSize();
2634514f5e3Sopenharmony_ci    traceEventsCpuProfiler_->emplace_back(event);
2644514f5e3Sopenharmony_ci}
2654514f5e3Sopenharmony_ci
2664514f5e3Sopenharmony_civoid Tracing::GetBufferUseage(double &percentFull, uint32_t &eventCount, double &value)
2674514f5e3Sopenharmony_ci{
2684514f5e3Sopenharmony_ci    percentFull = (bufferSize_ >= maxBufferSize_) ? 1.0 : static_cast<double>(bufferSize_) / maxBufferSize_;
2694514f5e3Sopenharmony_ci    eventCount = 0;
2704514f5e3Sopenharmony_ci    value = percentFull;
2714514f5e3Sopenharmony_ci}
2724514f5e3Sopenharmony_ci
2734514f5e3Sopenharmony_civoid Tracing::LoadModule([[maybe_unused]] std::string_view name, [[maybe_unused]] std::string_view)
2744514f5e3Sopenharmony_ci{
2754514f5e3Sopenharmony_ci    return;
2764514f5e3Sopenharmony_ci}
2774514f5e3Sopenharmony_civoid Tracing::BytecodePcChanged([[maybe_unused]] JSThread *thread, [[maybe_unused]] JSHandle<Method> method,
2784514f5e3Sopenharmony_ci                                [[maybe_unused]] uint32_t bcOffset)
2794514f5e3Sopenharmony_ci{
2804514f5e3Sopenharmony_ci    return;
2814514f5e3Sopenharmony_ci}
2824514f5e3Sopenharmony_cibool Tracing::HandleDebuggerStmt([[maybe_unused]] JSHandle<Method> method, [[maybe_unused]] uint32_t bcOffset)
2834514f5e3Sopenharmony_ci{
2844514f5e3Sopenharmony_ci    return true;
2854514f5e3Sopenharmony_ci}
2864514f5e3Sopenharmony_civoid Tracing::VmStart()
2874514f5e3Sopenharmony_ci{
2884514f5e3Sopenharmony_ci    return;
2894514f5e3Sopenharmony_ci}
2904514f5e3Sopenharmony_civoid Tracing::VmDeath()
2914514f5e3Sopenharmony_ci{
2924514f5e3Sopenharmony_ci    return;
2934514f5e3Sopenharmony_ci}
2944514f5e3Sopenharmony_civoid Tracing::NativeCalling([[maybe_unused]] const void *nativeAddress)
2954514f5e3Sopenharmony_ci{
2964514f5e3Sopenharmony_ci    return;
2974514f5e3Sopenharmony_ci}
2984514f5e3Sopenharmony_civoid Tracing::NativeReturn([[maybe_unused]] const void *nativeAddress)
2994514f5e3Sopenharmony_ci{
3004514f5e3Sopenharmony_ci    return;
3014514f5e3Sopenharmony_ci}
3024514f5e3Sopenharmony_civoid Tracing::MethodEntry([[maybe_unused]] JSHandle<Method> method, [[maybe_unused]] JSHandle<JSTaggedValue> envHandle)
3034514f5e3Sopenharmony_ci{
3044514f5e3Sopenharmony_ci    return;
3054514f5e3Sopenharmony_ci}
3064514f5e3Sopenharmony_civoid Tracing::MethodExit([[maybe_unused]] JSHandle<Method> method)
3074514f5e3Sopenharmony_ci{
3084514f5e3Sopenharmony_ci    TraceEventRecordMemory();
3094514f5e3Sopenharmony_ci    return;
3104514f5e3Sopenharmony_ci}
3114514f5e3Sopenharmony_ci}  // namespace panda::ecmascript
312