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