2626#include " precompiled.hpp"
2727#include " logging/log.hpp"
2828#include " logging/logStream.hpp"
29+ #ifdef COMPILER1
30+ #include " c1/c1_Compilation.hpp"
31+ #endif
2932#include " compiler/abstractCompiler.hpp"
3033#include " compiler/compilationMemoryStatistic.hpp"
3134#include " compiler/compilerDirectives.hpp"
4245#endif
4346#include " runtime/mutexLocker.hpp"
4447#include " runtime/os.hpp"
48+ #include " utilities/debug.hpp"
4549#include " utilities/globalDefinitions.hpp"
4650#include " utilities/ostream.hpp"
4751#include " utilities/quickSort.hpp"
4852#include " utilities/resourceHash.hpp"
4953
50-
5154ArenaStatCounter::ArenaStatCounter () :
5255 _current(0 ), _start(0 ), _peak(0 ),
5356 _na(0 ), _ra(0 ),
57+ _limit(0 ), _hit_limit(false ),
5458 _na_at_peak(0 ), _ra_at_peak(0 ), _live_nodes_at_peak(0 )
5559{}
5660
5761size_t ArenaStatCounter::peak_since_start () const {
5862 return _peak > _start ? _peak - _start : 0 ;
5963}
6064
61- void ArenaStatCounter::start () {
65+ void ArenaStatCounter::start (size_t limit ) {
6266 _peak = _start = _current;
67+ _limit = limit;
68+ _hit_limit = false ;
69+ }
70+
71+ void ArenaStatCounter::end (){
72+ _limit = 0 ;
73+ _hit_limit = false ;
6374}
6475
6576void ArenaStatCounter::update_c2_node_count () {
@@ -104,6 +115,10 @@ bool ArenaStatCounter::account(ssize_t delta, int tag) {
104115 _ra_at_peak = _ra;
105116 update_c2_node_count ();
106117 rc = true ;
118+ // Did we hit the memory limit?
119+ if (!_hit_limit && _limit > 0 && peak_since_start () > _limit) {
120+ _hit_limit = true ;
121+ }
107122 }
108123 return rc;
109124}
@@ -125,7 +140,8 @@ class FullMethodName {
125140
126141public:
127142
128- FullMethodName (Symbol* k, Symbol* m, Symbol* s) : _k(k), _m(m), _s(s) {}
143+ FullMethodName (const Method* m) :
144+ _k (m->klass_name ()), _m(m->name ()), _s(m->signature ()) {};
129145 FullMethodName (const FullMethodName& o) : _k(o._k), _m(o._m), _s(o._s) {}
130146
131147 void make_permanent () {
@@ -173,13 +189,15 @@ class MemStatEntry : public CHeapObj<mtInternal> {
173189 size_t _na_at_peak;
174190 size_t _ra_at_peak;
175191 unsigned _live_nodes_at_peak;
192+ const char * _result;
176193
177194public:
178195
179196 MemStatEntry (FullMethodName method)
180197 : _method(method), _comptype(compiler_c1),
181198 _time (0 ), _num_recomp(0 ), _thread(nullptr ),
182- _total(0 ), _na_at_peak(0 ), _ra_at_peak(0 ), _live_nodes_at_peak(0 ) {
199+ _total(0 ), _na_at_peak(0 ), _ra_at_peak(0 ), _live_nodes_at_peak(0 ),
200+ _result(nullptr ) {
183201 }
184202
185203 void set_comptype (CompilerType comptype) { _comptype = comptype; }
@@ -192,22 +210,25 @@ class MemStatEntry : public CHeapObj<mtInternal> {
192210 void set_ra_at_peak (size_t n) { _ra_at_peak = n; }
193211 void set_live_nodes_at_peak (unsigned n) { _live_nodes_at_peak = n; }
194212
213+ void set_result (const char * s) { _result = s; }
214+
195215 size_t total () const { return _total; }
196216
197217 static void print_legend (outputStream* st) {
198218 st->print_cr (" Legend:" );
199219 st->print_cr (" total : memory allocated via arenas while compiling" );
200220 st->print_cr (" NA : ...how much in node arenas (if c2)" );
201221 st->print_cr (" RA : ...how much in resource areas" );
202- st->print_cr (" #nodes : ...how many nodes (if c2)" );
222+ st->print_cr (" result : Result: 'ok' finished successfully, 'oom' hit memory limit, 'err' compilation failed" );
223+ st->print_cr (" #nodes : ...how many nodes (c2 only)" );
203224 st->print_cr (" time : time of last compilation (sec)" );
204225 st->print_cr (" type : compiler type" );
205226 st->print_cr (" #rc : how often recompiled" );
206227 st->print_cr (" thread : compiler thread" );
207228 }
208229
209230 static void print_header (outputStream* st) {
210- st->print_cr (" total NA RA #nodes time type #rc thread method" );
231+ st->print_cr (" total NA RA result #nodes time type #rc thread method" );
211232 }
212233
213234 void print_on (outputStream* st, bool human_readable) const {
@@ -237,6 +258,10 @@ class MemStatEntry : public CHeapObj<mtInternal> {
237258 }
238259 col += 10 ; st->fill_to (col);
239260
261+ // result?
262+ st->print (" %s " , _result ? _result : " " );
263+ col += 8 ; st->fill_to (col);
264+
240265 // Number of Nodes when memory peaked
241266 st->print (" %u " , _live_nodes_at_peak);
242267 col += 8 ; st->fill_to (col);
@@ -281,7 +306,7 @@ class MemStatTable :
281306
282307 void add (const FullMethodName& fmn, CompilerType comptype,
283308 size_t total, size_t na_at_peak, size_t ra_at_peak,
284- unsigned live_nodes_at_peak) {
309+ unsigned live_nodes_at_peak, const char * result ) {
285310 assert_lock_strong (NMTCompilationCostHistory_lock);
286311
287312 MemStatEntry** pe = get (fmn);
@@ -302,6 +327,7 @@ class MemStatTable :
302327 e->set_na_at_peak (na_at_peak);
303328 e->set_ra_at_peak (ra_at_peak);
304329 e->set_live_nodes_at_peak (live_nodes_at_peak);
330+ e->set_result (result);
305331 }
306332
307333 // Returns a C-heap-allocated SortMe array containing all entries from the table,
@@ -341,20 +367,21 @@ void CompilationMemoryStatistic::initialize() {
341367 log_info (compilation, alloc)(" Compilation memory statistic enabled" );
342368}
343369
344- void CompilationMemoryStatistic::on_start_compilation () {
370+ void CompilationMemoryStatistic::on_start_compilation (const DirectiveSet* directive ) {
345371 assert (enabled (), " Not enabled?" );
346- Thread::current ()->as_Compiler_thread ()->arena_stat ()->start ();
372+ const size_t limit = directive->mem_limit ();
373+ Thread::current ()->as_Compiler_thread ()->arena_stat ()->start (limit);
347374}
348375
349376void CompilationMemoryStatistic::on_end_compilation () {
350377 assert (enabled (), " Not enabled?" );
351378 ResourceMark rm;
352379 CompilerThread* const th = Thread::current ()->as_Compiler_thread ();
353- const ArenaStatCounter* const arena_stat = th->arena_stat ();
380+ ArenaStatCounter* const arena_stat = th->arena_stat ();
354381 const CompilerType ct = th->task ()->compiler ()->type ();
355382
356383 const Method* const m = th->task ()->method ();
357- FullMethodName fmn (m-> klass_name (), m-> name (), m-> signature () );
384+ FullMethodName fmn (m);
358385 fmn.make_permanent ();
359386
360387 const DirectiveSet* directive = th->task ()->directive ();
@@ -368,6 +395,20 @@ void CompilationMemoryStatistic::on_end_compilation() {
368395 arena_stat->print_on (tty);
369396 tty->cr ();
370397 }
398+
399+ // Store result
400+ // For this to work, we must call on_end_compilation() at a point where
401+ // Compile|Compilation already handed over the failure string to ciEnv,
402+ // but ciEnv must still be alive.
403+ const char * result = " ok" ; // ok
404+ const ciEnv* const env = th->env ();
405+ if (env) {
406+ const char * const failure_reason = env->failure_reason ();
407+ if (failure_reason != nullptr ) {
408+ result = (failure_reason == failure_reason_memlimit ()) ? " oom" : " err" ;
409+ }
410+ }
411+
371412 {
372413 MutexLocker ml (NMTCompilationCostHistory_lock, Mutex::_no_safepoint_check_flag);
373414 assert (_the_table != nullptr , " not initialized" );
@@ -376,14 +417,105 @@ void CompilationMemoryStatistic::on_end_compilation() {
376417 arena_stat->peak_since_start (), // total
377418 arena_stat->na_at_peak (),
378419 arena_stat->ra_at_peak (),
379- arena_stat->live_nodes_at_peak ());
420+ arena_stat->live_nodes_at_peak (),
421+ result);
422+ }
423+
424+ arena_stat->end (); // reset things
425+ }
426+
427+ static void inform_compilation_about_oom (CompilerType ct) {
428+ // Inform C1 or C2 that an OOM happened. They will take delayed action
429+ // and abort the compilation in progress. Note that this is not instantaneous,
430+ // since the compiler has to actively bailout, which may take a while, during
431+ // which memory usage may rise further.
432+ //
433+ // The mechanism differs slightly between C1 and C2:
434+ // - With C1, we directly set the bailout string, which will cause C1 to
435+ // bailout at the typical BAILOUT places.
436+ // - With C2, the corresponding mechanism would be the failure string; but
437+ // bailout paths in C2 are not complete and therefore it is dangerous to
438+ // set the failure string at - for C2 - seemingly random places. Instead,
439+ // upon OOM C2 sets the failure string next time it checks the node limit.
440+ if (ciEnv::current () != nullptr ) {
441+ void * compiler_data = ciEnv::current ()->compiler_data ();
442+ #ifdef COMPILER1
443+ if (ct == compiler_c1) {
444+ Compilation* C = static_cast <Compilation*>(compiler_data);
445+ if (C != nullptr ) {
446+ C->bailout (CompilationMemoryStatistic::failure_reason_memlimit ());
447+ C->set_oom ();
448+ }
449+ }
450+ #endif
451+ #ifdef COMPILER2
452+ if (ct == compiler_c2) {
453+ Compile* C = static_cast <Compile*>(compiler_data);
454+ if (C != nullptr ) {
455+ C->set_oom ();
456+ }
457+ }
458+ #endif // COMPILER2
380459 }
381460}
382461
383462void CompilationMemoryStatistic::on_arena_change (ssize_t diff, const Arena* arena) {
384463 assert (enabled (), " Not enabled?" );
385464 CompilerThread* const th = Thread::current ()->as_Compiler_thread ();
386- th->arena_stat ()->account (diff, (int )arena->get_tag ());
465+
466+ ArenaStatCounter* const arena_stat = th->arena_stat ();
467+ bool hit_limit_before = arena_stat->hit_limit ();
468+
469+ if (arena_stat->account (diff, (int )arena->get_tag ())) { // new peak?
470+
471+ // Limit handling
472+ if (arena_stat->hit_limit ()) {
473+
474+ char name[1024 ] = " " ;
475+ bool print = false ;
476+ bool crash = false ;
477+ CompilerType ct = compiler_none;
478+
479+ // get some more info
480+ const CompileTask* task = th->task ();
481+ if (task != nullptr ) {
482+ ct = task->compiler ()->type ();
483+ const DirectiveSet* directive = task->directive ();
484+ print = directive->should_print_memstat ();
485+ crash = directive->should_crash_at_mem_limit ();
486+ const Method* m = th->task ()->method ();
487+ if (m != nullptr ) {
488+ FullMethodName (m).as_C_string (name, sizeof (name));
489+ }
490+ }
491+
492+ char message[1024 ] = " " ;
493+
494+ // build up message if we need it later
495+ if (print || crash) {
496+ stringStream ss (message, sizeof (message));
497+ if (ct != compiler_none && name[0 ] != ' \0 ' ) {
498+ ss.print (" %s %s: " , compilertype2name (ct), name);
499+ }
500+ ss.print (" Hit MemLimit %s (limit: %zu now: %zu)" ,
501+ (hit_limit_before ? " again" : " " ),
502+ arena_stat->limit (), arena_stat->peak_since_start ());
503+ }
504+
505+ // log if needed
506+ if (print) {
507+ tty->print_raw (message);
508+ tty->cr ();
509+ }
510+
511+ // Crash out if needed
512+ if (crash) {
513+ report_fatal (OOM_HOTSPOT_ARENA, __FILE__, __LINE__, " %s" , message);
514+ } else {
515+ inform_compilation_about_oom (ct);
516+ }
517+ }
518+ }
387519}
388520
389521static inline ssize_t diff_entries_by_size (const MemStatEntry* e1 , const MemStatEntry* e2 ) {
@@ -438,10 +570,15 @@ void CompilationMemoryStatistic::print_all_by_size(outputStream* st, bool human_
438570 FREE_C_HEAP_ARRAY (Entry, filtered);
439571}
440572
573+ const char * CompilationMemoryStatistic::failure_reason_memlimit () {
574+ static const char * const s = " hit memory limit while compiling" ;
575+ return s;
576+ }
577+
441578CompilationMemoryStatisticMark::CompilationMemoryStatisticMark (const DirectiveSet* directive)
442579 : _active(directive->should_collect_memstat ()) {
443580 if (_active) {
444- CompilationMemoryStatistic::on_start_compilation ();
581+ CompilationMemoryStatistic::on_start_compilation (directive );
445582 }
446583}
447584CompilationMemoryStatisticMark::~CompilationMemoryStatisticMark () {
0 commit comments