| // Copyright 2018 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| 'use strict'; |
| |
| export class Isolate { |
| constructor(address) { |
| this.address = address; |
| this.start = null; |
| this.end = null; |
| this.samples = Object.create(null); |
| this.non_empty_instance_types = new Set(); |
| this.gcs = Object.create(null); |
| this.zonetags = []; |
| this.samples = {zone: {}}; |
| this.data_sets = new Set(); |
| this.peakMemory = 0; |
| // Maps instance_types to their max memory consumption over all gcs. |
| this.instanceTypePeakMemory = Object.create(null); |
| // Peak memory consumed by any single instance type. |
| this.singleInstanceTypePeakMemory = 0; |
| } |
| |
| finalize() { |
| Object.values(this.gcs).forEach(gc => this.finalizeGC(gc)); |
| this.sortInstanceTypePeakMemory(); |
| } |
| |
| getLabel() { |
| let label = `${this.address}: gc=#${Object.keys(this.gcs).length}`; |
| label += ` peak=${formatBytes(this.peakMemory)}` |
| return label; |
| } |
| |
| finalizeGC(gc_data) { |
| this.data_sets.forEach(key => this.finalizeDataSet(gc_data[key])); |
| if (!('live' in gc_data)) return; |
| let liveData = gc_data.live; |
| this.peakMemory = Math.max(this.peakMemory, liveData.overall); |
| let data = liveData.instance_type_data; |
| for (let name in data) { |
| let prev = this.instanceTypePeakMemory[name] || 0; |
| this.instanceTypePeakMemory[name] = Math.max(prev, data[name].overall); |
| } |
| } |
| |
| finalizeDataSet(data_set) { |
| // Create a ranked instance type array that sorts instance types by |
| // memory size (overall). |
| let data = data_set.instance_type_data; |
| let ranked_instance_types = |
| [...data_set.non_empty_instance_types].sort((a, b) => { |
| return data[a].overall - data[b].overall; |
| }); |
| // Reassemble the instance_type list sorted by size. |
| let sorted_data = Object.create(null); |
| let max = 0; |
| ranked_instance_types.forEach((name) => { |
| let entry = sorted_data[name] = data[name]; |
| max = Math.max(max, entry.overall); |
| }); |
| data_set.instance_type_data = data; |
| data_set.singleInstancePeakMemory = max; |
| |
| Object.entries(data_set.instance_type_data).forEach(([name, entry]) => { |
| this.checkHistogram( |
| name, entry, data_set.bucket_sizes, 'histogram', ' overall'); |
| this.checkHistogram( |
| name, entry, data_set.bucket_sizes, 'over_allocated_histogram', |
| ' over_allocated'); |
| }); |
| } |
| |
| // Check that a lower bound for histogram memory does not exceed the |
| // overall counter. |
| checkHistogram(type, entry, bucket_sizes, histogram, overallProperty) { |
| let sum = 0; |
| for (let i = 1; i < entry[histogram].length; i++) { |
| sum += entry[histogram][i] * bucket_sizes[i - 1]; |
| } |
| const overall = entry[overallProperty]; |
| if (sum >= overall) { |
| console.error( |
| `${type}: sum('${histogram}') > overall (${sum} > ${overall})`); |
| } |
| } |
| |
| sortInstanceTypePeakMemory() { |
| let entries = Object.entries(this.instanceTypePeakMemory); |
| entries.sort((a, b) => {return b[1] - a[1]}); |
| this.instanceTypePeakMemory = Object.create(null); |
| let max = 0; |
| for (let [key, value] of entries) { |
| this.instanceTypePeakMemory[key] = value; |
| max = Math.max(max, value); |
| } |
| this.singleInstanceTypePeakMemory = max; |
| } |
| |
| getInstanceTypePeakMemory(type) { |
| if (!(type in this.instanceTypePeakMemory)) return 0; |
| return this.instanceTypePeakMemory[type]; |
| } |
| } |