Commit 446a827d authored by Igor Sheludko's avatar Igor Sheludko Committed by Commit Bot

[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: 's avatarCamillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69104}
parent 02ad36a7
......@@ -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,7 +81,12 @@ defineCustomElement('global-timeline', (templateText) =>
return {label: name + " (used)", type: 'number'};
});
default:
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);
} else {
// KIND_USED_MEMORY
data.push(used);
if (data_kind == KIND_ALLOCATED_MEMORY) {
value = sample.allocated / KB;
} else if (data_kind == KIND_FREED_MEMORY) {
value = sample.freed / KB;
} else {
// KIND_USED_MEMORY
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);
} else {
// KIND_USED_MEMORY
data.push(used);
if (data_kind == KIND_ALLOCATED_MEMORY) {
value = sample.allocated / KB;
} else if (data_kind == KIND_FREED_MEMORY) {
value = sample.freed / KB;
} else {
// KIND_USED_MEMORY
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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment