2
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
3
* Copyright (c) 2023, 2024, Red Hat, Inc. and/or its affiliates.
4
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6
* This code is free software; you can redistribute it and/or modify it
7
* under the terms of the GNU General Public License version 2 only, as
8
* published by the Free Software Foundation.
10
* This code is distributed in the hope that it will be useful, but WITHOUT
11
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13
* version 2 for more details (a copy is included in the LICENSE file that
14
* accompanied this code).
16
* You should have received a copy of the GNU General Public License version
17
* 2 along with this work; if not, write to the Free Software Foundation,
18
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21
* or visit www.oracle.com if you need additional information or have any
26
#include "precompiled.hpp"
27
#include "logging/log.hpp"
28
#include "logging/logStream.hpp"
30
#include "c1/c1_Compilation.hpp"
32
#include "compiler/abstractCompiler.hpp"
33
#include "compiler/compilationMemoryStatistic.hpp"
34
#include "compiler/compilerDirectives.hpp"
35
#include "compiler/compileTask.hpp"
36
#include "compiler/compilerDefinitions.hpp"
37
#include "compiler/compilerThread.hpp"
38
#include "memory/arena.hpp"
39
#include "memory/resourceArea.hpp"
40
#include "nmt/nmtCommon.hpp"
41
#include "oops/symbol.hpp"
43
#include "opto/node.hpp" // compile.hpp is not self-contained
44
#include "opto/compile.hpp"
46
#include "runtime/mutexLocker.hpp"
47
#include "runtime/os.hpp"
48
#include "utilities/debug.hpp"
49
#include "utilities/globalDefinitions.hpp"
50
#include "utilities/ostream.hpp"
51
#include "utilities/quickSort.hpp"
52
#include "utilities/resourceHash.hpp"
54
ArenaStatCounter::ArenaStatCounter() :
55
_current(0), _start(0), _peak(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)
61
size_t ArenaStatCounter::peak_since_start() const {
62
return _peak > _start ? _peak - _start : 0;
65
void ArenaStatCounter::start(size_t limit) {
66
_peak = _start = _current;
71
void ArenaStatCounter::end(){
76
void ArenaStatCounter::update_c2_node_count() {
78
CompilerThread* const th = Thread::current()->as_Compiler_thread();
79
const CompileTask* const task = th->task();
80
if (task != nullptr &&
81
th->task()->compiler() != nullptr &&
82
th->task()->compiler()->type() == compiler_c2) {
83
const Compile* const comp = Compile::current();
84
if (comp != nullptr) {
85
_live_nodes_at_peak = comp->live_nodes();
91
// Account an arena allocation or de-allocation.
92
bool ArenaStatCounter::account(ssize_t delta, int tag) {
95
// Note: if this fires, we free more arena memory under the scope of the
96
// CompilationMemoryHistoryMark than we allocate. This cannot be since we
97
// assume arena allocations in CompilerThread to be stack bound and symmetric.
98
assert(delta >= 0 || ((ssize_t)_current + delta) >= 0,
99
"Negative overflow (d=%zd %zu %zu %zu)", delta, _current, _start, _peak);
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;
110
// Did we reach a peak?
111
if (_current > _peak) {
113
assert(delta > 0, "Sanity (%zu %zu %zu)", _current, _start, _peak);
116
update_c2_node_count();
118
// Did we hit the memory limit?
119
if (!_hit_limit && _limit > 0 && peak_since_start() > _limit) {
126
void ArenaStatCounter::print_on(outputStream* st) const {
127
st->print("%zu [na %zu ra %zu]", peak_since_start(), _na_at_peak, _ra_at_peak);
129
st->print(" (%zu->%zu->%zu)", _start, _peak, _current);
133
//////////////////////////
136
class FullMethodName {
143
FullMethodName(const Method* m) :
144
_k(m->klass_name()), _m(m->name()), _s(m->signature()) {};
145
FullMethodName(const FullMethodName& o) : _k(o._k), _m(o._m), _s(o._s) {}
147
void make_permanent() {
148
_k->make_permanent();
149
_m->make_permanent();
150
_s->make_permanent();
153
static unsigned compute_hash(const FullMethodName& n) {
154
return Symbol::compute_hash(n._k) ^
155
Symbol::compute_hash(n._m) ^
156
Symbol::compute_hash(n._s);
159
char* as_C_string(char* buf, size_t len) const {
160
stringStream ss(buf, len);
162
ss.print_raw(_k->as_C_string());
164
ss.print_raw(_m->as_C_string());
166
ss.print_raw(_s->as_C_string());
170
bool operator== (const FullMethodName& b) const {
171
return _k == b._k && _m == b._m && _s == b._s;
175
// Note: not mtCompiler since we don't want to change what we measure
176
class MemStatEntry : public CHeapObj<mtInternal> {
177
const FullMethodName _method;
178
CompilerType _comptype;
180
// How often this has been recompiled.
182
// Compiling thread. Only for diagnostic purposes. Thread may not be alive anymore.
183
const Thread* _thread;
184
// active limit for this compilation, if any
187
// peak usage, bytes, over all arenas
189
// usage in node arena when total peaked
191
// usage in resource area when total peaked
193
// number of nodes (c2 only) when total peaked
194
unsigned _live_nodes_at_peak;
199
MemStatEntry(FullMethodName method)
200
: _method(method), _comptype(compiler_c1),
201
_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),
206
void set_comptype(CompilerType comptype) { _comptype = comptype; }
207
void set_current_time() { _time = os::elapsedTime(); }
208
void set_current_thread() { _thread = Thread::current(); }
209
void set_limit(size_t limit) { _limit = limit; }
210
void inc_recompilation() { _num_recomp++; }
212
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; }
215
void set_live_nodes_at_peak(unsigned n) { _live_nodes_at_peak = n; }
217
void set_result(const char* s) { _result = s; }
219
size_t total() const { return _total; }
221
static void print_legend(outputStream* st) {
222
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");
235
static void print_header(outputStream* st) {
236
st->print_cr("total NA RA result #nodes limit time type #rc thread method");
239
void print_on(outputStream* st, bool human_readable) const {
243
if (human_readable) {
244
st->print(PROPERFMT " ", PROPERFMTARGS(_total));
246
st->print("%zu ", _total);
248
col += 10; st->fill_to(col);
251
if (human_readable) {
252
st->print(PROPERFMT " ", PROPERFMTARGS(_na_at_peak));
254
st->print("%zu ", _na_at_peak);
256
col += 10; st->fill_to(col);
259
if (human_readable) {
260
st->print(PROPERFMT " ", PROPERFMTARGS(_ra_at_peak));
262
st->print("%zu ", _ra_at_peak);
264
col += 10; st->fill_to(col);
267
st->print("%s ", _result ? _result : "");
268
col += 8; st->fill_to(col);
270
// Number of Nodes when memory peaked
271
if (_live_nodes_at_peak > 0) {
272
st->print("%u ", _live_nodes_at_peak);
276
col += 8; st->fill_to(col);
280
st->print(PROPERFMT " ", PROPERFMTARGS(_limit));
284
col += 8; st->fill_to(col);
287
st->print("%.3f ", _time);
288
col += 8; st->fill_to(col);
291
st->print("%s ", compilertype2name(_comptype));
292
col += 6; st->fill_to(col);
295
st->print("%u ", _num_recomp);
296
col += 4; st->fill_to(col);
299
st->print(PTR_FORMAT " ", p2i(_thread));
303
st->print("%s ", _method.as_C_string(buf, sizeof(buf)));
307
int compare_by_size(const MemStatEntry* b) const {
308
const size_t x1 = b->_total;
309
const size_t x2 = _total;
310
return x1 < x2 ? -1 : x1 == x2 ? 0 : 1;
314
// The MemStatTable contains records of memory usage of all compilations. It is printed,
315
// as memory summary, either with jcmd Compiler.memory, or - if the "print" suboption has
316
// been given with the MemStat compile command - as summary printout at VM exit.
317
// For any given compiled method, we only keep the memory statistics of the most recent
318
// compilation, but on a per-compiler basis. If one needs statistics of prior compilations,
319
// one needs to look into the log produced by the "print" suboption.
321
class MemStatTableKey {
322
const FullMethodName _fmn;
323
const CompilerType _comptype;
325
MemStatTableKey(FullMethodName fmn, CompilerType comptype) :
326
_fmn(fmn), _comptype(comptype) {}
327
MemStatTableKey(const MemStatTableKey& o) :
328
_fmn(o._fmn), _comptype(o._comptype) {}
329
bool operator== (const MemStatTableKey& other) const {
330
return _fmn == other._fmn && _comptype == other._comptype;
332
static unsigned compute_hash(const MemStatTableKey& n) {
333
return FullMethodName::compute_hash(n._fmn) + (unsigned)n._comptype;
338
public ResourceHashtable<MemStatTableKey, MemStatEntry*, 7919, AnyObj::C_HEAP,
339
mtInternal, MemStatTableKey::compute_hash>
343
void add(const FullMethodName& fmn, CompilerType comptype,
344
size_t total, size_t na_at_peak, size_t ra_at_peak,
345
unsigned live_nodes_at_peak, size_t limit, const char* result) {
346
assert_lock_strong(NMTCompilationCostHistory_lock);
347
MemStatTableKey key(fmn, comptype);
348
MemStatEntry** pe = get(key);
349
MemStatEntry* e = nullptr;
351
e = new MemStatEntry(fmn);
354
// Update existing entry
356
assert(e != nullptr, "Sanity");
358
e->set_current_time();
359
e->set_current_thread();
360
e->set_comptype(comptype);
361
e->inc_recompilation();
363
e->set_na_at_peak(na_at_peak);
364
e->set_ra_at_peak(ra_at_peak);
365
e->set_live_nodes_at_peak(live_nodes_at_peak);
367
e->set_result(result);
370
// Returns a C-heap-allocated SortMe array containing all entries from the table,
371
// optionally filtered by entry size
372
MemStatEntry** calc_flat_array(int& num, size_t min_size) {
373
assert_lock_strong(NMTCompilationCostHistory_lock);
375
const int num_all = number_of_entries();
376
MemStatEntry** flat = NEW_C_HEAP_ARRAY(MemStatEntry*, num_all, mtInternal);
378
auto do_f = [&] (const MemStatTableKey& ignored, MemStatEntry* e) {
379
if (e->total() >= min_size) {
381
assert(i < num_all, "Sanity");
387
assert(i == num_all, "Sanity");
389
assert(i <= num_all, "Sanity");
396
bool CompilationMemoryStatistic::_enabled = false;
398
static MemStatTable* _the_table = nullptr;
400
void CompilationMemoryStatistic::initialize() {
401
assert(_enabled == false && _the_table == nullptr, "Only once");
402
_the_table = new (mtCompiler) MemStatTable;
404
log_info(compilation, alloc)("Compilation memory statistic enabled");
407
void CompilationMemoryStatistic::on_start_compilation(const DirectiveSet* directive) {
408
assert(enabled(), "Not enabled?");
409
const size_t limit = directive->mem_limit();
410
Thread::current()->as_Compiler_thread()->arena_stat()->start(limit);
413
void CompilationMemoryStatistic::on_end_compilation() {
414
assert(enabled(), "Not enabled?");
416
CompilerThread* const th = Thread::current()->as_Compiler_thread();
417
ArenaStatCounter* const arena_stat = th->arena_stat();
418
CompileTask* const task = th->task();
419
const CompilerType ct = task->compiler()->type();
421
const Method* const m = th->task()->method();
422
FullMethodName fmn(m);
423
fmn.make_permanent();
425
const DirectiveSet* directive = th->task()->directive();
426
assert(directive->should_collect_memstat(), "Should only be called if memstat is enabled for this method");
427
const bool print = directive->should_print_memstat();
429
// Store memory used in task, for later processing by JFR
430
task->set_arena_bytes(arena_stat->peak_since_start());
433
// For this to work, we must call on_end_compilation() at a point where
434
// Compile|Compilation already handed over the failure string to ciEnv,
435
// but ciEnv must still be alive.
436
const char* result = "ok"; // ok
437
const ciEnv* const env = th->env();
439
const char* const failure_reason = env->failure_reason();
440
if (failure_reason != nullptr) {
441
result = (strcmp(failure_reason, failure_reason_memlimit()) == 0) ? "oom" : "err";
446
MutexLocker ml(NMTCompilationCostHistory_lock, Mutex::_no_safepoint_check_flag);
447
assert(_the_table != nullptr, "not initialized");
449
_the_table->add(fmn, ct,
450
arena_stat->peak_since_start(), // total
451
arena_stat->na_at_peak(),
452
arena_stat->ra_at_peak(),
453
arena_stat->live_nodes_at_peak(),
459
fmn.as_C_string(buf, sizeof(buf));
460
tty->print("%s Arena usage %s: ", compilertype2name(ct), buf);
461
arena_stat->print_on(tty);
465
arena_stat->end(); // reset things
468
static void inform_compilation_about_oom(CompilerType ct) {
469
// Inform C1 or C2 that an OOM happened. They will take delayed action
470
// and abort the compilation in progress. Note that this is not instantaneous,
471
// since the compiler has to actively bailout, which may take a while, during
472
// which memory usage may rise further.
474
// The mechanism differs slightly between C1 and C2:
475
// - With C1, we directly set the bailout string, which will cause C1 to
476
// bailout at the typical BAILOUT places.
477
// - With C2, the corresponding mechanism would be the failure string; but
478
// bailout paths in C2 are not complete and therefore it is dangerous to
479
// set the failure string at - for C2 - seemingly random places. Instead,
480
// upon OOM C2 sets the failure string next time it checks the node limit.
481
if (ciEnv::current() != nullptr) {
482
void* compiler_data = ciEnv::current()->compiler_data();
484
if (ct == compiler_c1) {
485
Compilation* C = static_cast<Compilation*>(compiler_data);
487
C->bailout(CompilationMemoryStatistic::failure_reason_memlimit());
493
if (ct == compiler_c2) {
494
Compile* C = static_cast<Compile*>(compiler_data);
503
void CompilationMemoryStatistic::on_arena_change(ssize_t diff, const Arena* arena) {
504
assert(enabled(), "Not enabled?");
505
CompilerThread* const th = Thread::current()->as_Compiler_thread();
507
ArenaStatCounter* const arena_stat = th->arena_stat();
508
if (arena_stat->limit_in_process()) {
509
return; // avoid recursion on limit hit
512
bool hit_limit_before = arena_stat->hit_limit();
514
if (arena_stat->account(diff, (int)arena->get_tag())) { // new peak?
517
if (arena_stat->hit_limit()) {
518
char name[1024] = "";
521
CompilerType ct = compiler_none;
523
arena_stat->set_limit_in_process(true); // prevent recursive limit hits
525
// get some more info
526
const CompileTask* const task = th->task();
527
if (task != nullptr) {
528
ct = task->compiler()->type();
529
const DirectiveSet* directive = task->directive();
530
print = directive->should_print_memstat();
531
crash = directive->should_crash_at_mem_limit();
532
const Method* m = th->task()->method();
534
FullMethodName(m).as_C_string(name, sizeof(name));
538
char message[1024] = "";
540
// build up message if we need it later
541
if (print || crash) {
542
stringStream ss(message, sizeof(message));
543
if (ct != compiler_none && name[0] != '\0') {
544
ss.print("%s %s: ", compilertype2name(ct), name);
546
ss.print("Hit MemLimit %s(limit: %zu now: %zu)",
547
(hit_limit_before ? "again " : ""),
548
arena_stat->limit(), arena_stat->peak_since_start());
553
tty->print_raw(message);
557
// Crash out if needed
559
report_fatal(OOM_HOTSPOT_ARENA, __FILE__, __LINE__, "%s", message);
561
inform_compilation_about_oom(ct);
564
arena_stat->set_limit_in_process(false);
569
static inline ssize_t diff_entries_by_size(const MemStatEntry* e1, const MemStatEntry* e2) {
570
return e1->compare_by_size(e2);
573
void CompilationMemoryStatistic::print_all_by_size(outputStream* st, bool human_readable, size_t min_size) {
575
MutexLocker ml(NMTCompilationCostHistory_lock, Mutex::_no_safepoint_check_flag);
578
st->print_cr("Compilation memory statistics");
581
st->print_cr("(unavailable)");
587
MemStatEntry::print_legend(st);
591
st->print_cr(" (cutoff: %zu bytes)", min_size);
595
MemStatEntry::print_header(st);
597
MemStatEntry** filtered = nullptr;
599
if (_the_table != nullptr) {
600
// We sort with quicksort
602
filtered = _the_table->calc_flat_array(num, min_size);
604
st->print_cr("(%d/%d)", num, _the_table->number_of_entries());
607
QuickSort::sort(filtered, num, diff_entries_by_size);
608
// Now print. Has to happen under lock protection too, since entries may be changed.
609
for (int i = 0; i < num; i ++) {
610
filtered[i]->print_on(st, human_readable);
613
st->print_cr("No entries.");
616
st->print_cr("Not initialized.");
620
FREE_C_HEAP_ARRAY(Entry, filtered);
623
const char* CompilationMemoryStatistic::failure_reason_memlimit() {
624
static const char* const s = "hit memory limit while compiling";
628
CompilationMemoryStatisticMark::CompilationMemoryStatisticMark(const DirectiveSet* directive)
629
: _active(directive->should_collect_memstat()) {
631
CompilationMemoryStatistic::on_start_compilation(directive);
634
CompilationMemoryStatisticMark::~CompilationMemoryStatisticMark() {
636
CompilationMemoryStatistic::on_end_compilation();