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
22 namespace panda::ecmascript::job {
EnqueueJobScope(const JSHandle<PendingJob> & pendingJob,QueueType queueType)23 EnqueueJobScope::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
~EnqueueJobScope()49 EnqueueJobScope::~EnqueueJobScope()
50 {
51 }
52
ExecuteJobScope(const JSHandle<PendingJob> & pendingJob)53 ExecuteJobScope::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
~ExecuteJobScope()75 ExecuteJobScope::~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
EnqueueJobTrace(JSThread * thread,const JSHandle<PendingJob> & pendingJob)89 EnqueueJobTrace::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_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, strTrace.c_str());
104 return;
105 }
106
107 JsFrameInfo jsFrameInfo = jsStackInfo.front();
108 size_t pos = jsFrameInfo.pos.find(':', 0);
109 if (pos != CString::npos) {
110 int64_t tmp = std::strtoll(jsFrameInfo.pos.substr(0, pos).c_str(), nullptr, 10);
111 if (tmp < INT_MIN || tmp > INT_MAX) {
112 LOG_ECMA(ERROR) << "MicroJobTrace: Invalid line number: " << jsFrameInfo.pos.substr(0, pos);
113 return;
114 }
115
116 int64_t val = std::strtoll(jsFrameInfo.pos.substr(pos + 1).c_str(), nullptr, 10);
117 if (val < INT_MIN || val > INT_MAX) {
118 LOG_ECMA(ERROR) << "MicroJobTrace: Invalid column number: " << jsFrameInfo.pos.substr(pos + 1);
119 return;
120 }
121 int lineNumber = static_cast<int>(tmp);
122 int columnNumber = static_cast<int>(val);
123 auto sourceMapcb = thread->GetEcmaVM()->GetSourceMapTranslateCallback();
124 if (sourceMapcb != nullptr && !jsFrameInfo.fileName.empty()) {
125 sourceMapcb(jsFrameInfo.fileName, lineNumber, columnNumber, jsFrameInfo.packageName);
126 }
127 }
128
129 strTrace += ", funcName: " + jsFrameInfo.functionName + ", url: " + jsFrameInfo.fileName + ":" + jsFrameInfo.pos;
130 ECMA_BYTRACE_START_TRACE(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, strTrace.c_str());
131 }
132
~EnqueueJobTrace()133 EnqueueJobTrace::~EnqueueJobTrace()
134 {
135 if (isMicroJobTraceEnable_) {
136 ECMA_BYTRACE_FINISH_TRACE(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK);
137 }
138 }
139
ExecuteJobTrace(JSThread * thread,const JSHandle<PendingJob> & pendingJob)140 ExecuteJobTrace::ExecuteJobTrace(JSThread *thread, const JSHandle<PendingJob> &pendingJob)
141 {
142 isMicroJobTraceEnable_ = thread->GetEcmaVM()->GetJSOptions().EnableMicroJobTrace();
143 if (isMicroJobTraceEnable_) {
144 uint64_t jobId = pendingJob->GetJobId();
145 std::string strTrace = "PendingJob::ExecutePendingJob: jobId: " + std::to_string(jobId);
146 strTrace += ", threadId: " + std::to_string(thread->GetThreadId());
147 ECMA_BYTRACE_START_TRACE(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK, strTrace.c_str());
148 }
149 }
150
~ExecuteJobTrace()151 ExecuteJobTrace::~ExecuteJobTrace()
152 {
153 if (isMicroJobTraceEnable_) {
154 ECMA_BYTRACE_FINISH_TRACE(HITRACE_LEVEL_COMMERCIAL, HITRACE_TAG_ARK);
155 }
156 }
157 } // namespace panda::ecmascript::job