[zone-stats] Track zone memory freed by container reallocations
Also use outer-function name as a ZONE_NAME instead of file:line and give explicit names to parser and preparser zones. Bug: v8:10572 Change-Id: I9b5acb23322889d8538a34bc888fd6f610eb6893 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2322627 Commit-Queue: Igor Sheludko <ishell@chromium.org> Reviewed-by: Camillo Bruni <cbruni@chromium.org> Reviewed-by: Leszek Swirski <leszeks@chromium.org> Cr-Commit-Position: refs/heads/master@{#69104}
This commit is contained in:
parent
02ad36a700
commit
446a827d5d
@ -2832,6 +2832,7 @@ class TracingAccountingAllocator : public AccountingAllocator {
|
||||
<< "\"time\": " << time << ", ";
|
||||
size_t total_segment_bytes_allocated = 0;
|
||||
size_t total_zone_allocation_size = 0;
|
||||
size_t total_zone_freed_size = 0;
|
||||
|
||||
if (dump_details) {
|
||||
// Print detailed zone stats if memory usage changes direction.
|
||||
@ -2840,6 +2841,7 @@ class TracingAccountingAllocator : public AccountingAllocator {
|
||||
for (const Zone* zone : active_zones_) {
|
||||
size_t zone_segment_bytes_allocated = zone->segment_bytes_allocated();
|
||||
size_t zone_allocation_size = zone->allocation_size_for_tracing();
|
||||
size_t freed_size = zone->freed_size_for_tracing();
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
@ -2848,9 +2850,11 @@ class TracingAccountingAllocator : public AccountingAllocator {
|
||||
out << "{"
|
||||
<< "\"name\": \"" << zone->name() << "\", "
|
||||
<< "\"allocated\": " << zone_segment_bytes_allocated << ", "
|
||||
<< "\"used\": " << zone_allocation_size << "}";
|
||||
<< "\"used\": " << zone_allocation_size << ", "
|
||||
<< "\"freed\": " << freed_size << "}";
|
||||
total_segment_bytes_allocated += zone_segment_bytes_allocated;
|
||||
total_zone_allocation_size += zone_allocation_size;
|
||||
total_zone_freed_size += freed_size;
|
||||
}
|
||||
out << "], ";
|
||||
} else {
|
||||
@ -2858,10 +2862,12 @@ class TracingAccountingAllocator : public AccountingAllocator {
|
||||
for (const Zone* zone : active_zones_) {
|
||||
total_segment_bytes_allocated += zone->segment_bytes_allocated();
|
||||
total_zone_allocation_size += zone->allocation_size_for_tracing();
|
||||
total_zone_freed_size += zone->freed_size_for_tracing();
|
||||
}
|
||||
}
|
||||
out << "\"allocated\": " << total_segment_bytes_allocated << ", "
|
||||
<< "\"used\": " << total_zone_allocation_size << "}";
|
||||
<< "\"used\": " << total_zone_allocation_size << ", "
|
||||
<< "\"freed\": " << total_zone_freed_size << "}";
|
||||
}
|
||||
|
||||
Isolate* const isolate_;
|
||||
|
@ -179,7 +179,7 @@ ParseInfo::ParseInfo(const UnoptimizedCompileFlags flags,
|
||||
UnoptimizedCompileState* state)
|
||||
: flags_(flags),
|
||||
state_(state),
|
||||
zone_(std::make_unique<Zone>(state->allocator(), ZONE_NAME)),
|
||||
zone_(std::make_unique<Zone>(state->allocator(), "parser-zone")),
|
||||
extension_(nullptr),
|
||||
script_scope_(nullptr),
|
||||
stack_limit_(0),
|
||||
|
@ -423,7 +423,7 @@ Parser::Parser(ParseInfo* info)
|
||||
info->runtime_call_stats(), info->logger(), info->flags(), true),
|
||||
info_(info),
|
||||
scanner_(info->character_stream(), flags()),
|
||||
preparser_zone_(info->zone()->allocator(), ZONE_NAME),
|
||||
preparser_zone_(info->zone()->allocator(), "pre-parser-zone"),
|
||||
reusable_preparser_(nullptr),
|
||||
mode_(PARSE_EAGERLY), // Lazy mode must be set explicitly.
|
||||
source_range_map_(info->source_range_map()),
|
||||
|
@ -62,6 +62,7 @@ void TypeStats::Dump() const {
|
||||
const StatsEntry& entry = item.second;
|
||||
total_allocation_count += entry.allocation_count;
|
||||
total_allocated_bytes += entry.allocated_bytes;
|
||||
total_deallocated_bytes += entry.deallocated_bytes;
|
||||
PrintF("%12zu | %12zu | %10zu | %6zu | %s\n", entry.allocated_bytes,
|
||||
entry.deallocated_bytes, entry.allocation_count, entry.instance_size,
|
||||
d.demangle(item.first));
|
||||
|
@ -15,9 +15,7 @@
|
||||
#include "src/zone/zone-segment.h"
|
||||
|
||||
#ifndef ZONE_NAME
|
||||
#define STRINGIFY(x) #x
|
||||
#define TOSTRING(x) STRINGIFY(x)
|
||||
#define ZONE_NAME __FILE__ ":" TOSTRING(__LINE__)
|
||||
#define ZONE_NAME __func__
|
||||
#endif
|
||||
|
||||
namespace v8 {
|
||||
@ -72,7 +70,7 @@ class V8_EXPORT_PRIVATE Zone final {
|
||||
position_ += size;
|
||||
}
|
||||
return reinterpret_cast<void*>(result);
|
||||
#endif
|
||||
#endif // V8_USE_ADDRESS_SANITIZER
|
||||
}
|
||||
|
||||
// Return 'size' bytes of memory back to Zone. These bytes can be reused
|
||||
@ -84,12 +82,12 @@ class V8_EXPORT_PRIVATE Zone final {
|
||||
void Delete(void* pointer, size_t size) {
|
||||
DCHECK_NOT_NULL(pointer);
|
||||
DCHECK_NE(size, 0);
|
||||
// TODO(v8:10572): implement accounting for reusable zone memory
|
||||
size = RoundUp(size, kAlignmentInBytes);
|
||||
#ifdef V8_ENABLE_PRECISE_ZONE_STATS
|
||||
if (V8_UNLIKELY(TracingFlags::is_zone_stats_enabled())) {
|
||||
type_stats_.AddDeallocated<TypeTag>(size);
|
||||
}
|
||||
freed_size_for_tracing_ += size;
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -156,7 +154,7 @@ class V8_EXPORT_PRIVATE Zone final {
|
||||
return allocation_size_ + extra;
|
||||
}
|
||||
|
||||
// When V8_ENABLE_PRECISE_ZONE_STATS is not enabled, returns used zone memory
|
||||
// When V8_ENABLE_PRECISE_ZONE_STATS is not defined, returns used zone memory
|
||||
// not including the head segment.
|
||||
// Can be called from threads not owning the zone.
|
||||
size_t allocation_size_for_tracing() const {
|
||||
@ -167,6 +165,17 @@ class V8_EXPORT_PRIVATE Zone final {
|
||||
#endif
|
||||
}
|
||||
|
||||
// Returns number of bytes freed in this zone via Delete<T>()/DeleteArray<T>()
|
||||
// calls. Returns non-zero values only when V8_ENABLE_PRECISE_ZONE_STATS is
|
||||
// defined.
|
||||
size_t freed_size_for_tracing() const {
|
||||
#ifdef V8_ENABLE_PRECISE_ZONE_STATS
|
||||
return freed_size_for_tracing_;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
AccountingAllocator* allocator() const { return allocator_; }
|
||||
|
||||
#ifdef V8_ENABLE_PRECISE_ZONE_STATS
|
||||
@ -221,6 +230,9 @@ class V8_EXPORT_PRIVATE Zone final {
|
||||
#ifdef V8_ENABLE_PRECISE_ZONE_STATS
|
||||
TypeStats type_stats_;
|
||||
size_t allocation_size_for_tracing_ = 0;
|
||||
|
||||
// The number of bytes freed in this zone so far.
|
||||
size_t freed_size_for_tracing_ = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -10,8 +10,8 @@ export const CATEGORIES = new Map([
|
||||
[
|
||||
'parser', new Set([
|
||||
'AstStringConstants',
|
||||
'ParseInfo',
|
||||
'Parser',
|
||||
'parser-zone',
|
||||
'pre-parser-zone',
|
||||
])
|
||||
],
|
||||
[
|
||||
|
@ -12,6 +12,7 @@ export const VIEW_BY_ZONE_CATEGORY = 'by-zone-category';
|
||||
|
||||
export const KIND_ALLOCATED_MEMORY = 'kind-detailed-allocated';
|
||||
export const KIND_USED_MEMORY = 'kind-detailed-used';
|
||||
export const KIND_FREED_MEMORY = 'kind-detailed-freed';
|
||||
|
||||
defineCustomElement('details-selection', (templateText) =>
|
||||
class DetailsSelection extends HTMLElement {
|
||||
@ -175,6 +176,7 @@ defineCustomElement('details-selection', (templateText) =>
|
||||
'#data-kind-select', [
|
||||
[KIND_ALLOCATED_MEMORY, 'Allocated memory per zone'],
|
||||
[KIND_USED_MEMORY, 'Used memory per zone'],
|
||||
[KIND_FREED_MEMORY, 'Freed memory per zone'],
|
||||
],
|
||||
(key, label) => label, KIND_ALLOCATED_MEMORY);
|
||||
|
||||
|
@ -13,6 +13,7 @@ import {
|
||||
|
||||
KIND_ALLOCATED_MEMORY,
|
||||
KIND_USED_MEMORY,
|
||||
KIND_FREED_MEMORY,
|
||||
} from './details-selection.js';
|
||||
|
||||
defineCustomElement('global-timeline', (templateText) =>
|
||||
@ -80,6 +81,11 @@ defineCustomElement('global-timeline', (templateText) =>
|
||||
return {label: name + " (used)", type: 'number'};
|
||||
});
|
||||
|
||||
case KIND_FREED_MEMORY:
|
||||
return zone_names.map(name => {
|
||||
return {label: name + " (freed)", type: 'number'};
|
||||
});
|
||||
|
||||
default:
|
||||
// Don't show detailed per-zone information.
|
||||
return [];
|
||||
@ -92,6 +98,7 @@ defineCustomElement('global-timeline', (templateText) =>
|
||||
{ label: "Time", type: "number" },
|
||||
{ label: "Total allocated", type: "number" },
|
||||
{ label: "Total used", type: "number" },
|
||||
{ label: "Total freed", type: "number" },
|
||||
];
|
||||
const chart_data = [labels];
|
||||
|
||||
@ -105,6 +112,7 @@ defineCustomElement('global-timeline', (templateText) =>
|
||||
data.push(time * kMillis2Seconds);
|
||||
data.push(zone_data.allocated / KB);
|
||||
data.push(zone_data.used / KB);
|
||||
data.push(zone_data.freed / KB);
|
||||
chart_data.push(data);
|
||||
}
|
||||
return chart_data;
|
||||
@ -122,6 +130,7 @@ defineCustomElement('global-timeline', (templateText) =>
|
||||
? [
|
||||
{ label: "Total allocated", type: "number" },
|
||||
{ label: "Total used", type: "number" },
|
||||
{ label: "Total freed", type: "number" },
|
||||
]
|
||||
: [];
|
||||
|
||||
@ -146,13 +155,17 @@ defineCustomElement('global-timeline', (templateText) =>
|
||||
const current_stats = active_zone_stats[zone_name];
|
||||
if (current_stats === undefined) {
|
||||
active_zone_stats[zone_name] =
|
||||
{ allocated: zone_stats.allocated, used: zone_stats.used };
|
||||
{ allocated: zone_stats.allocated,
|
||||
used: zone_stats.used,
|
||||
freed: zone_stats.freed,
|
||||
};
|
||||
} else {
|
||||
// We've got two zones with the same name.
|
||||
console.log("=== Duplicate zone names: " + zone_name);
|
||||
// Sum stats.
|
||||
current_stats.allocated += zone_stats.allocated;
|
||||
current_stats.used += zone_stats.used;
|
||||
current_stats.freed += zone_stats.freed;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -162,27 +175,23 @@ defineCustomElement('global-timeline', (templateText) =>
|
||||
if (show_totals) {
|
||||
data.push(zone_data.allocated / KB);
|
||||
data.push(zone_data.used / KB);
|
||||
}
|
||||
|
||||
if (zone_data.used > 30 * MB) {
|
||||
console.log("BOOOM!!!! Zone usage in a sample is too big: " +
|
||||
(zone_data.used / MB) + " MB");
|
||||
data.push(zone_data.freed / KB);
|
||||
}
|
||||
|
||||
zone_names.forEach(zone => {
|
||||
const sample = active_zone_stats[zone];
|
||||
let used = null;
|
||||
let allocated = null;
|
||||
let value = null;
|
||||
if (sample !== undefined) {
|
||||
used = sample.used / KB;
|
||||
allocated = sample.allocated / KB;
|
||||
}
|
||||
if (data_kind == KIND_ALLOCATED_MEMORY) {
|
||||
data.push(allocated);
|
||||
value = sample.allocated / KB;
|
||||
} else if (data_kind == KIND_FREED_MEMORY) {
|
||||
value = sample.freed / KB;
|
||||
} else {
|
||||
// KIND_USED_MEMORY
|
||||
data.push(used);
|
||||
value = sample.used / KB;
|
||||
}
|
||||
}
|
||||
data.push(value);
|
||||
});
|
||||
chart_data.push(data);
|
||||
}
|
||||
@ -204,6 +213,7 @@ defineCustomElement('global-timeline', (templateText) =>
|
||||
? [
|
||||
{ label: "Total allocated", type: "number" },
|
||||
{ label: "Total used", type: "number" },
|
||||
{ label: "Total freed", type: "number" },
|
||||
]
|
||||
: [];
|
||||
|
||||
@ -229,11 +239,15 @@ defineCustomElement('global-timeline', (templateText) =>
|
||||
const current_stats = active_category_stats[category];
|
||||
if (current_stats === undefined) {
|
||||
active_category_stats[category] =
|
||||
{ allocated: zone_stats.allocated, used: zone_stats.used };
|
||||
{ allocated: zone_stats.allocated,
|
||||
used: zone_stats.used,
|
||||
freed: zone_stats.freed,
|
||||
};
|
||||
} else {
|
||||
// Sum stats.
|
||||
current_stats.allocated += zone_stats.allocated;
|
||||
current_stats.used += zone_stats.used;
|
||||
current_stats.freed += zone_stats.freed;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -243,22 +257,23 @@ defineCustomElement('global-timeline', (templateText) =>
|
||||
if (show_totals) {
|
||||
data.push(zone_data.allocated / KB);
|
||||
data.push(zone_data.used / KB);
|
||||
data.push(zone_data.freed / KB);
|
||||
}
|
||||
|
||||
categories.forEach(category => {
|
||||
const sample = active_category_stats[category];
|
||||
let used = null;
|
||||
let allocated = null;
|
||||
let value = null;
|
||||
if (sample !== undefined) {
|
||||
used = sample.used / KB;
|
||||
allocated = sample.allocated / KB;
|
||||
}
|
||||
if (data_kind == KIND_ALLOCATED_MEMORY) {
|
||||
data.push(allocated);
|
||||
value = sample.allocated / KB;
|
||||
} else if (data_kind == KIND_FREED_MEMORY) {
|
||||
value = sample.freed / KB;
|
||||
} else {
|
||||
// KIND_USED_MEMORY
|
||||
data.push(used);
|
||||
value = sample.used / KB;
|
||||
}
|
||||
}
|
||||
data.push(value);
|
||||
});
|
||||
chart_data.push(data);
|
||||
}
|
||||
@ -301,9 +316,11 @@ defineCustomElement('global-timeline', (templateText) =>
|
||||
if (this.selection.data_view == VIEW_TOTALS) {
|
||||
series[0] = {type: 'line', color: "red"};
|
||||
series[1] = {type: 'line', color: "blue"};
|
||||
series[2] = {type: 'line', color: "orange"};
|
||||
} else if (this.selection.show_totals) {
|
||||
series[0] = {type: 'line', color: "red", lineDashStyle: [13, 13]};
|
||||
series[1] = {type: 'line', color: "blue", lineDashStyle: [13, 13]};
|
||||
series[2] = {type: 'line', color: "orange", lineDashStyle: [13, 13]};
|
||||
}
|
||||
return Object.assign(options, {series: series});
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ found in the LICENSE file. -->
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>V8 Heap Statistics</title>
|
||||
<title>V8 Zone Statistics</title>
|
||||
<link href='https://fonts.googleapis.com/css?family=Roboto' rel='stylesheet'>
|
||||
<script
|
||||
src="https://www.gstatic.com/charts/loader.js"></script>
|
||||
@ -67,7 +67,7 @@ function globalSelectionChangedA(e) {
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>V8 Zone memory usage Statistics</h1>
|
||||
<h1>V8 Zone memory usage statistics</h1>
|
||||
<trace-file-reader onchange="globalDataChanged(event)"></trace-file-reader>
|
||||
|
||||
<details-selection id="details-selection" onchange="globalSelectionChangedA(event)"></details-selection>
|
||||
|
@ -155,8 +155,11 @@ defineCustomElement('trace-file-reader', (templateText) =>
|
||||
if (existing_zone_stats !== undefined) {
|
||||
existing_zone_stats.allocated += zone.allocated;
|
||||
existing_zone_stats.used += zone.used;
|
||||
existing_zone_stats.freed += zone.freed;
|
||||
} else {
|
||||
zones.set(zone.name, {allocated: zone.allocated, used: zone.used});
|
||||
zones.set(zone.name, { allocated: zone.allocated,
|
||||
used: zone.used,
|
||||
freed: zone.freed });
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -165,6 +168,7 @@ defineCustomElement('trace-file-reader', (templateText) =>
|
||||
time: time,
|
||||
allocated: entry_stats.allocated,
|
||||
used: entry_stats.used,
|
||||
freed: entry_stats.freed,
|
||||
zones: zones
|
||||
};
|
||||
isolate_data.samples.set(time, sample);
|
||||
|
Loading…
Reference in New Issue
Block a user