• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 #ifndef ECMASCRIPT_PGO_PROFILER_PGO_TRACE_H
17 #define ECMASCRIPT_PGO_PROFILER_PGO_TRACE_H
18 
19 #include <iomanip>
20 #include <memory>
21 #include <numeric>
22 #include <unordered_map>
23 
24 #include "ecmascript/method.h"
25 
26 namespace panda::ecmascript::pgo {
27 class PGOTrace {
28 public:
29     static constexpr int NAME_WIDTH = 40;
30     static constexpr int WIDTH = 20;
31     static constexpr int COLUMN_WIDTH = NAME_WIDTH + WIDTH * 6;
32     static constexpr const char* TITLE_TEXT = " PGO Trace ";
33     static constexpr const float MIN_PRINT_TIME = 10.0;
34     static constexpr const int MIN_PRINT_COUNT = 10;
35     static constexpr const int PRECISION = 3;
36     static constexpr const int TOTAL_COLUMN = 6;
37     static constexpr const int PROFILE_BYTECODE_TIME_COLUMN = 2;
38 
Title()39     static std::string Title()
40     {
41         int halfWidth = (COLUMN_WIDTH - std::strlen(TITLE_TEXT)) / 2 + 1;
42         return std::string(halfWidth, '=') + TITLE_TEXT + std::string(halfWidth, '=');
43     }
44 
Separator()45     static std::string Separator()
46     {
47         return std::string(Title().length(), '=');
48     }
49 
GetInstance()50     static std::shared_ptr<PGOTrace> GetInstance()
51     {
52         static auto trace = std::make_shared<PGOTrace>();
53         return trace;
54     }
55 
SetEnable(bool enable)56     void SetEnable(bool enable)
57     {
58         LOG_PGO(DEBUG) << "pgo trace is " << (enable ? "enabled" : "disabled");
59         enable_ = enable;
60     }
61 
IsEnable()62     bool IsEnable() const
63     {
64         return enable_;
65     }
66 
67     class MethodData {
68     public:
MethodData(JSTaggedValue value,bool hotness)69         MethodData(JSTaggedValue value, bool hotness)
70         {
71             Method* method = Method::Cast(value);
72             name_ = method->GetMethodName();
73             id_ = method->GetMethodId();
74             codesize_ = method->GetCodeSize();
75             hotness_ = hotness;
76         }
77 
GetId()78         EntityId GetId() const
79         {
80             return id_;
81         }
82 
SetProfileBytecodeTime(float time)83         void SetProfileBytecodeTime(float time)
84         {
85             profileBytecodeTime_.push_back(time);
86         }
87 
Print()88         void Print() const
89         {
90             float totalTime = std::accumulate(profileBytecodeTime_.begin(), profileBytecodeTime_.end(), 0.0);
91             float count = profileBytecodeTime_.size();
92 #if defined(PANDA_TARGET_OHOS) && !defined(STANDALONE_MODE)
93             if (totalTime < MIN_PRINT_TIME && count < MIN_PRINT_COUNT) {
94                 return;
95             }
96 #endif
97             if (count <= 0) {
98                 return;
99             }
100             float avgProfileBytecodeTime = totalTime / count;
101             LOG_TRACE(INFO) << std::left << std::setw(NAME_WIDTH) << name_ << std::right << std::setw(WIDTH) << id_
102                             << std::setw(WIDTH) << codesize_ << std::setw(WIDTH) << hotness_ << std::setw(WIDTH)
103                             << count << std::fixed << std::setprecision(PRECISION) << std::setw(WIDTH)
104                             << avgProfileBytecodeTime << std::setw(WIDTH) << totalTime;
105         }
106 
SetHotness(bool hotness)107         void SetHotness(bool hotness)
108         {
109             hotness_ = hotness;
110         }
111 
112     private:
113         const char* name_;
114         EntityId id_;
115         uint32_t codesize_;
116         std::list<float> profileBytecodeTime_;
117         bool hotness_;
118     };
119 
GetMethodData(EntityId id)120     MethodData* GetMethodData(EntityId id)
121     {
122         auto iter = methods.find(id);
123         if (iter == methods.end()) {
124             return nullptr;
125         }
126         return &(iter->second);
127     }
128 
129     MethodData* TryGetMethodData(JSTaggedValue value, bool hotness = false)
130     {
131         MethodData method(value, hotness);
132         auto data = GetMethodData(method.GetId());
133         if (data) {
134             data->SetHotness(hotness);
135             return data;
136         } else {
137             auto res = methods.emplace(method.GetId(), method);
138             return &(res.first->second);
139         }
140     }
141 
Print()142     void Print() const
143     {
144         LOG_TRACE(INFO) << "only print methods which (total time > 10 ms || count > 10) on ohos device";
145         LOG_TRACE(INFO) << Title();
146         LOG_TRACE(INFO) << std::setw(NAME_WIDTH + WIDTH * (TOTAL_COLUMN - PROFILE_BYTECODE_TIME_COLUMN)) << ""
147                         << std::right << std::setw(WIDTH * PROFILE_BYTECODE_TIME_COLUMN) << "Profile Bytecode Time(ms)";
148         LOG_TRACE(INFO) << std::left << std::setw(NAME_WIDTH) << "Name" << std::right << std::setw(WIDTH) << "Id"
149                         << std::setw(WIDTH) << "CodeSize" << std::setw(WIDTH) << "Hotness" << std::setw(WIDTH)
150                         << "Count" << std::setw(WIDTH) << "Avg(ms)" << std::setw(WIDTH) << "Total(ms)";
151         for (auto& [id, method]: methods) {
152             method.Print();
153         }
154         LOG_TRACE(INFO) << Separator();
155         LOG_TRACE(INFO) << std::left << std::setw(NAME_WIDTH) << "MergeWithExistAP(ms) " << mergeWithExistProfileTime_;
156         LOG_TRACE(INFO) << std::left << std::setw(NAME_WIDTH) << "SaveAndRename(ms) " << saveTime_;
157         LOG_TRACE(INFO) << Separator();
158     }
159 
SetSaveTime(float time)160     void SetSaveTime(float time)
161     {
162         saveTime_ = time;
163     }
164 
SetMergeWithExistProfileTime(float time)165     void SetMergeWithExistProfileTime(float time)
166     {
167         mergeWithExistProfileTime_ = time;
168     }
169 
170 private:
171     std::unordered_map<EntityId, MethodData> methods;
172     float mergeWithExistProfileTime_;
173     float saveTime_;
174     bool enable_ {false};
175 };
176 } // namespace panda::ecmascript::pgo
177 #endif // ECMASCRIPT_PGO_PROFILER_PGO_TRACE_H