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
16 #include "utils/memory_reporter.h"
17
18 #include <cassert>
19 #include <mutex>
20 #include <sstream>
21 #include <stack>
22
23 #include "hb.h"
24 #include "line_metrics.h"
25 #include "texgine/any_span.h"
26 #include "texgine/dynamic_font_provider.h"
27 #include "texgine/system_font_provider.h"
28 #include "typeface.h"
29 #include "typography_impl.h"
30
31 namespace OHOS {
32 namespace Rosen {
33 namespace TextEngine {
34 //Enable memory test
35 #ifdef TEXGINE_ENABLE_MEMORY
36 class MemoryReporter {
37 public:
38 static MemoryReporter &GetInstance();
39 void Enter(const std::string &scopeType);
40 void Exit();
41 void Report(const std::string &member, double usage);
42
43 private:
44 MemoryReporter() = default;
45 ~MemoryReporter();
46 MemoryReporter(const MemoryReporter &) = delete;
47 MemoryReporter(MemoryReporter &&) = delete;
48 MemoryReporter& operator=(const MemoryReporter &) = delete;
49 MemoryReporter& operator=(MemoryReporter &&) = delete;
50
51 uint64_t now_ = 0;
52 std::vector<std::pair<uint64_t, std::string>> contents_;
53 std::stack<std::string> scopeStack_ = {};
54 };
55
GetInstance()56 MemoryReporter &MemoryReporter::GetInstance()
57 {
58 static MemoryReporter instance;
59 return instance;
60 }
61
Enter(const std::string & scopeType)62 void MemoryReporter::Enter(const std::string &scopeType)
63 {
64 scopeStack_.push(scopeType);
65 contents_.push_back(std::make_pair(now_, "B" + scopeStack_.top()));
66 }
67
Exit()68 void MemoryReporter::Exit()
69 {
70 scopeStack_.pop();
71 contents_.push_back(std::make_pair(now_, "E"));
72 }
73
Report(const std::string & member,double usage)74 void MemoryReporter::Report(const std::string &member, double usage)
75 {
76 contents_.push_back(std::make_pair(now_, "B" + scopeStack_.top() + "::" + member));
77 now_ += usage;
78 contents_.push_back(std::make_pair(now_, "Cusage|" + std::to_string(now_)));
79 contents_.push_back(std::make_pair(now_, "E"));
80 }
81
~MemoryReporter()82 MemoryReporter::~MemoryReporter()
83 {
84 auto fp = fopen("texgine_usage.trace", "w");
85 if (fp == nullptr) {
86 return;
87 }
88
89 fprintf(fp, "# tracer: nop\n");
90 for (const auto &[timeUs, content] : contents_) {
91 fprintf(fp, "texgine-1 (1) [000] .... %.6lf: tracing_mark_write: %c|1|%s\n",
92 timeUs / 1e6, content[0], content.substr(1).c_str());
93 }
94
95 fclose(fp);
96 }
97
MemoryUsageScope(const std::string & name)98 MemoryUsageScope::MemoryUsageScope(const std::string &name)
99 {
100 MemoryReporter::GetInstance().Enter(name);
101 }
102
~MemoryUsageScope()103 MemoryUsageScope::~MemoryUsageScope()
104 {
105 MemoryReporter::GetInstance().Exit();
106 }
107
DoReportMemoryUsage(const std::string & name,int usage)108 void DoReportMemoryUsage(const std::string &name, int usage)
109 {
110 MemoryReporter::GetInstance().Report(name, usage);
111 }
112 #else
113 MemoryUsageScope::MemoryUsageScope(const std::string &name)
114 {
115 }
116
117 MemoryUsageScope::~MemoryUsageScope()
118 {
119 }
120
121 void DoReportMemoryUsage(const std::string &name, int usage)
122 {
123 }
124 #endif
125
DECLARE_RMU(std::string)126 DECLARE_RMU(std::string)
127 {
128 /*
129 * The capacity of string 16, 24 is the the critical value of string type memory usage
130 * If need calculate this pointer:
131 * If the capacity of string less than 16, it`s memory usage is 32
132 * If the capacity of string more than 16 and less than 24, it`s memory usage is 64
133 * If the capacity of string more than 24, it`s memory is 80 + (capacity - 64) / 16 * 16
134 * If don`t need calculate this pointer:
135 * If the capacity of string >= 16 and < 24, it`s memory usage is 32
136 * else it`s memory usage is 32 + (capacity - 24) / 16 * 16
137 */
138 unsigned long fisrtCapacity = 16;
139 unsigned long secondCapacity = 24;
140 unsigned long baseMemory = 16;
141 unsigned long fisrtMemory = 32;
142 unsigned long secondMemory = 64;
143 unsigned long thirdMemory = 80;
144
145 if (needThis) {
146 if (that.capacity() < fisrtCapacity) {
147 DoReportMemoryUsage(member, fisrtMemory);
148 } else if (that.capacity() < secondCapacity) {
149 DoReportMemoryUsage(member, secondMemory);
150 } else {
151 DoReportMemoryUsage(member, thirdMemory + (that.capacity() - secondCapacity) / fisrtCapacity * baseMemory);
152 }
153 return;
154 }
155
156 if (that.capacity() >= fisrtCapacity && that.capacity() < secondCapacity) {
157 DoReportMemoryUsage(member, fisrtMemory);
158 } else {
159 DoReportMemoryUsage(member, fisrtMemory + (that.capacity() - secondCapacity) / fisrtCapacity * baseMemory);
160 }
161 }
162
DECLARE_RMU(struct LineMetrics)163 DECLARE_RMU(struct LineMetrics)
164 {
165 MEMORY_USAGE_SCOPE("LineMetrics", that);
166 MEMORY_USAGE_REPORT(lineSpans);
167 }
168
DECLARE_RMU(struct TypographyStyle)169 DECLARE_RMU(struct TypographyStyle)
170 {
171 MEMORY_USAGE_SCOPE("Typography::Style", that);
172 MEMORY_USAGE_REPORT(fontFamilies);
173 MEMORY_USAGE_REPORT(ellipsis);
174 MEMORY_USAGE_REPORT(lineStyle.fontFamilies);
175 MEMORY_USAGE_REPORT(locale);
176 }
177
DECLARE_RMU(VariantSpan)178 DECLARE_RMU(VariantSpan)
179 {
180 if (auto ts = that.TryToTextSpan(); ts != nullptr) {
181 ReportMemoryUsage(member, *ts, needThis);
182 }
183
184 if (auto as = that.TryToAnySpan(); as != nullptr) {
185 ReportMemoryUsage(member, *as, needThis);
186 }
187 }
188
DECLARE_RMU(AnySpan)189 DECLARE_RMU(AnySpan)
190 {
191 that.ReportMemoryUsage(member, needThis);
192 }
193
DECLARE_CLASS_RMU(AnySpan)194 DECLARE_CLASS_RMU(AnySpan)
195 {
196 MEMORY_USAGE_SCOPE("AnySpan", *this);
197 }
198
DECLARE_RMU(Typography)199 DECLARE_RMU(Typography)
200 {
201 that.ReportMemoryUsage(member, needThis);
202 }
203
DECLARE_CLASS_RMU(TypographyImpl)204 DECLARE_CLASS_RMU(TypographyImpl)
205 {
206 MEMORY_USAGE_SCOPE("TypographyImpl", *this);
207 MEMORY_USAGE_REPORT(lineMetrics_);
208 MEMORY_USAGE_REPORT(typographyStyle_);
209 MEMORY_USAGE_REPORT(spans_);
210 MEMORY_USAGE_REPORT(fontProviders_);
211 }
212
DECLARE_RMU(FontProviders)213 DECLARE_RMU(FontProviders)
214 {
215 MEMORY_USAGE_SCOPE("FontProviders", that);
216 MEMORY_USAGE_REPORT(providers_);
217 MEMORY_USAGE_REPORT(fontStyleSetCache_);
218 }
219
DECLARE_RMU(IFontProvider)220 DECLARE_RMU(IFontProvider)
221 {
222 that.ReportMemoryUsage(member, needThis);
223 }
224
DECLARE_CLASS_RMU(IFontProvider)225 DECLARE_CLASS_RMU(IFontProvider)
226 {
227 MEMORY_USAGE_SCOPE("IFontProvider", *this);
228 }
229
DECLARE_CLASS_RMU(DynamicFontProvider)230 DECLARE_CLASS_RMU(DynamicFontProvider)
231 {
232 MEMORY_USAGE_SCOPE("DynamicFontProvider", *this);
233 MEMORY_USAGE_REPORT(fontStyleSetMap_);
234 }
235
DECLARE_CLASS_RMU(SystemFontProvider)236 DECLARE_CLASS_RMU(SystemFontProvider)
237 {
238 MEMORY_USAGE_SCOPE("SystemFontProvider", *this);
239 }
240
DECLARE_RMU(TextSpan)241 DECLARE_RMU(TextSpan)
242 {
243 MEMORY_USAGE_SCOPE("TextSpan", that);
244 MEMORY_USAGE_REPORT(typeface_);
245 MEMORY_USAGE_REPORT(u16vect_);
246 MEMORY_USAGE_REPORT(glyphWidths_);
247 MEMORY_USAGE_REPORT(cgs_);
248 }
249
DECLARE_RMU(Typeface)250 DECLARE_RMU(Typeface)
251 {
252 MEMORY_USAGE_SCOPE("Typeface", that);
253 MEMORY_USAGE_REPORT(hblob_);
254 MEMORY_USAGE_REPORT(cmapParser_);
255 }
256
DECLARE_RMU(hb_blob_t *)257 DECLARE_RMU(hb_blob_t *)
258 {
259 if (that == nullptr) {
260 return;
261 }
262 DoReportMemoryUsage(member, hb_blob_get_length(const_cast<hb_blob_t *>(that)));
263 }
264
DECLARE_RMU(CharGroups)265 DECLARE_RMU(CharGroups)
266 {
267 MEMORY_USAGE_SCOPE("CharGroups", that);
268 MEMORY_USAGE_REPORT(pcgs_);
269 }
270
DECLARE_RMU(struct TextStyle)271 DECLARE_RMU(struct TextStyle)
272 {
273 MEMORY_USAGE_SCOPE("TextSpan::Style", that);
274 MEMORY_USAGE_REPORT(fontFamilies);
275 MEMORY_USAGE_REPORT(shadows);
276 MEMORY_USAGE_REPORT(fontFeature);
277 }
278
DECLARE_RMU(CmapParser)279 DECLARE_RMU(CmapParser)
280 {
281 MEMORY_USAGE_SCOPE("CmapParser", that);
282 MEMORY_USAGE_REPORT(ranges_);
283 }
284
DECLARE_RMU(CharGroup)285 DECLARE_RMU(CharGroup)
286 {
287 MEMORY_USAGE_SCOPE("CharGroup", that);
288 MEMORY_USAGE_REPORT(chars);
289 MEMORY_USAGE_REPORT(glyphs);
290 MEMORY_USAGE_REPORT(typeface);
291 }
292
DECLARE_RMU(FontFeatures)293 DECLARE_RMU(FontFeatures)
294 {
295 MEMORY_USAGE_SCOPE("FontFeatures", that);
296 MEMORY_USAGE_REPORT(features_);
297 }
298
DECLARE_RMU(Ranges)299 DECLARE_RMU(Ranges)
300 {
301 MEMORY_USAGE_SCOPE("Ranges", that);
302 MEMORY_USAGE_REPORT(ranges_);
303 MEMORY_USAGE_REPORT(singles_);
304 }
305
306 #ifdef TEXGINE_ENABLE_MEMORY
307 DEFINE_RMU(struct Ranges::Range);
308 #endif
309 } // namespace TextEngine
310 } // namespace Rosen
311 } // namespace OHOS
312