OLD | NEW |
---|---|
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/class_table.h" | 5 #include "vm/class_table.h" |
6 #include "vm/flags.h" | 6 #include "vm/flags.h" |
7 #include "vm/freelist.h" | 7 #include "vm/freelist.h" |
8 #include "vm/heap.h" | |
8 #include "vm/object.h" | 9 #include "vm/object.h" |
9 #include "vm/raw_object.h" | 10 #include "vm/raw_object.h" |
10 #include "vm/visitor.h" | 11 #include "vm/visitor.h" |
11 | 12 |
12 namespace dart { | 13 namespace dart { |
13 | 14 |
14 DEFINE_FLAG(bool, print_class_table, false, "Print initial class table."); | 15 DEFINE_FLAG(bool, print_class_table, false, "Print initial class table."); |
15 | 16 |
16 ClassTable::ClassTable() | 17 ClassTable::ClassTable() |
17 : top_(kNumPredefinedCids), capacity_(0), table_(NULL) { | 18 : top_(kNumPredefinedCids), capacity_(0), table_(NULL), |
19 class_heap_stats_table_(NULL), | |
20 predefined_class_heap_stats_table_(NULL) { | |
18 if (Dart::vm_isolate() == NULL) { | 21 if (Dart::vm_isolate() == NULL) { |
19 capacity_ = initial_capacity_; | 22 capacity_ = initial_capacity_; |
20 table_ = reinterpret_cast<RawClass**>( | 23 table_ = reinterpret_cast<RawClass**>( |
21 calloc(capacity_, sizeof(RawClass*))); // NOLINT | 24 calloc(capacity_, sizeof(RawClass*))); // NOLINT |
22 } else { | 25 } else { |
23 // Duplicate the class table from the VM isolate. | 26 // Duplicate the class table from the VM isolate. |
24 ClassTable* vm_class_table = Dart::vm_isolate()->class_table(); | 27 ClassTable* vm_class_table = Dart::vm_isolate()->class_table(); |
25 capacity_ = vm_class_table->capacity_; | 28 capacity_ = vm_class_table->capacity_; |
26 table_ = reinterpret_cast<RawClass**>( | 29 table_ = reinterpret_cast<RawClass**>( |
27 calloc(capacity_, sizeof(RawClass*))); // NOLINT | 30 calloc(capacity_, sizeof(RawClass*))); // NOLINT |
28 for (intptr_t i = kObjectCid; i < kInstanceCid; i++) { | 31 for (intptr_t i = kObjectCid; i < kInstanceCid; i++) { |
29 table_[i] = vm_class_table->At(i); | 32 table_[i] = vm_class_table->At(i); |
30 } | 33 } |
31 table_[kFreeListElement] = vm_class_table->At(kFreeListElement); | 34 table_[kFreeListElement] = vm_class_table->At(kFreeListElement); |
32 table_[kDynamicCid] = vm_class_table->At(kDynamicCid); | 35 table_[kDynamicCid] = vm_class_table->At(kDynamicCid); |
33 table_[kVoidCid] = vm_class_table->At(kVoidCid); | 36 table_[kVoidCid] = vm_class_table->At(kVoidCid); |
37 class_heap_stats_table_ = reinterpret_cast<ClassHeapStats*>( | |
38 calloc(capacity_, sizeof(ClassHeapStats))); // NOLINT | |
39 for (intptr_t i = 0; i < capacity_; i++) { | |
40 class_heap_stats_table_[i].Initialize(); | |
41 } | |
42 } | |
43 predefined_class_heap_stats_table_ = reinterpret_cast<ClassHeapStats*>( | |
44 calloc(kNumPredefinedCids, sizeof(ClassHeapStats))); // NOLINT | |
45 for (intptr_t i = 0; i < kNumPredefinedCids; i++) { | |
46 predefined_class_heap_stats_table_[i].Initialize(); | |
34 } | 47 } |
35 } | 48 } |
36 | 49 |
37 | 50 |
38 ClassTable::~ClassTable() { | 51 ClassTable::~ClassTable() { |
39 free(table_); | 52 free(table_); |
53 free(predefined_class_heap_stats_table_); | |
54 free(class_heap_stats_table_); | |
40 } | 55 } |
41 | 56 |
42 | 57 |
43 void ClassTable::Register(const Class& cls) { | 58 void ClassTable::Register(const Class& cls) { |
44 intptr_t index = cls.id(); | 59 intptr_t index = cls.id(); |
45 if (index != kIllegalCid) { | 60 if (index != kIllegalCid) { |
46 ASSERT(index > 0); | 61 ASSERT(index > 0); |
47 ASSERT(index < kNumPredefinedCids); | 62 ASSERT(index < kNumPredefinedCids); |
48 ASSERT(table_[index] == 0); | 63 ASSERT(table_[index] == 0); |
49 ASSERT(index < capacity_); | 64 ASSERT(index < capacity_); |
50 table_[index] = cls.raw(); | 65 table_[index] = cls.raw(); |
51 // Add the vtable for this predefined class into the static vtable registry | 66 // Add the vtable for this predefined class into the static vtable registry |
52 // if it has not been setup yet. | 67 // if it has not been setup yet. |
53 cpp_vtable cls_vtable = cls.handle_vtable(); | 68 cpp_vtable cls_vtable = cls.handle_vtable(); |
54 cpp_vtable table_entry = Object::builtin_vtables_[index]; | 69 cpp_vtable table_entry = Object::builtin_vtables_[index]; |
55 ASSERT((table_entry == 0) || (table_entry == cls_vtable)); | 70 ASSERT((table_entry == 0) || (table_entry == cls_vtable)); |
56 if (table_entry == 0) { | 71 if (table_entry == 0) { |
57 Object::builtin_vtables_[index] = cls_vtable; | 72 Object::builtin_vtables_[index] = cls_vtable; |
58 } | 73 } |
59 } else { | 74 } else { |
60 if (top_ == capacity_) { | 75 if (top_ == capacity_) { |
61 // Grow the capacity of the class table. | 76 // Grow the capacity of the class table. |
62 intptr_t new_capacity = capacity_ + capacity_increment_; | 77 intptr_t new_capacity = capacity_ + capacity_increment_; |
63 RawClass** new_table = reinterpret_cast<RawClass**>( | 78 RawClass** new_table = reinterpret_cast<RawClass**>( |
64 realloc(table_, new_capacity * sizeof(RawClass*))); // NOLINT | 79 realloc(table_, new_capacity * sizeof(RawClass*))); // NOLINT |
80 ClassHeapStats* new_stats_table = reinterpret_cast<ClassHeapStats*>( | |
81 realloc(class_heap_stats_table_, | |
82 new_capacity * sizeof(ClassHeapStats))); // NOLINT | |
65 for (intptr_t i = capacity_; i < new_capacity; i++) { | 83 for (intptr_t i = capacity_; i < new_capacity; i++) { |
66 new_table[i] = NULL; | 84 new_table[i] = NULL; |
85 new_stats_table[i].Initialize(); | |
67 } | 86 } |
68 capacity_ = new_capacity; | 87 capacity_ = new_capacity; |
69 table_ = new_table; | 88 table_ = new_table; |
89 class_heap_stats_table_ = new_stats_table; | |
70 } | 90 } |
71 ASSERT(top_ < capacity_); | 91 ASSERT(top_ < capacity_); |
72 cls.set_id(top_); | 92 cls.set_id(top_); |
73 table_[top_] = cls.raw(); | 93 table_[top_] = cls.raw(); |
74 top_++; // Increment next index. | 94 top_++; // Increment next index. |
75 } | 95 } |
76 } | 96 } |
77 | 97 |
78 | 98 |
79 void ClassTable::VisitObjectPointers(ObjectPointerVisitor* visitor) { | 99 void ClassTable::VisitObjectPointers(ObjectPointerVisitor* visitor) { |
(...skipping 24 matching lines...) Expand all Loading... | |
104 JSONArray members(&jsobj, "members"); | 124 JSONArray members(&jsobj, "members"); |
105 for (intptr_t i = 1; i < top_; i++) { | 125 for (intptr_t i = 1; i < top_; i++) { |
106 if (HasValidClassAt(i)) { | 126 if (HasValidClassAt(i)) { |
107 cls = At(i); | 127 cls = At(i); |
108 members.AddValue(cls); | 128 members.AddValue(cls); |
109 } | 129 } |
110 } | 130 } |
111 } | 131 } |
112 } | 132 } |
113 | 133 |
134 | |
135 void ClassHeapStats::Initialize() { | |
136 allocated_before_gc_old_space = 0; | |
137 allocated_before_gc_new_space = 0; | |
138 allocated_size_before_gc_old_space = 0; | |
139 allocated_size_before_gc_new_space = 0; | |
140 live_after_gc_old_space = 0; | |
141 live_after_gc_new_space = 0; | |
142 live_size_after_gc_old_space = 0; | |
143 live_size_after_gc_new_space = 0; | |
144 allocated_since_gc_new_space = 0; | |
145 allocated_since_gc_old_space = 0; | |
146 allocated_size_since_gc_new_space = 0; | |
147 allocated_size_since_gc_old_space = 0; | |
148 } | |
149 | |
150 | |
151 void ClassHeapStats::ResetAtNewGC() { | |
152 allocated_before_gc_new_space = live_after_gc_new_space + | |
153 allocated_since_gc_new_space; | |
154 allocated_size_before_gc_new_space = live_size_after_gc_new_space + | |
155 allocated_size_since_gc_new_space; | |
156 live_after_gc_new_space = 0; | |
157 live_size_after_gc_new_space = 0; | |
158 allocated_since_gc_new_space = 0; | |
159 allocated_size_since_gc_new_space = 0; | |
160 } | |
161 | |
162 | |
163 void ClassHeapStats::ResetAtOldGC() { | |
164 allocated_before_gc_old_space = live_after_gc_old_space + | |
165 allocated_since_gc_old_space; | |
166 allocated_size_before_gc_old_space = live_size_after_gc_old_space + | |
167 allocated_size_since_gc_old_space; | |
168 live_after_gc_old_space = 0; | |
169 live_size_after_gc_old_space = 0; | |
170 allocated_since_gc_old_space = 0; | |
171 allocated_size_since_gc_old_space = 0; | |
172 } | |
173 | |
174 | |
175 void ClassHeapStats::UpdateSize(intptr_t instance_size) { | |
176 ASSERT(instance_size > 0); | |
177 // For classes with fixed instance size we do not emit code to update | |
178 // the size statistics. Update them here. | |
179 allocated_size_before_gc_old_space = | |
180 allocated_before_gc_old_space * instance_size; | |
181 allocated_size_before_gc_new_space = | |
182 allocated_before_gc_new_space * instance_size; | |
183 live_size_after_gc_old_space = | |
184 live_after_gc_old_space * instance_size; | |
185 live_size_after_gc_new_space = | |
186 live_after_gc_new_space * instance_size; | |
187 allocated_size_since_gc_new_space = | |
188 allocated_since_gc_new_space * instance_size; | |
189 allocated_size_since_gc_old_space = | |
190 allocated_since_gc_old_space * instance_size; | |
191 } | |
192 | |
193 | |
194 void ClassHeapStats::PrintTOJSONArray(const Class& cls, JSONArray* array) { | |
195 JSONObject obj(array); | |
196 obj.AddProperty("type", "ClassHeapStats"); | |
197 obj.AddProperty("class", cls); | |
198 { | |
199 JSONArray new_stats(&obj, "new"); | |
200 new_stats.AddValue(allocated_before_gc_new_space); | |
201 new_stats.AddValue(allocated_size_before_gc_new_space); | |
202 new_stats.AddValue(live_after_gc_new_space); | |
203 new_stats.AddValue(live_size_after_gc_new_space); | |
204 new_stats.AddValue(allocated_since_gc_new_space); | |
205 new_stats.AddValue(allocated_size_since_gc_new_space); | |
206 } | |
207 { | |
208 JSONArray old_stats(&obj, "old"); | |
209 old_stats.AddValue(allocated_before_gc_old_space); | |
210 old_stats.AddValue(allocated_size_before_gc_old_space); | |
211 old_stats.AddValue(live_after_gc_old_space); | |
212 old_stats.AddValue(live_size_after_gc_old_space); | |
213 old_stats.AddValue(allocated_since_gc_old_space); | |
214 old_stats.AddValue(allocated_size_since_gc_old_space); | |
215 } | |
216 } | |
217 | |
218 | |
219 void ClassTable::UpdateAllocatedNew(intptr_t cid, intptr_t size) { | |
220 ClassHeapStats* stats = StatsAt(cid); | |
221 ASSERT(stats != NULL); | |
222 ASSERT(size != 0); | |
223 stats->allocated_since_gc_new_space++; | |
224 stats->allocated_size_since_gc_new_space += size; | |
225 } | |
226 | |
227 | |
228 void ClassTable::UpdateAllocatedOld(intptr_t cid, intptr_t size) { | |
229 ClassHeapStats* stats = StatsAt(cid); | |
230 ASSERT(stats != NULL); | |
231 ASSERT(size != 0); | |
232 stats->allocated_since_gc_old_space++; | |
233 stats->allocated_size_since_gc_old_space += size; | |
234 } | |
235 | |
236 | |
237 // #define DEBUG_PRINT | |
Ivan Posva
2014/01/17 06:53:16
Debugging code should go.
Cutch
2014/01/17 18:37:59
Done.
| |
238 | |
239 #if defined(DEBUG_PRINT) | |
240 static void PrintClassHeapStats(intptr_t cid, const ClassHeapStats& stat) { | |
241 int new_new = static_cast<int>(stat.new_count_since_gc_new_space); | |
242 int new_old = static_cast<int>(stat.new_count_since_gc_old_space); | |
243 int b_new = static_cast<int>(stat.new_size_since_gc_new_space); | |
244 int b_old = static_cast<int>(stat.new_size_since_gc_old_space); | |
245 printf("%d (%d %d) [%d %d]\n", static_cast<int>(cid), | |
246 new_new, b_new, new_old, b_old); | |
247 } | |
248 #endif | |
249 | |
250 | |
251 bool ClassTable::CollectInstanceSizesForClass(intptr_t cid) { | |
Ivan Posva
2014/01/17 06:53:16
We have other lists of class ids in raw_object, fo
Cutch
2014/01/17 18:37:59
Done.
| |
252 // We only collect size information for classes which do not have | |
253 // fixed lengths. | |
254 if ((cid == kArrayCid) || | |
255 (cid == kImmutableArrayCid) || | |
256 RawObject::IsOneByteStringClassId(cid) || | |
257 RawObject::IsTwoByteStringClassId(cid) || | |
258 RawObject::IsTypedDataClassId(cid) || | |
259 (cid == kContextCid) || | |
260 (cid == kTypeArgumentsCid) || | |
261 (cid == kInstructionsCid) || | |
262 (cid == kPcDescriptorsCid) || | |
263 (cid == kStackmapCid) || | |
264 (cid == kLocalVarDescriptorsCid) || | |
265 (cid == kExceptionHandlersCid) || | |
266 (cid == kDeoptInfoCid) || | |
267 (cid == kCodeCid) || | |
268 (cid == kContextScopeCid) || | |
269 (cid == kInstanceCid) || | |
270 (cid == kBigintCid) || | |
271 (cid == kJSRegExpCid) || | |
272 (cid == kSmiCid)) { | |
Ivan Posva
2014/01/17 06:53:16
SmiCid is definitely not variable in size.
| |
273 return true; | |
274 } | |
275 return false; | |
276 } | |
277 | |
278 | |
279 ClassHeapStats* ClassTable::StatsAt(intptr_t cid) { | |
280 ASSERT(cid > 0); | |
281 if (cid < kNumPredefinedCids) { | |
282 return &predefined_class_heap_stats_table_[cid]; | |
283 } | |
284 ASSERT(cid < top_); | |
285 return &class_heap_stats_table_[cid]; | |
286 } | |
287 | |
288 | |
289 void ClassTable::ResetCountersOld() { | |
290 for (intptr_t i = 0; i < kNumPredefinedCids; i++) { | |
291 predefined_class_heap_stats_table_[i].ResetAtOldGC(); | |
292 } | |
293 for (intptr_t i = kNumPredefinedCids; i < top_; i++) { | |
294 class_heap_stats_table_[i].ResetAtOldGC(); | |
295 } | |
296 } | |
297 | |
298 | |
299 void ClassTable::ResetCountersNew() { | |
300 for (intptr_t i = 0; i < kNumPredefinedCids; i++) { | |
301 predefined_class_heap_stats_table_[i].ResetAtNewGC(); | |
302 } | |
303 for (intptr_t i = kNumPredefinedCids; i < top_; i++) { | |
304 class_heap_stats_table_[i].ResetAtNewGC(); | |
305 } | |
306 } | |
307 | |
308 | |
309 void ClassTable::HeapPrintToJSONStream(JSONStream* stream) { | |
310 Isolate* isolate = Isolate::Current(); | |
311 ASSERT(isolate != NULL); | |
312 Heap* heap = isolate->heap(); | |
313 ASSERT(heap != NULL); | |
314 JSONObject obj(stream); | |
315 obj.AddProperty("type", "HeapProfile"); | |
316 { | |
317 JSONObject heaps(&obj, "heap"); | |
Ivan Posva
2014/01/17 06:53:16
The heap should print itself here at least as a re
| |
318 { | |
319 JSONObject space(&heaps, "new"); | |
320 space.AddProperty("collections", heap->Collections(Heap::kNew)); | |
321 space.AddProperty("used", heap->UsedInWords(Heap::kNew) * kWordSize); | |
322 space.AddProperty("capacity", | |
323 heap->CapacityInWords(Heap::kNew) * kWordSize); | |
324 space.AddProperty("time", heap->GCTimeInSeconds(Heap::kNew)); | |
325 } | |
326 { | |
327 JSONObject space(&heaps, "old"); | |
328 space.AddProperty("collections", heap->Collections(Heap::kOld)); | |
329 space.AddProperty("used", heap->UsedInWords(Heap::kOld) * kWordSize); | |
330 space.AddProperty("capacity", | |
331 heap->CapacityInWords(Heap::kOld) * kWordSize); | |
332 space.AddProperty("time", heap->GCTimeInSeconds(Heap::kOld)); | |
333 } | |
334 } | |
335 { | |
336 Class& cls = Class::Handle(); | |
337 JSONArray arr(&obj, "members"); | |
338 for (intptr_t i = 1; i < kNumPredefinedCids; i++) { | |
339 if (!HasValidClassAt(i) || (i == kFreeListElement)) { | |
340 continue; | |
341 } | |
342 cls = At(i); | |
343 if (!(cls.is_finalized() || cls.is_prefinalized())) { | |
344 // Not finalized. | |
345 continue; | |
346 } | |
347 if (!CollectInstanceSizesForClass(i)) { | |
348 predefined_class_heap_stats_table_[i].UpdateSize(cls.instance_size()); | |
349 } | |
350 predefined_class_heap_stats_table_[i].PrintTOJSONArray(cls, &arr); | |
351 } | |
352 for (intptr_t i = kNumPredefinedCids; i < top_; i++) { | |
353 if (!HasValidClassAt(i)) { | |
354 continue; | |
355 } | |
356 cls = At(i); | |
357 if (!(cls.is_finalized() || cls.is_prefinalized())) { | |
358 // Not finalized. | |
359 continue; | |
360 } | |
361 if (!CollectInstanceSizesForClass(i)) { | |
362 class_heap_stats_table_[i].UpdateSize(cls.instance_size()); | |
363 } | |
364 class_heap_stats_table_[i].PrintTOJSONArray(cls, &arr); | |
365 } | |
366 } | |
367 } | |
368 | |
369 | |
370 void ClassTable::UpdateLiveOld(intptr_t cid, intptr_t size) { | |
371 ClassHeapStats* stats = StatsAt(cid); | |
372 ASSERT(stats != NULL); | |
373 ASSERT(size > 0); | |
374 stats->live_after_gc_old_space++; | |
375 stats->live_size_after_gc_old_space += size; | |
376 } | |
377 | |
378 | |
379 void ClassTable::UpdateLiveNew(intptr_t cid, intptr_t size) { | |
380 ClassHeapStats* stats = StatsAt(cid); | |
381 ASSERT(stats != NULL); | |
382 ASSERT(size > 0); | |
383 stats->live_after_gc_new_space++; | |
384 stats->live_size_after_gc_new_space += size; | |
385 } | |
386 | |
387 | |
114 } // namespace dart | 388 } // namespace dart |
OLD | NEW |