forked from facebook/hermes
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathInlineCacheProfiler.cpp
More file actions
232 lines (207 loc) · 7.3 KB
/
InlineCacheProfiler.cpp
File metadata and controls
232 lines (207 loc) · 7.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#ifdef HERMESVM_PROFILER_BB
#ifndef INLINECACHE_PROFILER_H
#include "hermes/VM/Profiler/InlineCacheProfiler.h"
#include "hermes/Support/Algorithms.h"
#include "hermes/VM/CodeBlock.h"
#include "hermes/VM/Handle.h"
#include "hermes/VM/HiddenClass.h"
#include "hermes/VM/JSArray.h"
#include "hermes/VM/Runtime.h"
#include "hermes/VM/StringView.h"
#include "hermes/VM/SymbolID.h"
#include <iomanip>
#include <sstream>
#include <vector>
namespace hermes {
namespace vm {
InlineCacheProfiler::ICMiss &InlineCacheProfiler::getICMissBySourceLocation(
CodeBlock *codeblock,
uint32_t instOffset) {
// if not exist, create inline caching entry for the source location
ICSrcKey icKey(instOffset, codeblock);
auto it = cacheMisses_.find(icKey);
if (it == cacheMisses_.end()) {
ICMiss icMiss;
auto p = cacheMisses_.try_emplace(icKey, icMiss);
assert(p.second && "Guaranteed to insert");
it = p.first;
}
return it->second;
}
bool InlineCacheProfiler::insertICMiss(
CodeBlock *codeblock,
uint32_t instOffset,
SymbolID &propertyID,
ClassId objectHiddenClassId,
ClassId cachedHiddenClassId) {
ICMiss &icMiss = getICMissBySourceLocation(codeblock, instOffset);
// record the hidden class pair for the source location
auto hcPair =
std::pair<ClassId, ClassId>(objectHiddenClassId, cachedHiddenClassId);
auto icRecord =
std::pair<PropertyId, HiddenClassPair>(propertyID.unsafeGetRaw(), hcPair);
icMiss.insertMiss(icRecord);
++totalMisses_;
return true;
}
bool InlineCacheProfiler::insertICHit(
CodeBlock *codeblock,
uint32_t instOffset) {
// if not exist, create inline caching entry for the source location
ICMiss &icMiss = getICMissBySourceLocation(codeblock, instOffset);
icMiss.incrementHit();
++totalHits_;
return true;
}
JSArray *&InlineCacheProfiler::getHiddenClassArray() {
return cachedHiddenClassesRawPtr_;
}
void InlineCacheProfiler::setHiddenClassArray(JSArray *hiddenClassArray) {
cachedHiddenClassesRawPtr_ = hiddenClassArray;
}
uint32_t &InlineCacheProfiler::getHiddenClassArrayIndex() {
return hcIdx_;
}
llvh::DenseMap<InlineCacheProfiler::ClassId, int32_t>
&InlineCacheProfiler::getClassIdtoIndexMap() {
return classIdToIdx_;
}
void InlineCacheProfiler::dumpHiddenClassProperties(
llvh::raw_ostream &ostream,
HiddenClass *hc,
Runtime *runtime) {
ostream << "\t\t";
if (hc == nullptr) {
ostream << "[none]\n";
return;
}
if (hc->isDictionary()) {
ostream << "[dict] ";
}
ostream << "<";
bool first = true;
HiddenClass::forEachPropertyNoAlloc(
hc,
runtime,
[&ostream, &runtime, &first](
SymbolID symId, NamedPropertyDescriptor desc) {
if (first) {
first = false;
} else {
ostream << ", ";
}
ostream << runtime->convertSymbolToUTF8(symId);
});
ostream << ">\n";
}
std::unique_ptr<InlineCacheProfiler::ICMissList>
InlineCacheProfiler::getRankedInlineCachingMisses() {
std::unique_ptr<InlineCacheProfiler::ICMissList> icInfoList =
std::make_unique<InlineCacheProfiler::ICMissList>();
// rank inline caching miss information
for (auto itr = cacheMisses_.begin(); itr != cacheMisses_.end(); ++itr) {
icInfoList->push_back(*itr);
}
auto compare = [](std::pair<ICSrcKey, ICMiss> &a,
std::pair<ICSrcKey, ICMiss> &b) {
// sort in descending order
return a.second.missCount > b.second.missCount;
};
std::sort(icInfoList->begin(), icInfoList->end(), compare);
return icInfoList;
}
void InlineCacheProfiler::dumpInlineCachingMissRecord(
ICMissKey &icInfo,
uint64_t icMiss,
Runtime *runtime,
llvh::raw_ostream &ostream) {
GCScope gcscope(runtime);
// dump get property name and frequency
auto propSymbolID = SymbolID::unsafeCreate(icInfo.first);
auto propName = runtime->convertSymbolToUTF8(propSymbolID);
ostream << "\tproperty: " << propName << ", inline cache misses: " << icMiss
<< "\n";
// dump the information of hidden class layout to ostream
HiddenClassPair hcPair = icInfo.second;
HiddenClass *objectHiddenClass = runtime->resolveHiddenClassId(hcPair.first);
HiddenClass *cachedHiddenClass = runtime->resolveHiddenClassId(hcPair.second);
dumpHiddenClassProperties(ostream, objectHiddenClass, runtime);
dumpHiddenClassProperties(ostream, cachedHiddenClass, runtime);
ostream << "\n";
ostream.flush();
}
void InlineCacheProfiler::dumpInfoOfSourceLocation(
ICSrcKey &srcLoc,
ICMiss &icMiss,
Runtime *runtime,
llvh::raw_ostream &ostream) {
// get filename, line number, and column number
auto locOrNull = runtime->getIPSourceLocation(
srcLoc.second, srcLoc.second->getOffsetPtr(srcLoc.first));
// output information at the source location
if (locOrNull.hasValue()) {
// output the source location info
auto loc = locOrNull.getValue();
ostream << "[" << std::get<0>(loc) << ":" << std::get<1>(loc) << ":"
<< std::get<2>(loc) << "] ";
// output inline caching statistics
std::stringstream stream;
stream << std::fixed << std::setprecision(1)
<< (1. * icMiss.missCount) / (icMiss.missCount + icMiss.hitCount);
std::string missRatio = stream.str();
ostream << "total access: " << icMiss.missCount + icMiss.hitCount
<< ", miss ratio: " << missRatio << "\n";
} else {
ostream << "[No Loc]\n";
}
}
/// Dumps most frequent inline caching miss source locations and their
/// detailed information, which include inline caching statistics and
/// hidden class layouts at the source location.
/// The source locations are ranked in the descending order of IC misses.
///
/// An example of output for a specific source location is as follows:
/// [filename:line:column] total access: 2661, miss ratio: 0.3
/// property: children, inline cache misses: 427
/// <type, domNamespace, children, childIndex, context, footer>
/// <domNamespace, type, children, childIndex, context, footer>
///
/// property: children, inline cache misses: 427
/// <domNamespace, type, children, childIndex, context, footer>
/// <type, domNamespace, children, childIndex, context, footer>
/// ...
void InlineCacheProfiler::dumpRankedInlineCachingMisses(
Runtime *runtime,
llvh::raw_ostream &ostream) {
// rank the inline caching misses
std::shared_ptr<InlineCacheProfiler::ICMissList> icInfoList =
getRankedInlineCachingMisses();
uint64_t recordPrinted = 0;
// enumerate each source location where inline caching miss happens
for (auto &cacheMissEntry : *icInfoList) {
ICMiss &icMiss = cacheMissEntry.second;
// print only top 10 location
if (recordPrinted++ >= 10) {
break;
}
// dump general information at the source location
ICSrcKey &srcLoc = cacheMissEntry.first;
dumpInfoOfSourceLocation(srcLoc, icMiss, runtime, ostream);
// dump details of each type of inline caching misses at the source location
for (auto &missHCEntry : icMiss.hiddenClasses) {
ICMissKey &icInfo = missHCEntry.first;
uint64_t icMiss = missHCEntry.second;
dumpInlineCachingMissRecord(icInfo, icMiss, runtime, ostream);
}
}
}
} // namespace vm
} // namespace hermes
#endif
#endif