1 /*
2 * Copyright (c) 2023 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 #include "frameworks/bridge/declarative_frontend/jsview/js_state_mgmt_profiler.h"
16 #include "base/log/dump_log.h"
17 #include "base/utils/utils.h"
18
19 namespace OHOS::Ace::Framework {
JSStateMgmtProfiler(std::string profilerPackage)20 JSStateMgmtProfiler::JSStateMgmtProfiler(std::string profilerPackage) : profilerPackage_(std::move(profilerPackage))
21 {
22 }
23
JSBind(BindingTarget globalObj)24 void JSStateMgmtProfiler::JSBind(BindingTarget globalObj)
25 {
26 JSClass<JSStateMgmtProfiler>::Declare("StateMgmtProfiler");
27 JSClass<JSStateMgmtProfiler>::Method("begin", &JSStateMgmtProfiler::Begin);
28 JSClass<JSStateMgmtProfiler>::Method("end", &JSStateMgmtProfiler::End);
29 JSClass<JSStateMgmtProfiler>::Method("report", &JSStateMgmtProfiler::Report);
30 JSClass<JSStateMgmtProfiler>::Method("clear", &JSStateMgmtProfiler::Clear);
31 JSClass<JSStateMgmtProfiler>::Bind(globalObj, JSStateMgmtProfiler::ConstructorCallback);
32 }
33
ConstructorCallback(const JSCallbackInfo & info)34 void JSStateMgmtProfiler::ConstructorCallback(const JSCallbackInfo& info)
35 {
36 if (info[0]->IsString()) {
37 auto instance = new JSStateMgmtProfiler(info[0]->ToString());
38 info.SetReturnValue(instance);
39 } else {
40 LOGE("JSStateMgmtProfiler invalid arguments! Expected a string");
41 }
42 }
43
Begin(const std::string & blockName)44 void JSStateMgmtProfiler::Begin(const std::string& blockName)
45 {
46 auto then = GetNanoseconds();
47 std::shared_ptr<ProfileBlock> block = nullptr;
48 if (currentBlocks_.empty()) {
49 for (const auto& rootBlock : rootBlocks_) {
50 if (blockName == rootBlock->Name()) {
51 block = rootBlock;
52 break;
53 }
54 }
55 if (!block) {
56 block = std::make_shared<ProfileBlock>(blockName);
57 rootBlocks_.push_back(block);
58 }
59 } else {
60 block = currentBlocks_.top()->GetOrCreateChild(blockName);
61 }
62
63 currentBlocks_.push(block);
64 block->IncreaseCalls();
65 block->SetOwnLookupTime(GetNanoseconds() - then);
66 block->SetStartTime(GetNanoseconds());
67 }
68
End()69 void JSStateMgmtProfiler::End()
70 {
71 auto now = GetNanoseconds();
72 auto then = currentBlocks_.top();
73 then->SetTotalTime(then->TotalTime() + (now - then->StartTime()));
74 currentBlocks_.pop();
75 if (!currentBlocks_.empty()) {
76 auto parent = currentBlocks_.top();
77 parent->SetOwnLookupTime(parent->OwnLookupTime() + then->OwnLookupTime());
78 }
79 }
80
Report()81 void JSStateMgmtProfiler::Report()
82 {
83 if (rootBlocks_.empty()) {
84 DumpLog::GetInstance().Print(0, "StateMgmtProfiler: nothing to report.");
85 return;
86 }
87 const int nameWidth = 70;
88 const int itemWidth = 14;
89
90 DumpLog::GetInstance().Reset();
91 std::unique_ptr<std::ostringstream> stdOut = std::make_unique<std::ostringstream>();
92 DumpLog::GetInstance().SetDumpFile(std::move(stdOut));
93 std::ostringstream ss;
94 ss << std::left << "Block name" << std::setw(nameWidth) << std::right << "#Calls" << std::setw(itemWidth) << "Self"
95 << std::setw(itemWidth) << "Total";
96 std::string out = ss.str();
97 std::string dashes(out.size(), '=');
98 DumpLog::GetInstance().Print(0, dashes);
99 DumpLog::GetInstance().Print(0, out);
100 DumpLog::GetInstance().Print(0, dashes);
101 DumpLog::GetInstance().Print(0, profilerPackage_);
102 for (const auto& blocks : rootBlocks_) {
103 blocks->Report(1);
104 }
105 DumpLog::GetInstance().Print(0, dashes);
106
107 Clear();
108 }
109
Report(int32_t depth) const110 void JSStateMgmtProfiler::ProfileBlock::Report(int32_t depth) const
111 {
112 std::ostringstream ss;
113 uint64_t childrenTime = 0ULL;
114 for (const auto& childrenBlocks : childrenBlocks_) {
115 childrenTime += childrenBlocks->TotalTime();
116 }
117 const int nameAdjustWidth = 80;
118 const int itemAdjustWidth = 12;
119 const int itemPrecision = 3;
120 const int nanoSecsInMilliSec = 1000000;
121
122 ss << std::left << std::string(depth, ' ');
123 ss << name_;
124 ss << std::setw(nameAdjustWidth - static_cast<int32_t>(name_.size()) - depth);
125 ss << std::right << numberOfCalls_;
126 ss << std::setw(itemAdjustWidth);
127 ss << std::fixed << std::setprecision(itemPrecision)
128 << (static_cast<double>(totalTime_ - childrenTime - ownLookupTime_) / nanoSecsInMilliSec) << "ms";
129 ss << std::setw(itemAdjustWidth);
130 ss << (static_cast<double>(totalTime_ - ownLookupTime_) / nanoSecsInMilliSec) << "ms";
131
132 DumpLog::GetInstance().Print(0, ss.str());
133 for (const auto& childrenBlocks : childrenBlocks_) {
134 childrenBlocks->Report(depth + 1);
135 }
136 }
137
Clear()138 void JSStateMgmtProfiler::Clear()
139 {
140 rootBlocks_.clear();
141 std::stack<std::shared_ptr<ProfileBlock>> empty;
142 currentBlocks_.swap(empty);
143 }
144 } // namespace OHOS::Ace::Framework