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

Side by Side Diff: src/heap/object-stats.cc

Issue 2147693004: [heap] ObjectStats: Fix accounting for fixed array subtypes (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Filter out dupes Created 4 years, 5 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
OLDNEW
1 // Copyright 2015 the V8 project authors. All rights reserved. 1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/heap/object-stats.h" 5 #include "src/heap/object-stats.h"
6 6
7 #include "src/counters.h" 7 #include "src/counters.h"
8 #include "src/heap/heap-inl.h" 8 #include "src/heap/heap-inl.h"
9 #include "src/isolate.h" 9 #include "src/isolate.h"
10 #include "src/utils.h" 10 #include "src/utils.h"
11 11
12 namespace v8 { 12 namespace v8 {
13 namespace internal { 13 namespace internal {
14 14
15 static base::LazyMutex object_stats_mutex = LAZY_MUTEX_INITIALIZER; 15 static base::LazyMutex object_stats_mutex = LAZY_MUTEX_INITIALIZER;
16 16
17 17
18 void ObjectStats::ClearObjectStats(bool clear_last_time_stats) { 18 void ObjectStats::ClearObjectStats(bool clear_last_time_stats) {
19 memset(object_counts_, 0, sizeof(object_counts_)); 19 memset(object_counts_, 0, sizeof(object_counts_));
20 memset(object_sizes_, 0, sizeof(object_sizes_)); 20 memset(object_sizes_, 0, sizeof(object_sizes_));
21 memset(over_allocated_, 0, sizeof(over_allocated_)); 21 memset(over_allocated_, 0, sizeof(over_allocated_));
22 memset(size_histogram_, 0, sizeof(size_histogram_)); 22 memset(size_histogram_, 0, sizeof(size_histogram_));
23 memset(over_allocated_histogram_, 0, sizeof(over_allocated_histogram_)); 23 memset(over_allocated_histogram_, 0, sizeof(over_allocated_histogram_));
24 if (clear_last_time_stats) { 24 if (clear_last_time_stats) {
25 memset(object_counts_last_time_, 0, sizeof(object_counts_last_time_)); 25 memset(object_counts_last_time_, 0, sizeof(object_counts_last_time_));
26 memset(object_sizes_last_time_, 0, sizeof(object_sizes_last_time_)); 26 memset(object_sizes_last_time_, 0, sizeof(object_sizes_last_time_));
27 } 27 }
28 visited_fixed_array_sub_types_.clear();
28 } 29 }
29 30
30 static void PrintJSONArray(size_t* array, const int len) { 31 static void PrintJSONArray(size_t* array, const int len) {
31 PrintF("[ "); 32 PrintF("[ ");
32 for (int i = 0; i < len; i++) { 33 for (int i = 0; i < len; i++) {
33 PrintF("%zu", array[i]); 34 PrintF("%zu", array[i]);
34 if (i != (len - 1)) PrintF(", "); 35 if (i != (len - 1)) PrintF(", ");
35 } 36 }
36 PrintF(" ]"); 37 PrintF(" ]");
37 } 38 }
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
183 } 184 }
184 if (obj->IsJSObject()) { 185 if (obj->IsJSObject()) {
185 RecordJSObjectDetails(stats, heap, JSObject::cast(obj)); 186 RecordJSObjectDetails(stats, heap, JSObject::cast(obj));
186 } 187 }
187 if (obj->IsJSWeakCollection()) { 188 if (obj->IsJSWeakCollection()) {
188 RecordJSWeakCollectionDetails(stats, heap, JSWeakCollection::cast(obj)); 189 RecordJSWeakCollectionDetails(stats, heap, JSWeakCollection::cast(obj));
189 } 190 }
190 } 191 }
191 192
192 static bool CanRecordFixedArray(Heap* heap, FixedArrayBase* array) { 193 static bool CanRecordFixedArray(Heap* heap, FixedArrayBase* array) {
193 return array->map() != heap->fixed_cow_array_map() && 194 return array->map()->instance_type() == FIXED_ARRAY_TYPE &&
195 array->map() != heap->fixed_cow_array_map() &&
194 array->map() != heap->fixed_double_array_map() && 196 array->map() != heap->fixed_double_array_map() &&
195 array != heap->empty_fixed_array(); 197 array != heap->empty_fixed_array() &&
198 array != heap->empty_byte_array() &&
199 array != heap->empty_literals_array() &&
200 array != heap->empty_sloppy_arguments_elements() &&
201 array != heap->empty_slow_element_dictionary() &&
202 array != heap->empty_descriptor_array() &&
203 array != heap->empty_properties_dictionary();
204 }
205
206 static bool SameLiveness(HeapObject* obj1, HeapObject* obj2) {
207 return ObjectMarking::Color(obj1) == ObjectMarking::Color(obj2);
208 }
209
210 void ObjectStatsCollector::RecordFixedArrayHelper(
211 ObjectStats* stats, Heap* heap, HeapObject* parent, FixedArray* array,
212 int subtype, size_t overhead) {
213 if (SameLiveness(parent, array) && CanRecordFixedArray(heap, array)) {
214 stats->RecordFixedArraySubTypeStats(array, subtype, array->Size(),
215 overhead);
216 }
196 } 217 }
197 218
198 void ObjectStatsCollector::RecordJSObjectDetails(ObjectStats* stats, Heap* heap, 219 void ObjectStatsCollector::RecordJSObjectDetails(ObjectStats* stats, Heap* heap,
199 JSObject* object) { 220 JSObject* object) {
200 DCHECK(object->IsJSObject()); 221 DCHECK(object->IsJSObject());
201 222
202 size_t overhead = 0; 223 size_t overhead = 0;
203 FixedArrayBase* elements = object->elements(); 224 FixedArrayBase* elements = object->elements();
204 if (CanRecordFixedArray(heap, elements)) { 225 if (CanRecordFixedArray(heap, elements)) {
205 if (elements->IsDictionary()) { 226 if (elements->IsDictionary() && SameLiveness(object, elements)) {
206 SeededNumberDictionary* dict = object->element_dictionary(); 227 SeededNumberDictionary* dict = SeededNumberDictionary::cast(elements);
207 int used = dict->NumberOfElements() * SeededNumberDictionary::kEntrySize; 228 int used = dict->NumberOfElements() * SeededNumberDictionary::kEntrySize;
208 CHECK_GE(elements->Size(), used); 229 CHECK_GE(elements->Size(), used);
209 overhead = elements->Size() - used; 230 overhead = elements->Size() - used;
210 stats->RecordFixedArraySubTypeStats(DICTIONARY_ELEMENTS_SUB_TYPE, 231 stats->RecordFixedArraySubTypeStats(
211 elements->Size(), overhead); 232 elements, DICTIONARY_ELEMENTS_SUB_TYPE, elements->Size(), overhead);
212 } else { 233 } else {
213 if (IsFastHoleyElementsKind(object->GetElementsKind())) { 234 if (IsFastHoleyElementsKind(object->GetElementsKind())) {
214 int used = object->GetFastElementsUsage() * kPointerSize; 235 int used = object->GetFastElementsUsage() * kPointerSize;
215 if (object->GetElementsKind() == FAST_HOLEY_DOUBLE_ELEMENTS) used *= 2; 236 if (object->GetElementsKind() == FAST_HOLEY_DOUBLE_ELEMENTS) used *= 2;
216 CHECK_GE(elements->Size(), used); 237 CHECK_GE(elements->Size(), used);
217 overhead = elements->Size() - used; 238 overhead = elements->Size() - used;
218 } 239 }
219 stats->RecordFixedArraySubTypeStats(FAST_ELEMENTS_SUB_TYPE, 240 stats->RecordFixedArraySubTypeStats(elements, FAST_ELEMENTS_SUB_TYPE,
220 elements->Size(), overhead); 241 elements->Size(), overhead);
221 } 242 }
222 } 243 }
223 244
224 overhead = 0; 245 overhead = 0;
225 FixedArrayBase* properties = object->properties(); 246 FixedArrayBase* properties = object->properties();
226 if (CanRecordFixedArray(heap, properties)) { 247 if (CanRecordFixedArray(heap, properties) &&
248 SameLiveness(object, properties)) {
227 if (properties->IsDictionary()) { 249 if (properties->IsDictionary()) {
228 NameDictionary* dict = object->property_dictionary(); 250 NameDictionary* dict = NameDictionary::cast(properties);
229 int used = dict->NumberOfElements() * NameDictionary::kEntrySize; 251 int used = dict->NumberOfElements() * NameDictionary::kEntrySize;
230 CHECK_GE(properties->Size(), used); 252 CHECK_GE(properties->Size(), used);
231 overhead = properties->Size() - used; 253 overhead = properties->Size() - used;
232 stats->RecordFixedArraySubTypeStats(DICTIONARY_PROPERTIES_SUB_TYPE, 254 stats->RecordFixedArraySubTypeStats(properties,
255 DICTIONARY_PROPERTIES_SUB_TYPE,
233 properties->Size(), overhead); 256 properties->Size(), overhead);
234 } else { 257 } else {
235 stats->RecordFixedArraySubTypeStats(FAST_PROPERTIES_SUB_TYPE, 258 stats->RecordFixedArraySubTypeStats(properties, FAST_PROPERTIES_SUB_TYPE,
236 properties->Size(), overhead); 259 properties->Size(), overhead);
237 } 260 }
238 } 261 }
239 } 262 }
240 263
241 void ObjectStatsCollector::RecordJSWeakCollectionDetails( 264 void ObjectStatsCollector::RecordJSWeakCollectionDetails(
242 ObjectStats* stats, Heap* heap, JSWeakCollection* obj) { 265 ObjectStats* stats, Heap* heap, JSWeakCollection* obj) {
243 if (obj->table()->IsHashTable()) { 266 if (obj->table()->IsHashTable()) {
244 ObjectHashTable* table = ObjectHashTable::cast(obj->table()); 267 ObjectHashTable* table = ObjectHashTable::cast(obj->table());
245 int used = table->NumberOfElements() * ObjectHashTable::kEntrySize; 268 int used = table->NumberOfElements() * ObjectHashTable::kEntrySize;
246 size_t overhead = table->Size() - used; 269 size_t overhead = table->Size() - used;
247 stats->RecordFixedArraySubTypeStats(WEAK_COLLECTION_SUB_TYPE, table->Size(), 270 RecordFixedArrayHelper(stats, heap, obj, table, WEAK_COLLECTION_SUB_TYPE,
248 overhead); 271 overhead);
249 } 272 }
250 } 273 }
251 274
252 void ObjectStatsCollector::RecordMapDetails(ObjectStats* stats, Heap* heap, 275 void ObjectStatsCollector::RecordMapDetails(ObjectStats* stats, Heap* heap,
253 HeapObject* obj) { 276 HeapObject* obj) {
254 Map* map_obj = Map::cast(obj); 277 Map* map_obj = Map::cast(obj);
255 DCHECK(obj->map()->instance_type() == MAP_TYPE); 278 DCHECK(obj->map()->instance_type() == MAP_TYPE);
256 DescriptorArray* array = map_obj->instance_descriptors(); 279 DescriptorArray* array = map_obj->instance_descriptors();
257 if (map_obj->owns_descriptors() && array != heap->empty_descriptor_array()) { 280 if (map_obj->owns_descriptors() && array != heap->empty_descriptor_array() &&
258 int fixed_array_size = array->Size(); 281 SameLiveness(map_obj, array)) {
259 stats->RecordFixedArraySubTypeStats(DESCRIPTOR_ARRAY_SUB_TYPE, 282 RecordFixedArrayHelper(stats, heap, map_obj, array,
260 fixed_array_size, 0); 283 DESCRIPTOR_ARRAY_SUB_TYPE, 0);
261 if (array->HasEnumCache()) { 284 if (array->HasEnumCache()) {
262 stats->RecordFixedArraySubTypeStats(ENUM_CACHE_SUB_TYPE, 285 RecordFixedArrayHelper(stats, heap, array, array->GetEnumCache(),
263 array->GetEnumCache()->Size(), 0); 286 ENUM_CACHE_SUB_TYPE, 0);
264 } 287 }
265 if (array->HasEnumIndicesCache()) { 288 if (array->HasEnumIndicesCache()) {
266 stats->RecordFixedArraySubTypeStats( 289 RecordFixedArrayHelper(stats, heap, array, array->GetEnumIndicesCache(),
267 ENUM_INDICES_CACHE_SUB_TYPE, array->GetEnumIndicesCache()->Size(), 0); 290 ENUM_INDICES_CACHE_SUB_TYPE, 0);
268 } 291 }
269 } 292 }
270 293
271 if (map_obj->has_code_cache()) { 294 if (map_obj->has_code_cache()) {
272 FixedArray* cache = map_obj->code_cache(); 295 RecordFixedArrayHelper(stats, heap, map_obj, map_obj->code_cache(),
273 stats->RecordFixedArraySubTypeStats(MAP_CODE_CACHE_SUB_TYPE, cache->Size(), 296 MAP_CODE_CACHE_SUB_TYPE, 0);
274 0);
275 } 297 }
276 } 298 }
277 299
278 void ObjectStatsCollector::RecordCodeDetails(ObjectStats* stats, Heap* heap, 300 void ObjectStatsCollector::RecordCodeDetails(ObjectStats* stats, Heap* heap,
279 HeapObject* obj) { 301 HeapObject* obj) {
280 int object_size = obj->Size(); 302 int object_size = obj->Size();
281 DCHECK(obj->map()->instance_type() == CODE_TYPE); 303 DCHECK(obj->map()->instance_type() == CODE_TYPE);
282 Code* code_obj = Code::cast(obj); 304 Code* code_obj = Code::cast(obj);
283 stats->RecordCodeSubTypeStats(code_obj->kind(), code_obj->GetAge(), 305 stats->RecordCodeSubTypeStats(code_obj->kind(), code_obj->GetAge(),
284 object_size); 306 object_size);
285 Code* code = Code::cast(obj); 307 Code* code = Code::cast(obj);
286 if (code->deoptimization_data() != heap->empty_fixed_array()) { 308 RecordFixedArrayHelper(stats, heap, code, code->deoptimization_data(),
287 stats->RecordFixedArraySubTypeStats(DEOPTIMIZATION_DATA_SUB_TYPE, 309 DEOPTIMIZATION_DATA_SUB_TYPE, 0);
288 code->deoptimization_data()->Size(), 0);
289 }
290 FixedArrayBase* reloc_info =
291 reinterpret_cast<FixedArrayBase*>(code->unchecked_relocation_info());
292 if (reloc_info != heap->empty_fixed_array()) {
293 stats->RecordFixedArraySubTypeStats(RELOC_INFO_SUB_TYPE,
294 code->relocation_info()->Size(), 0);
295 }
296 FixedArrayBase* source_pos_table =
297 reinterpret_cast<FixedArrayBase*>(code->source_position_table());
298 if (source_pos_table != heap->empty_fixed_array()) {
299 stats->RecordFixedArraySubTypeStats(SOURCE_POS_SUB_TYPE,
300 source_pos_table->Size(), 0);
301 }
302 } 310 }
303 311
304 void ObjectStatsCollector::RecordSharedFunctionInfoDetails(ObjectStats* stats, 312 void ObjectStatsCollector::RecordSharedFunctionInfoDetails(ObjectStats* stats,
305 Heap* heap, 313 Heap* heap,
306 HeapObject* obj) { 314 HeapObject* obj) {
307 SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj); 315 SharedFunctionInfo* sfi = SharedFunctionInfo::cast(obj);
308 if (sfi->scope_info() != heap->empty_fixed_array()) { 316 FixedArray* scope_info = sfi->scope_info();
309 stats->RecordFixedArraySubTypeStats(SCOPE_INFO_SUB_TYPE, 317 RecordFixedArrayHelper(stats, heap, sfi, scope_info, SCOPE_INFO_SUB_TYPE, 0);
310 sfi->scope_info()->Size(), 0); 318 FixedArray* feedback_metadata = sfi->feedback_metadata();
311 } 319 RecordFixedArrayHelper(stats, heap, sfi, feedback_metadata,
312 if (sfi->feedback_metadata() != heap->empty_fixed_array()) { 320 TYPE_FEEDBACK_METADATA_SUB_TYPE, 0);
313 stats->RecordFixedArraySubTypeStats(TYPE_FEEDBACK_METADATA_SUB_TYPE, 321
314 sfi->feedback_metadata()->Size(), 0);
315 }
316 if (!sfi->OptimizedCodeMapIsCleared()) { 322 if (!sfi->OptimizedCodeMapIsCleared()) {
317 FixedArray* optimized_code_map = sfi->optimized_code_map(); 323 FixedArray* optimized_code_map = sfi->optimized_code_map();
318 // Optimized code map should be small, so skip accounting. 324 // Optimized code map should be small, so skip accounting.
319 int len = optimized_code_map->length(); 325 int len = optimized_code_map->length();
320 for (int i = SharedFunctionInfo::kEntriesStart; i < len; 326 for (int i = SharedFunctionInfo::kEntriesStart; i < len;
321 i += SharedFunctionInfo::kEntryLength) { 327 i += SharedFunctionInfo::kEntryLength) {
322 Object* slot = 328 Object* slot =
323 optimized_code_map->get(i + SharedFunctionInfo::kLiteralsOffset); 329 optimized_code_map->get(i + SharedFunctionInfo::kLiteralsOffset);
324 LiteralsArray* literals = nullptr; 330 LiteralsArray* literals = nullptr;
325 if (slot->IsWeakCell()) { 331 if (slot->IsWeakCell()) {
326 WeakCell* cell = WeakCell::cast(slot); 332 WeakCell* cell = WeakCell::cast(slot);
327 if (!cell->cleared()) { 333 if (!cell->cleared()) {
328 literals = LiteralsArray::cast(cell->value()); 334 literals = LiteralsArray::cast(cell->value());
329 } 335 }
330 } else { 336 } else {
331 literals = LiteralsArray::cast(slot); 337 literals = LiteralsArray::cast(slot);
332 } 338 }
333 if (literals != nullptr) { 339 if (literals != nullptr) {
334 stats->RecordFixedArraySubTypeStats(LITERALS_ARRAY_SUB_TYPE, 340 RecordFixedArrayHelper(stats, heap, sfi, literals,
335 literals->Size(), 0); 341 LITERALS_ARRAY_SUB_TYPE, 0);
336 TypeFeedbackVector* tfv = literals->feedback_vector(); 342 RecordFixedArrayHelper(stats, heap, sfi, literals->feedback_vector(),
337 343 TYPE_FEEDBACK_VECTOR_SUB_TYPE, 0);
338 stats->RecordFixedArraySubTypeStats(TYPE_FEEDBACK_VECTOR_SUB_TYPE,
339 tfv->Size(), 0);
340 } 344 }
341 } 345 }
342 } 346 }
343 } 347 }
344 348
345 void ObjectStatsCollector::RecordFixedArrayDetails(ObjectStats* stats, 349 void ObjectStatsCollector::RecordFixedArrayDetails(ObjectStats* stats,
346 Heap* heap, 350 Heap* heap,
347 HeapObject* obj) { 351 HeapObject* obj) {
348 FixedArray* fixed_array = FixedArray::cast(obj); 352 FixedArray* fixed_array = FixedArray::cast(obj);
349 if (fixed_array == heap->string_table()) {
350 stats->RecordFixedArraySubTypeStats(STRING_TABLE_SUB_TYPE,
351 fixed_array->Size(), 0);
352 }
353 if (fixed_array == heap->weak_object_to_code_table()) { 353 if (fixed_array == heap->weak_object_to_code_table()) {
354 WeakHashTable* table = reinterpret_cast<WeakHashTable*>(fixed_array); 354 WeakHashTable* table = reinterpret_cast<WeakHashTable*>(fixed_array);
355 int used = table->NumberOfElements() * WeakHashTable::kEntrySize; 355 int used = table->NumberOfElements() * WeakHashTable::kEntrySize;
356 CHECK_GE(fixed_array->Size(), used); 356 CHECK_GE(fixed_array->Size(), used);
357 size_t overhead = fixed_array->Size() - used; 357 size_t overhead = fixed_array->Size() - used;
358 stats->RecordFixedArraySubTypeStats(OBJECT_TO_CODE_SUB_TYPE, 358 stats->RecordFixedArraySubTypeStats(table, OBJECT_TO_CODE_SUB_TYPE,
359 fixed_array->Size(), overhead); 359 fixed_array->Size(), overhead);
360 } 360 }
361 if (obj->IsContext()) { 361
362 stats->RecordFixedArraySubTypeStats(CONTEXT_SUB_TYPE, fixed_array->Size(), 362 int subtype = -1;
363 0); 363 if (fixed_array == heap->string_table()) subtype = STRING_TABLE_SUB_TYPE;
364 } 364 if (fixed_array->IsContext()) subtype = CONTEXT_SUB_TYPE;
365 if (fixed_array->map() == heap->fixed_cow_array_map()) { 365 if (fixed_array->map() == heap->fixed_cow_array_map())
366 stats->RecordFixedArraySubTypeStats(COPY_ON_WRITE_SUB_TYPE, 366 subtype = COPY_ON_WRITE_SUB_TYPE;
367 if (subtype != -1) {
368 stats->RecordFixedArraySubTypeStats(fixed_array, subtype,
367 fixed_array->Size(), 0); 369 fixed_array->Size(), 0);
368 } 370 }
369 } 371 }
370 372
371 } // namespace internal 373 } // namespace internal
372 } // namespace v8 374 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698