1/*
2 * Copyright (c) 2021-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 "ecmascript/jobs/hitrace_scope.h"
17
18#include "ecmascript/jobs/pending_job.h"
19#include "hitrace/trace.h"
20#include "ecmascript/dfx/stackinfo/js_stackinfo.h"
21
22namespace panda::ecmascript::job {
23EnqueueJobScope::EnqueueJobScope(const JSHandle<PendingJob> &pendingJob, QueueType queueType)
24{
25    HiTraceId id = HiTraceChain::GetId();
26    if (id.IsValid() && id.IsFlagEnabled(HITRACE_FLAG_INCLUDE_ASYNC)) {
27        HiTraceId childId = HiTraceChain::CreateSpan();
28
29        pendingJob->SetChainId(childId.GetChainId());
30        pendingJob->SetSpanId(childId.GetSpanId());
31        pendingJob->SetParentSpanId(childId.GetParentSpanId());
32        pendingJob->SetFlags(childId.GetFlags());
33
34        if (id.IsFlagEnabled(HITRACE_FLAG_TP_INFO)) {
35            if (queueType == QueueType::QUEUE_PROMISE) {
36                HiTraceChain::Tracepoint(HITRACE_CM_THREAD, HITRACE_TP_CS,
37                    childId, "Queue type:%s", "Promise queue");
38            } else if (queueType == QueueType::QUEUE_SCRIPT) {
39                HiTraceChain::Tracepoint(HITRACE_CM_THREAD, HITRACE_TP_CS,
40                    childId, "Queue type:%s", "Script queue");
41            } else {
42                HiTraceChain::Tracepoint(HITRACE_CM_THREAD, HITRACE_TP_CS,
43                    childId, "Queue type:%s", "Other queue");
44            }
45        }
46    }
47}
48
49EnqueueJobScope::~EnqueueJobScope()
50{
51}
52
53ExecuteJobScope::ExecuteJobScope(const JSHandle<PendingJob> &pendingJob)
54{
55    saveId_ = HiTraceChain::GetId();
56    if (saveId_.IsValid()) {
57        HiTraceChain::ClearId();
58    }
59    if (pendingJob->GetChainId() != 0) {
60        hitraceId_.SetChainId(pendingJob->GetChainId());
61        hitraceId_.SetSpanId(pendingJob->GetSpanId());
62        hitraceId_.SetParentSpanId(pendingJob->GetParentSpanId());
63        hitraceId_.SetFlags(pendingJob->GetFlags());
64
65        if (hitraceId_.IsValid()) {
66            HiTraceChain::SetId(hitraceId_);
67            if (hitraceId_.IsFlagEnabled(HITRACE_FLAG_TP_INFO)) {
68                HiTraceChain::Tracepoint(HITRACE_CM_THREAD, HITRACE_TP_SR,
69                    hitraceId_, "Before %s pending job execute", "Promise");
70            }
71        }
72    }
73}
74
75ExecuteJobScope::~ExecuteJobScope()
76{
77    if (hitraceId_.IsValid()) {
78        if (hitraceId_.IsFlagEnabled(HITRACE_FLAG_TP_INFO)) {
79            HiTraceChain::Tracepoint(HITRACE_CM_THREAD, HITRACE_TP_SS,
80                hitraceId_, "After %s pending job execute", "Promise");
81        }
82        HiTraceChain::ClearId();
83    }
84    if (saveId_.IsValid()) {
85        HiTraceChain::SetId(saveId_);
86    }
87}
88
89EnqueueJobTrace::EnqueueJobTrace(JSThread *thread, const JSHandle<PendingJob> &pendingJob)
90{
91    isMicroJobTraceEnable_ = thread->GetEcmaVM()->GetJSOptions().EnableMicroJobTrace();
92    if (!isMicroJobTraceEnable_) {
93        return;
94    }
95
96    uint64_t jobId = thread->GetJobId();
97    pendingJob->SetJobId(jobId);
98    std::string strTrace = "MicroJobQueue::EnqueueJob: jobId: " + std::to_string(jobId);
99    strTrace += ", threadId: " + std::to_string(thread->GetThreadId());
100
101    std::vector<JsFrameInfo> jsStackInfo = JsStackInfo::BuildJsStackInfo(thread, true);
102    if (jsStackInfo.empty()) {
103        ECMA_BYTRACE_START_TRACE(HITRACE_TAG_ARK, strTrace);
104        return;
105    }
106
107    JsFrameInfo jsFrameInfo = jsStackInfo.front();
108    size_t pos = jsFrameInfo.pos.find(':', 0);
109    if (pos != CString::npos) {
110        int lineNumber = std::stoi(jsFrameInfo.pos.substr(0, pos));
111        int columnNumber = std::stoi(jsFrameInfo.pos.substr(pos + 1));
112        auto sourceMapcb = thread->GetEcmaVM()->GetSourceMapTranslateCallback();
113        if (sourceMapcb != nullptr && !jsFrameInfo.fileName.empty()) {
114            sourceMapcb(jsFrameInfo.fileName, lineNumber, columnNumber);
115        }
116    }
117
118    strTrace += ", funcName: " + jsFrameInfo.functionName + ", url: " + jsFrameInfo.fileName + ":" + jsFrameInfo.pos;
119    ECMA_BYTRACE_START_TRACE(HITRACE_TAG_ARK, strTrace);
120}
121
122EnqueueJobTrace::~EnqueueJobTrace()
123{
124    if (isMicroJobTraceEnable_) {
125        ECMA_BYTRACE_FINISH_TRACE(HITRACE_TAG_ARK);
126    }
127}
128
129ExecuteJobTrace::ExecuteJobTrace(JSThread *thread, const JSHandle<PendingJob> &pendingJob)
130{
131    isMicroJobTraceEnable_ = thread->GetEcmaVM()->GetJSOptions().EnableMicroJobTrace();
132    if (isMicroJobTraceEnable_) {
133        uint64_t jobId = pendingJob->GetJobId();
134        std::string strTrace = "PendingJob::ExecutePendingJob: jobId: " + std::to_string(jobId);
135        strTrace += ", threadId: " + std::to_string(thread->GetThreadId());
136        ECMA_BYTRACE_START_TRACE(HITRACE_TAG_ARK, strTrace);
137    }
138}
139
140ExecuteJobTrace::~ExecuteJobTrace()
141{
142    if (isMicroJobTraceEnable_) {
143        ECMA_BYTRACE_FINISH_TRACE(HITRACE_TAG_ARK);
144    }
145}
146}  // namespace panda::ecmascript::job