Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(37)

Side by Side Diff: test/cctest/test-heap-profiler.cc

Issue 200132: Add initial version of retainers heap profile. (Closed)
Patch Set: Comments addressed Created 11 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « test/cctest/SConscript ('k') | tools/gyp/v8.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2009 the V8 project authors. All rights reserved.
2 //
3 // Tests for heap profiler
4
5 #ifdef ENABLE_LOGGING_AND_PROFILING
6
7 #include "v8.h"
8 #include "heap-profiler.h"
9 #include "string-stream.h"
10 #include "cctest.h"
11
12 namespace i = v8::internal;
13 using i::ClustersCoarser;
14 using i::JSObjectsCluster;
15 using i::JSObjectsClusterTree;
16 using i::RetainerHeapProfile;
17
18
19 static void CompileAndRunScript(const char *src) {
20 v8::Script::Compile(v8::String::New(src))->Run();
21 }
22
23
24 namespace {
25
26 class ConstructorHeapProfileTestHelper : public i::ConstructorHeapProfile {
27 public:
28 ConstructorHeapProfileTestHelper()
29 : i::ConstructorHeapProfile(),
30 f_name_(i::Factory::NewStringFromAscii(i::CStrVector("F"))),
31 f_count_(0) {
32 }
33
34 void Call(i::String* name, const i::NumberAndSizeInfo& number_and_size) {
35 CHECK(name != NULL);
36 if (f_name_->Equals(name)) {
37 CHECK_EQ(f_count_, 0);
38 f_count_ = number_and_size.number();
39 CHECK_GT(f_count_, 0);
40 }
41 }
42
43 int f_count() { return f_count_; }
44
45 private:
46 i::Handle<i::String> f_name_;
47 int f_count_;
48 };
49
50 } // namespace
51
52
53 TEST(ConstructorProfile) {
54 v8::HandleScope scope;
55 v8::Handle<v8::Context> env = v8::Context::New();
56 env->Enter();
57
58 CompileAndRunScript(
59 "function F() {} // A constructor\n"
60 "var f1 = new F();\n"
61 "var f2 = new F();\n");
62
63 ConstructorHeapProfileTestHelper cons_profile;
64 i::AssertNoAllocation no_alloc;
65 i::HeapIterator iterator;
66 while (iterator.has_next()) {
67 i::HeapObject* obj = iterator.next();
68 cons_profile.CollectStats(obj);
69 }
70 CHECK_EQ(0, cons_profile.f_count());
71 cons_profile.PrintStats();
72 CHECK_EQ(2, cons_profile.f_count());
73 }
74
75
76 static JSObjectsCluster AddHeapObjectToTree(
77 JSObjectsClusterTree* tree,
78 i::String* constructor,
79 int instance,
80 JSObjectsCluster* ref1 = NULL,
81 JSObjectsCluster* ref2 = NULL,
82 JSObjectsCluster* ref3 = NULL) {
83 JSObjectsCluster o(constructor, reinterpret_cast<i::Object*>(instance));
84 JSObjectsClusterTree* o_tree = new JSObjectsClusterTree();
85 JSObjectsClusterTree::Locator loc;
86 if (ref1 != NULL) o_tree->Insert(*ref1, &loc);
87 if (ref2 != NULL) o_tree->Insert(*ref2, &loc);
88 if (ref3 != NULL) o_tree->Insert(*ref3, &loc);
89 tree->Insert(o, &loc);
90 loc.set_value(o_tree);
91 return o;
92 }
93
94
95 static inline void CheckEqualsHelper(const char* file, int line,
96 const char* expected_source,
97 const JSObjectsCluster& expected,
98 const char* value_source,
99 const JSObjectsCluster& value) {
100 if (JSObjectsCluster::Compare(expected, value) != 0) {
101 i::HeapStringAllocator allocator;
102 i::StringStream stream(&allocator);
103 stream.Add("# Expected: ");
104 expected.DebugPrint(&stream);
105 stream.Add("\n# Found: ");
106 value.DebugPrint(&stream);
107 V8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n%s",
108 expected_source, value_source,
109 *stream.ToCString());
110 }
111 }
112
113
114 static inline void CheckNonEqualsHelper(const char* file, int line,
115 const char* expected_source,
116 const JSObjectsCluster& expected,
117 const char* value_source,
118 const JSObjectsCluster& value) {
119 if (JSObjectsCluster::Compare(expected, value) == 0) {
120 i::HeapStringAllocator allocator;
121 i::StringStream stream(&allocator);
122 stream.Add("# Expected: ");
123 expected.DebugPrint(&stream);
124 stream.Add("\n# Found: ");
125 value.DebugPrint(&stream);
126 V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n%s",
127 expected_source, value_source,
128 *stream.ToCString());
129 }
130 }
131
132
133 TEST(ClustersCoarserSimple) {
134 v8::HandleScope scope;
135 v8::Handle<v8::Context> env = v8::Context::New();
136 env->Enter();
137
138 i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
139
140 JSObjectsClusterTree tree;
141 JSObjectsCluster function(i::Heap::function_class_symbol());
142 JSObjectsCluster a(*i::Factory::NewStringFromAscii(i::CStrVector("A")));
143 JSObjectsCluster b(*i::Factory::NewStringFromAscii(i::CStrVector("B")));
144
145 // o1 <- Function
146 JSObjectsCluster o1 =
147 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100, &function);
148 // o2 <- Function
149 JSObjectsCluster o2 =
150 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x200, &function);
151 // o3 <- A, B
152 JSObjectsCluster o3 =
153 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x300, &a, &b);
154 // o4 <- B, A
155 JSObjectsCluster o4 =
156 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x400, &b, &a);
157 // o5 <- A, B, Function
158 JSObjectsCluster o5 =
159 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x500,
160 &a, &b, &function);
161
162 ClustersCoarser coarser;
163 coarser.Process(&tree);
164
165 CHECK_EQ(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o2));
166 CHECK_EQ(coarser.GetCoarseEquivalent(o3), coarser.GetCoarseEquivalent(o4));
167 CHECK_NE(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o3));
168 CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o5));
169 }
170
171
172 TEST(ClustersCoarserMultipleConstructors) {
173 v8::HandleScope scope;
174 v8::Handle<v8::Context> env = v8::Context::New();
175 env->Enter();
176
177 i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
178
179 JSObjectsClusterTree tree;
180 JSObjectsCluster function(i::Heap::function_class_symbol());
181
182 // o1 <- Function
183 JSObjectsCluster o1 =
184 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100, &function);
185 // a1 <- Function
186 JSObjectsCluster a1 =
187 AddHeapObjectToTree(&tree, i::Heap::Array_symbol(), 0x1000, &function);
188 // o2 <- Function
189 JSObjectsCluster o2 =
190 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x200, &function);
191 // a2 <- Function
192 JSObjectsCluster a2 =
193 AddHeapObjectToTree(&tree, i::Heap::Array_symbol(), 0x2000, &function);
194
195 ClustersCoarser coarser;
196 coarser.Process(&tree);
197
198 CHECK_EQ(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o2));
199 CHECK_EQ(coarser.GetCoarseEquivalent(a1), coarser.GetCoarseEquivalent(a2));
200 }
201
202
203 TEST(ClustersCoarserPathsTraversal) {
204 v8::HandleScope scope;
205 v8::Handle<v8::Context> env = v8::Context::New();
206 env->Enter();
207
208 i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
209
210 JSObjectsClusterTree tree;
211
212 // On the following graph:
213 //
214 // p
215 // <- o21 <- o11 <-
216 // q o
217 // <- o22 <- o12 <-
218 // r
219 //
220 // we expect that coarser will deduce equivalences: p ~ q ~ r,
221 // o21 ~ o22, and o11 ~ o12.
222
223 JSObjectsCluster o =
224 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100);
225 JSObjectsCluster o11 =
226 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x110, &o);
227 JSObjectsCluster o12 =
228 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x120, &o);
229 JSObjectsCluster o21 =
230 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x210, &o11);
231 JSObjectsCluster o22 =
232 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x220, &o12);
233 JSObjectsCluster p =
234 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x300, &o21);
235 JSObjectsCluster q =
236 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x310, &o21, &o22);
237 JSObjectsCluster r =
238 AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x320, &o22);
239
240 ClustersCoarser coarser;
241 coarser.Process(&tree);
242
243 CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o));
244 CHECK_EQ(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(o12));
245 CHECK_EQ(coarser.GetCoarseEquivalent(o21), coarser.GetCoarseEquivalent(o22));
246 CHECK_NE(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(o21));
247 CHECK_EQ(coarser.GetCoarseEquivalent(p), coarser.GetCoarseEquivalent(q));
248 CHECK_EQ(coarser.GetCoarseEquivalent(q), coarser.GetCoarseEquivalent(r));
249 CHECK_NE(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(p));
250 CHECK_NE(coarser.GetCoarseEquivalent(o21), coarser.GetCoarseEquivalent(p));
251 }
252
253
254 namespace {
255
256 class RetainerProfilePrinter : public RetainerHeapProfile::Printer {
257 public:
258 RetainerProfilePrinter() : stream_(&allocator_), lines_(100) {}
259
260 void PrintRetainers(const i::StringStream& retainers) {
261 stream_.Add("%s", *(retainers.ToCString()));
262 stream_.Put('\0');
263 }
264
265 const char* GetRetainers(const char* constructor) {
266 FillLines();
267 const size_t cons_len = strlen(constructor);
268 for (int i = 0; i < lines_.length(); ++i) {
269 if (strncmp(constructor, lines_[i], cons_len) == 0 &&
270 lines_[i][cons_len] == ',') {
271 return lines_[i] + cons_len + 1;
272 }
273 }
274 return NULL;
275 }
276
277 private:
278 void FillLines() {
279 if (lines_.length() > 0) return;
280 stream_.Put('\0');
281 stream_str_ = stream_.ToCString();
282 const char* pos = *stream_str_;
283 while (pos != NULL && *pos != '\0') {
284 lines_.Add(pos);
285 pos = strchr(pos, '\0');
286 if (pos != NULL) ++pos;
287 }
288 }
289
290 i::HeapStringAllocator allocator_;
291 i::StringStream stream_;
292 i::SmartPointer<const char> stream_str_;
293 i::List<const char*> lines_;
294 };
295
296 } // namespace
297
298
299 TEST(RetainerProfile) {
300 v8::HandleScope scope;
301 v8::Handle<v8::Context> env = v8::Context::New();
302 env->Enter();
303
304 CompileAndRunScript(
305 "function A() {}\n"
306 "function B(x) { this.x = x; }\n"
307 "var a = new A();\n"
308 "var b = new B(a);\n");
309
310 RetainerHeapProfile ret_profile;
311 i::AssertNoAllocation no_alloc;
312 i::HeapIterator iterator;
313 while (iterator.has_next()) {
314 i::HeapObject* obj = iterator.next();
315 ret_profile.CollectStats(obj);
316 }
317 RetainerProfilePrinter printer;
318 ret_profile.DebugPrintStats(&printer);
319 CHECK_EQ("(global property),B", printer.GetRetainers("A"));
320 CHECK_EQ("(global property)", printer.GetRetainers("B"));
321 }
322
323 #endif // ENABLE_LOGGING_AND_PROFILING
OLDNEW
« no previous file with comments | « test/cctest/SConscript ('k') | tools/gyp/v8.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698