Skip to content

Commit e63d016

Browse files
author
Ashutosh Mehra
committedJul 31, 2024
8337031: Improvements to CompilationMemoryStatistic
Reviewed-by: kvn, stuefe
1 parent 1c6fef8 commit e63d016

File tree

6 files changed

+155
-98
lines changed

6 files changed

+155
-98
lines changed
 

‎src/hotspot/share/compiler/compilationMemoryStatistic.cpp

+77-68
Original file line numberDiff line numberDiff line change
@@ -51,29 +51,36 @@
5151
#include "utilities/quickSort.hpp"
5252
#include "utilities/resourceHash.hpp"
5353

54-
ArenaStatCounter::ArenaStatCounter() :
55-
_current(0), _start(0), _peak(0),
56-
_na(0), _ra(0),
57-
_limit(0), _hit_limit(false), _limit_in_process(false),
58-
_na_at_peak(0), _ra_at_peak(0), _live_nodes_at_peak(0)
59-
{}
60-
61-
size_t ArenaStatCounter::peak_since_start() const {
62-
return _peak > _start ? _peak - _start : 0;
54+
ArenaStatCounter::ArenaStatCounter() {
55+
reset();
56+
}
57+
58+
void ArenaStatCounter::reset() {
59+
_current = 0;
60+
_peak = 0;
61+
_current_by_tag.clear();
62+
_peak_by_tag.clear();
63+
_limit = 0;
64+
_hit_limit = false;
65+
_limit_in_process = false;
66+
_live_nodes_at_peak = 0;
67+
_active = false;
6368
}
6469

6570
void ArenaStatCounter::start(size_t limit) {
66-
_peak = _start = _current;
71+
reset();
72+
_active = true;
6773
_limit = limit;
68-
_hit_limit = false;
6974
}
7075

71-
void ArenaStatCounter::end(){
76+
void ArenaStatCounter::end() {
7277
_limit = 0;
7378
_hit_limit = false;
79+
_active = false;
7480
}
7581

7682
void ArenaStatCounter::update_c2_node_count() {
83+
assert(_active, "compilaton has not yet started");
7784
#ifdef COMPILER2
7885
CompilerThread* const th = Thread::current()->as_Compiler_thread();
7986
const CompileTask* const task = th->task();
@@ -90,43 +97,43 @@ void ArenaStatCounter::update_c2_node_count() {
9097

9198
// Account an arena allocation or de-allocation.
9299
bool ArenaStatCounter::account(ssize_t delta, int tag) {
100+
assert(_active, "compilaton has not yet started");
93101
bool rc = false;
94102
#ifdef ASSERT
95103
// Note: if this fires, we free more arena memory under the scope of the
96104
// CompilationMemoryHistoryMark than we allocate. This cannot be since we
97105
// assume arena allocations in CompilerThread to be stack bound and symmetric.
98106
assert(delta >= 0 || ((ssize_t)_current + delta) >= 0,
99-
"Negative overflow (d=%zd %zu %zu %zu)", delta, _current, _start, _peak);
107+
"Negative overflow (d=%zd %zu %zu)", delta, _current, _peak);
100108
#endif
101109
// Update totals
102110
_current += delta;
103-
// Update detail counter
104-
switch ((Arena::Tag)tag) {
105-
case Arena::Tag::tag_ra: _ra += delta; break;
106-
case Arena::Tag::tag_node: _na += delta; break;
107-
default: // ignore
108-
break;
109-
};
111+
_current_by_tag.add(tag, delta);
110112
// Did we reach a peak?
111113
if (_current > _peak) {
112114
_peak = _current;
113-
assert(delta > 0, "Sanity (%zu %zu %zu)", _current, _start, _peak);
114-
_na_at_peak = _na;
115-
_ra_at_peak = _ra;
115+
assert(delta > 0, "Sanity (%zu %zu)", _current, _peak);
116116
update_c2_node_count();
117+
_peak_by_tag = _current_by_tag;
117118
rc = true;
118119
// Did we hit the memory limit?
119-
if (!_hit_limit && _limit > 0 && peak_since_start() > _limit) {
120+
if (!_hit_limit && _limit > 0 && _peak > _limit) {
120121
_hit_limit = true;
121122
}
122123
}
123124
return rc;
124125
}
125126

126127
void ArenaStatCounter::print_on(outputStream* st) const {
127-
st->print("%zu [na %zu ra %zu]", peak_since_start(), _na_at_peak, _ra_at_peak);
128+
st->print("%zu [", _peak);
129+
for (int tag = 0; tag < _peak_by_tag.element_count(); tag++) {
130+
if (_peak_by_tag.counter(tag) > 0) {
131+
st->print("%s %zu ", _peak_by_tag.tag_name(tag), _peak_by_tag.counter(tag));
132+
}
133+
}
134+
st->print("]");
128135
#ifdef ASSERT
129-
st->print(" (%zu->%zu->%zu)", _start, _peak, _current);
136+
st->print(" (%zu->%zu)", _peak, _current);
130137
#endif
131138
}
132139

@@ -186,10 +193,8 @@ class MemStatEntry : public CHeapObj<mtInternal> {
186193

187194
// peak usage, bytes, over all arenas
188195
size_t _total;
189-
// usage in node arena when total peaked
190-
size_t _na_at_peak;
191-
// usage in resource area when total peaked
192-
size_t _ra_at_peak;
196+
// usage per arena tag when total peaked
197+
ArenaCountersByTag _peak_by_tag;
193198
// number of nodes (c2 only) when total peaked
194199
unsigned _live_nodes_at_peak;
195200
const char* _result;
@@ -199,8 +204,9 @@ class MemStatEntry : public CHeapObj<mtInternal> {
199204
MemStatEntry(FullMethodName method)
200205
: _method(method), _comptype(compiler_c1),
201206
_time(0), _num_recomp(0), _thread(nullptr), _limit(0),
202-
_total(0), _na_at_peak(0), _ra_at_peak(0), _live_nodes_at_peak(0),
207+
_total(0), _live_nodes_at_peak(0),
203208
_result(nullptr) {
209+
_peak_by_tag.clear();
204210
}
205211

206212
void set_comptype(CompilerType comptype) { _comptype = comptype; }
@@ -210,30 +216,42 @@ class MemStatEntry : public CHeapObj<mtInternal> {
210216
void inc_recompilation() { _num_recomp++; }
211217

212218
void set_total(size_t n) { _total = n; }
213-
void set_na_at_peak(size_t n) { _na_at_peak = n; }
214-
void set_ra_at_peak(size_t n) { _ra_at_peak = n; }
219+
void set_peak_by_tag(ArenaCountersByTag peak_by_tag) { _peak_by_tag = peak_by_tag; }
215220
void set_live_nodes_at_peak(unsigned n) { _live_nodes_at_peak = n; }
216221

217222
void set_result(const char* s) { _result = s; }
218223

219224
size_t total() const { return _total; }
220225

221226
static void print_legend(outputStream* st) {
227+
#define LEGEND_KEY_FMT "%11s"
222228
st->print_cr("Legend:");
223-
st->print_cr(" total : memory allocated via arenas while compiling");
224-
st->print_cr(" NA : ...how much in node arenas (if c2)");
225-
st->print_cr(" RA : ...how much in resource areas");
226-
st->print_cr(" result : Result: 'ok' finished successfully, 'oom' hit memory limit, 'err' compilation failed");
227-
st->print_cr(" #nodes : ...how many nodes (c2 only)");
228-
st->print_cr(" limit : memory limit, if set");
229-
st->print_cr(" time : time of last compilation (sec)");
230-
st->print_cr(" type : compiler type");
231-
st->print_cr(" #rc : how often recompiled");
232-
st->print_cr(" thread : compiler thread");
229+
st->print_cr(" " LEGEND_KEY_FMT ": %s", "total", "memory allocated via arenas while compiling");
230+
for (int tag = 0; tag < Arena::tag_count(); tag++) {
231+
st->print_cr(" " LEGEND_KEY_FMT ": %s", Arena::tag_name[tag], Arena::tag_desc[tag]);
232+
}
233+
st->print_cr(" " LEGEND_KEY_FMT ": %s", "result", "Result: 'ok' finished successfully, 'oom' hit memory limit, 'err' compilation failed");
234+
st->print_cr(" " LEGEND_KEY_FMT ": %s", "#nodes", "...how many nodes (c2 only)");
235+
st->print_cr(" " LEGEND_KEY_FMT ": %s", "limit", "memory limit, if set");
236+
st->print_cr(" " LEGEND_KEY_FMT ": %s", "time", "time taken for last compilation (sec)");
237+
st->print_cr(" " LEGEND_KEY_FMT ": %s", "type", "compiler type");
238+
st->print_cr(" " LEGEND_KEY_FMT ": %s", "#rc", "how often recompiled");
239+
st->print_cr(" " LEGEND_KEY_FMT ": %s", "thread", "compiler thread");
240+
#undef LEGEND_KEY_FMT
233241
}
234242

235243
static void print_header(outputStream* st) {
236-
st->print_cr("total NA RA result #nodes limit time type #rc thread method");
244+
#define SIZE_FMT "%-10s"
245+
st->print(SIZE_FMT, "total");
246+
for (int tag = 0; tag < Arena::tag_count(); tag++) {
247+
st->print(SIZE_FMT, Arena::tag_name[tag]);
248+
}
249+
#define HDR_FMT1 "%-8s%-8s%-8s%-8s"
250+
#define HDR_FMT2 "%-6s%-4s%-19s%s"
251+
252+
st->print(HDR_FMT1, "result", "#nodes", "limit", "time");
253+
st->print(HDR_FMT2, "type", "#rc", "thread", "method");
254+
st->print_cr("");
237255
}
238256

239257
void print_on(outputStream* st, bool human_readable) const {
@@ -247,21 +265,14 @@ class MemStatEntry : public CHeapObj<mtInternal> {
247265
}
248266
col += 10; st->fill_to(col);
249267

250-
// NA
251-
if (human_readable) {
252-
st->print(PROPERFMT " ", PROPERFMTARGS(_na_at_peak));
253-
} else {
254-
st->print("%zu ", _na_at_peak);
255-
}
256-
col += 10; st->fill_to(col);
257-
258-
// RA
259-
if (human_readable) {
260-
st->print(PROPERFMT " ", PROPERFMTARGS(_ra_at_peak));
261-
} else {
262-
st->print("%zu ", _ra_at_peak);
268+
for (int tag = 0; tag < Arena::tag_count(); tag++) {
269+
if (human_readable) {
270+
st->print(PROPERFMT " ", PROPERFMTARGS(_peak_by_tag.counter(tag)));
271+
} else {
272+
st->print("%zu ", _peak_by_tag.counter(tag));
273+
}
274+
col += 10; st->fill_to(col);
263275
}
264-
col += 10; st->fill_to(col);
265276

266277
// result?
267278
st->print("%s ", _result ? _result : "");
@@ -296,7 +307,7 @@ class MemStatEntry : public CHeapObj<mtInternal> {
296307
col += 4; st->fill_to(col);
297308

298309
// Thread
299-
st->print(PTR_FORMAT " ", p2i(_thread));
310+
st->print(PTR_FORMAT " ", p2i(_thread));
300311

301312
// MethodName
302313
char buf[1024];
@@ -341,7 +352,7 @@ class MemStatTable :
341352
public:
342353

343354
void add(const FullMethodName& fmn, CompilerType comptype,
344-
size_t total, size_t na_at_peak, size_t ra_at_peak,
355+
size_t total, ArenaCountersByTag peak_by_tag,
345356
unsigned live_nodes_at_peak, size_t limit, const char* result) {
346357
assert_lock_strong(NMTCompilationCostHistory_lock);
347358
MemStatTableKey key(fmn, comptype);
@@ -360,8 +371,7 @@ class MemStatTable :
360371
e->set_comptype(comptype);
361372
e->inc_recompilation();
362373
e->set_total(total);
363-
e->set_na_at_peak(na_at_peak);
364-
e->set_ra_at_peak(ra_at_peak);
374+
e->set_peak_by_tag(peak_by_tag);
365375
e->set_live_nodes_at_peak(live_nodes_at_peak);
366376
e->set_limit(limit);
367377
e->set_result(result);
@@ -427,7 +437,7 @@ void CompilationMemoryStatistic::on_end_compilation() {
427437
const bool print = directive->should_print_memstat();
428438

429439
// Store memory used in task, for later processing by JFR
430-
task->set_arena_bytes(arena_stat->peak_since_start());
440+
task->set_arena_bytes(arena_stat->peak());
431441

432442
// Store result
433443
// For this to work, we must call on_end_compilation() at a point where
@@ -447,9 +457,8 @@ void CompilationMemoryStatistic::on_end_compilation() {
447457
assert(_the_table != nullptr, "not initialized");
448458

449459
_the_table->add(fmn, ct,
450-
arena_stat->peak_since_start(), // total
451-
arena_stat->na_at_peak(),
452-
arena_stat->ra_at_peak(),
460+
arena_stat->peak(), // total
461+
arena_stat->peak_by_tag(),
453462
arena_stat->live_nodes_at_peak(),
454463
arena_stat->limit(),
455464
result);
@@ -511,7 +520,7 @@ void CompilationMemoryStatistic::on_arena_change(ssize_t diff, const Arena* aren
511520

512521
bool hit_limit_before = arena_stat->hit_limit();
513522

514-
if (arena_stat->account(diff, (int)arena->get_tag())) { // new peak?
523+
if (arena_stat->is_active() && arena_stat->account(diff, (int)arena->get_tag())) { // new peak?
515524

516525
// Limit handling
517526
if (arena_stat->hit_limit()) {
@@ -545,7 +554,7 @@ void CompilationMemoryStatistic::on_arena_change(ssize_t diff, const Arena* aren
545554
}
546555
ss.print("Hit MemLimit %s(limit: %zu now: %zu)",
547556
(hit_limit_before ? "again " : ""),
548-
arena_stat->limit(), arena_stat->peak_since_start());
557+
arena_stat->limit(), arena_stat->peak());
549558
}
550559

551560
// log if needed

‎src/hotspot/share/compiler/compilationMemoryStatistic.hpp

+38-16
Original file line numberDiff line numberDiff line change
@@ -29,48 +29,70 @@
2929
#include "compiler/compilerDefinitions.hpp"
3030
#include "memory/allocation.hpp"
3131
#include "memory/allStatic.hpp"
32+
#include "memory/arena.hpp"
3233
#include "utilities/globalDefinitions.hpp"
3334

3435
class outputStream;
3536
class Symbol;
3637
class DirectiveSet;
3738

38-
// Counters for allocations from one arena
39+
// Helper class to wrap the array of arena tags for easier processing
40+
class ArenaCountersByTag {
41+
private:
42+
size_t _counter[Arena::tag_count()];
43+
44+
public:
45+
int element_count() const { return Arena::tag_count(); }
46+
const char* tag_name(int tag) const { return Arena::tag_name[tag]; }
47+
48+
size_t counter(int tag) const {
49+
assert(tag < element_count(), "invalid tag %d", tag);
50+
return _counter[tag];
51+
}
52+
53+
void add(int tag, size_t value) {
54+
assert(tag < element_count(), "invalid tag %d", tag);
55+
_counter[tag] += value;
56+
}
57+
58+
void clear() {
59+
memset(_counter, 0, sizeof(size_t) * element_count());
60+
}
61+
};
62+
63+
// Counters for allocations from arenas during compilation
3964
class ArenaStatCounter : public CHeapObj<mtCompiler> {
4065
// Current bytes, total
4166
size_t _current;
42-
// bytes when compilation started
43-
size_t _start;
4467
// bytes at last peak, total
4568
size_t _peak;
46-
// Current bytes used for node arenas, total
47-
size_t _na;
48-
// Current bytes used for resource areas
49-
size_t _ra;
69+
// Current bytes used by arenas per tag
70+
ArenaCountersByTag _current_by_tag;
71+
// Peak composition:
72+
ArenaCountersByTag _peak_by_tag;
5073
// MemLimit handling
5174
size_t _limit;
5275
bool _hit_limit;
5376
bool _limit_in_process;
5477

55-
// Peak composition:
56-
// Size of node arena when total peaked (c2 only)
57-
size_t _na_at_peak;
58-
// Size of resource area when total peaked
59-
size_t _ra_at_peak;
78+
// When to start accounting
79+
bool _active;
80+
6081
// Number of live nodes when total peaked (c2 only)
6182
unsigned _live_nodes_at_peak;
6283

6384
void update_c2_node_count();
6485

86+
void reset();
87+
6588
public:
6689
ArenaStatCounter();
6790

6891
// Size of peak since last compilation
69-
size_t peak_since_start() const;
92+
size_t peak() const { return _peak; }
7093

7194
// Peak details
72-
size_t na_at_peak() const { return _na_at_peak; }
73-
size_t ra_at_peak() const { return _ra_at_peak; }
95+
ArenaCountersByTag peak_by_tag() const { return _peak_by_tag; }
7496
unsigned live_nodes_at_peak() const { return _live_nodes_at_peak; }
7597

7698
// Mark the start and end of a compilation.
@@ -89,7 +111,7 @@ class ArenaStatCounter : public CHeapObj<mtCompiler> {
89111
bool hit_limit() const { return _hit_limit; }
90112
bool limit_in_process() const { return _limit_in_process; }
91113
void set_limit_in_process(bool v) { _limit_in_process = v; }
92-
114+
bool is_active() const { return _active; }
93115
};
94116

95117
class CompilationMemoryStatistic : public AllStatic {

‎src/hotspot/share/memory/arena.cpp

+13
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,19 @@ STATIC_ASSERT(is_aligned((int)Chunk::init_size, ARENA_AMALLOC_ALIGNMENT));
4444
STATIC_ASSERT(is_aligned((int)Chunk::medium_size, ARENA_AMALLOC_ALIGNMENT));
4545
STATIC_ASSERT(is_aligned((int)Chunk::size, ARENA_AMALLOC_ALIGNMENT));
4646

47+
48+
const char* Arena::tag_name[] = {
49+
#define ARENA_TAG_STRING(name, str, desc) XSTR(name),
50+
DO_ARENA_TAG(ARENA_TAG_STRING)
51+
#undef ARENA_TAG_STRING
52+
};
53+
54+
const char* Arena::tag_desc[] = {
55+
#define ARENA_TAG_DESC(name, str, desc) XSTR(desc),
56+
DO_ARENA_TAG(ARENA_TAG_DESC)
57+
#undef ARENA_TAG_DESC
58+
};
59+
4760
// MT-safe pool of same-sized chunks to reduce malloc/free thrashing
4861
// NB: not using Mutex because pools are used before Threads are initialized
4962
class ChunkPool {

‎src/hotspot/share/memory/arena.hpp

+18-6
Original file line numberDiff line numberDiff line change
@@ -83,17 +83,29 @@ class Chunk {
8383
bool contains(char* p) const { return bottom() <= p && p <= top(); }
8484
};
8585

86+
#define DO_ARENA_TAG(FN) \
87+
FN(other, Others, Other arenas) \
88+
FN(ra, RA, Resource areas) \
89+
FN(ha, HA, Handle area) \
90+
FN(node, NA, Node arena) \
91+
8692
// Fast allocation of memory
8793
class Arena : public CHeapObjBase {
8894
public:
89-
90-
enum class Tag : uint8_t {
91-
tag_other = 0,
92-
tag_ra, // resource area
93-
tag_ha, // handle area
94-
tag_node // C2 Node arena
95+
enum class Tag: uint8_t {
96+
#define ARENA_TAG_ENUM(name, str, desc) tag_##name,
97+
DO_ARENA_TAG(ARENA_TAG_ENUM)
98+
#undef ARENA_TAG_ENUM
99+
tag_count
95100
};
96101

102+
constexpr static int tag_count() {
103+
return static_cast<int>(Tag::tag_count);
104+
}
105+
106+
static const char* tag_name[static_cast<int>(Arena::Tag::tag_count)];
107+
static const char* tag_desc[static_cast<int>(Arena::Tag::tag_count)];
108+
97109
private:
98110
const MEMFLAGS _flags; // Memory tracking flags
99111
const Tag _tag;

‎test/hotspot/jtreg/compiler/print/CompileCommandPrintMemStat.java

+6-5
Original file line numberDiff line numberDiff line change
@@ -77,16 +77,17 @@ private static void test(String include, String exclude) throws Exception {
7777

7878
// Should see final report
7979
// Looks like this:
80-
// total NA RA result #nodes limit time type #rc thread method
81-
// 2149912 0 1986272 ok - - 0.101 c1 1 0x000000015180a600 jdk/internal/org/objectweb/asm/Frame::execute((IILjdk/internal/org/objectweb/asm/Symbol;Ljdk/internal/org/objectweb/asm/SymbolTable;)V) oa.shouldMatch("total.*method");
80+
// total Others RA HA NA result #nodes limit time type #rc thread method
81+
// 523648 32728 490920 0 0 ok - - 0.250 c1 1 0x00007f4ec00d4ac0 java/lang/Class::descriptorString(()Ljava/lang/String;)
8282
// or
83-
// 537784 98184 208536 ok 267 - 0.096 c2 1 0x0000000153019c00 jdk/internal/classfile/impl/BufWriterImpl::writeU1((I)V) 4521912 0 1986272 ok - - 0.101 c1 1 0x000000015180a600 jdk/internal/org/objectweb/asm/Frame::execute((IILjdk/internal/org/objectweb/asm/Symbol;Ljdk/internal/org/objectweb/asm/SymbolTable;)V) oa.shouldMatch("total.*method");
84-
oa.shouldMatch("\\d+ +\\d+ +\\d+ +ok +(\\d+|-) +.*" + expectedNameIncl + ".*");
83+
// 1898600 853176 750872 0 294552 ok 934 - 1.501 c2 1 0x00007f4ec00d3330 java/lang/String::replace((CC)Ljava/lang/String;)
84+
oa.shouldMatch("total.*method");
85+
oa.shouldMatch("\\d+ +(\\d+ +){4}ok +(\\d+|-) +.*" + expectedNameIncl + ".*");
8586

8687
// In debug builds, we have a default memory limit enabled. That implies MemStat. Therefore we
8788
// expect to see all methods, not just the one we specified on the command line.
8889
if (Platform.isDebugBuild()) {
89-
oa.shouldMatch("\\d+ +\\d+ +\\d+ +ok +(\\d+|-) +.*" + expectedNameExcl + ".*");
90+
oa.shouldMatch("\\d+ +(\\d+ +){4}ok +(\\d+|-) +.*" + expectedNameExcl + ".*");
9091
} else {
9192
oa.shouldNotMatch(".*" + expectedNameExcl + ".*");
9293
}

‎test/hotspot/jtreg/serviceability/dcmd/compiler/CompilerMemoryStatisticTest.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ public static void main(String args[]) throws Exception {
4747
out.shouldHaveExitValue(0);
4848

4949
// Looks like this:
50-
// total NA RA result #nodes time type #rc thread method
51-
// 211488 66440 77624 ok 13 0.057 c2 2 0x00007fb49428db70 compiler/print/CompileCommandPrintMemStat$TestMain::method1(()V)
50+
// total Others RA HA NA result #nodes limit time type #rc thread method
51+
// 1898600 853176 750872 0 294552 ok 934 - 1.501 c2 1 0x00007f4ec00d3330 java/lang/String::replace((CC)Ljava/lang/String;)
5252
out.shouldMatch("total.*method");
53-
out.shouldMatch("\\d+ +\\d+ +\\d+ +\\S+ +\\d+.*java.*\\(.*\\)");
53+
out.shouldMatch("\\d+ +(\\d+ +){4}\\S+ +\\d+.*java.*\\(.*\\)");
5454
}
5555
}

0 commit comments

Comments
 (0)
Please sign in to comment.