Mercurial > hg > openjdk > bsd-port > hotspot
changeset 4718:e50c5a1869b1 hs24-b46
Merge
author | amurillo |
---|---|
date | Thu, 23 May 2013 13:57:41 -0700 |
parents | af383e67806b (current diff) f2a9de120e2d (diff) |
children | f2614c006bb7 |
files | |
diffstat | 29 files changed, 321 insertions(+), 103 deletions(-) [+] |
line wrap: on
line diff
--- a/make/hotspot_version Wed May 22 16:01:50 2013 -0700 +++ b/make/hotspot_version Thu May 23 13:57:41 2013 -0700 @@ -35,7 +35,7 @@ HS_MAJOR_VER=24 HS_MINOR_VER=0 -HS_BUILD_NUMBER=45 +HS_BUILD_NUMBER=46 JDK_MAJOR_VER=1 JDK_MINOR_VER=7
--- a/make/jprt.properties Wed May 22 16:01:50 2013 -0700 +++ b/make/jprt.properties Thu May 23 13:57:41 2013 -0700 @@ -38,7 +38,7 @@ # This tells jprt what default release we want to build -jprt.hotspot.default.release=jdk7u14 +jprt.hotspot.default.release=jdk7u40 jprt.tools.default.release=${jprt.submit.option.release?${jprt.submit.option.release}:${jprt.hotspot.default.release}} @@ -54,97 +54,97 @@ # Define the Solaris platforms we want for the various releases jprt.my.solaris.sparc.jdk8=solaris_sparc_5.10 jprt.my.solaris.sparc.jdk7=solaris_sparc_5.10 -jprt.my.solaris.sparc.jdk7u14=${jprt.my.solaris.sparc.jdk7} +jprt.my.solaris.sparc.jdk7u40=${jprt.my.solaris.sparc.jdk7} jprt.my.solaris.sparc=${jprt.my.solaris.sparc.${jprt.tools.default.release}} jprt.my.solaris.sparcv9.jdk8=solaris_sparcv9_5.10 jprt.my.solaris.sparcv9.jdk7=solaris_sparcv9_5.10 -jprt.my.solaris.sparcv9.jdk7u14=${jprt.my.solaris.sparcv9.jdk7} +jprt.my.solaris.sparcv9.jdk7u40=${jprt.my.solaris.sparcv9.jdk7} jprt.my.solaris.sparcv9=${jprt.my.solaris.sparcv9.${jprt.tools.default.release}} jprt.my.solaris.i586.jdk8=solaris_i586_5.10 jprt.my.solaris.i586.jdk7=solaris_i586_5.10 -jprt.my.solaris.i586.jdk7u14=${jprt.my.solaris.i586.jdk7} +jprt.my.solaris.i586.jdk7u40=${jprt.my.solaris.i586.jdk7} jprt.my.solaris.i586=${jprt.my.solaris.i586.${jprt.tools.default.release}} jprt.my.solaris.x64.jdk8=solaris_x64_5.10 jprt.my.solaris.x64.jdk7=solaris_x64_5.10 -jprt.my.solaris.x64.jdk7u14=${jprt.my.solaris.x64.jdk7} +jprt.my.solaris.x64.jdk7u40=${jprt.my.solaris.x64.jdk7} jprt.my.solaris.x64=${jprt.my.solaris.x64.${jprt.tools.default.release}} jprt.my.linux.i586.jdk8=linux_i586_2.6 jprt.my.linux.i586.jdk7=linux_i586_2.6 -jprt.my.linux.i586.jdk7u14=${jprt.my.linux.i586.jdk7} +jprt.my.linux.i586.jdk7u40=${jprt.my.linux.i586.jdk7} jprt.my.linux.i586=${jprt.my.linux.i586.${jprt.tools.default.release}} jprt.my.linux.x64.jdk8=linux_x64_2.6 jprt.my.linux.x64.jdk7=linux_x64_2.6 -jprt.my.linux.x64.jdk7u14=${jprt.my.linux.x64.jdk7} +jprt.my.linux.x64.jdk7u40=${jprt.my.linux.x64.jdk7} jprt.my.linux.x64=${jprt.my.linux.x64.${jprt.tools.default.release}} jprt.my.linux.ppc.jdk8=linux_ppc_2.6 jprt.my.linux.ppc.jdk7=linux_ppc_2.6 -jprt.my.linux.ppc.jdk7u14=${jprt.my.linux.ppc.jdk7} +jprt.my.linux.ppc.jdk7u40=${jprt.my.linux.ppc.jdk7} jprt.my.linux.ppc=${jprt.my.linux.ppc.${jprt.tools.default.release}} jprt.my.linux.ppcv2.jdk8=linux_ppcv2_2.6 jprt.my.linux.ppcv2.jdk7=linux_ppcv2_2.6 -jprt.my.linux.ppcv2.jdk7u14=${jprt.my.linux.ppcv2.jdk7} +jprt.my.linux.ppcv2.jdk7u40=${jprt.my.linux.ppcv2.jdk7} jprt.my.linux.ppcv2=${jprt.my.linux.ppcv2.${jprt.tools.default.release}} jprt.my.linux.ppcsflt.jdk8=linux_ppcsflt_2.6 jprt.my.linux.ppcsflt.jdk7=linux_ppcsflt_2.6 -jprt.my.linux.ppcsflt.jdk7u14=${jprt.my.linux.ppcsflt.jdk7} +jprt.my.linux.ppcsflt.jdk7u40=${jprt.my.linux.ppcsflt.jdk7} jprt.my.linux.ppcsflt=${jprt.my.linux.ppcsflt.${jprt.tools.default.release}} jprt.my.linux.armvfp.jdk8=linux_armvfp_2.6 jprt.my.linux.armvfp.jdk7=linux_armvfp_2.6 -jprt.my.linux.armvfp.jdk7u14=${jprt.my.linux.armvfp.jdk7} +jprt.my.linux.armvfp.jdk7u40=${jprt.my.linux.armvfp.jdk7} jprt.my.linux.armvfp=${jprt.my.linux.armvfp.${jprt.tools.default.release}} jprt.my.linux.armvfpsflt.jdk8=linux_armvfpsflt_2.6 jprt.my.linux.armvfpsflt.jdk7=linux_armvfpsflt_2.6 -jprt.my.linux.armvfpsflt.jdk7u14=${jprt.my.linux.armvfpsflt.jdk7} +jprt.my.linux.armvfpsflt.jdk7u40=${jprt.my.linux.armvfpsflt.jdk7} jprt.my.linux.armvfpsflt=${jprt.my.linux.armvfpsflt.${jprt.tools.default.release}} jprt.my.linux.armvfphflt.jdk8=linux_armvfphflt_2.6 jprt.my.linux.armvfphflt.jdk7=linux_armvfphflt_2.6 -jprt.my.linux.armvfphflt.jdk7u14=${jprt.my.linux.armvfphflt.jdk7} +jprt.my.linux.armvfphflt.jdk7u40=${jprt.my.linux.armvfphflt.jdk7} jprt.my.linux.armvfphflt=${jprt.my.linux.armvfphflt.${jprt.tools.default.release}} jprt.my.linux.armv6.jdk8=linux_armv6_2.6 jprt.my.linux.armv6.jdk7=linux_armv6_2.6 -jprt.my.linux.armv6.jdk7u14=${jprt.my.linux.armv6.jdk7} +jprt.my.linux.armv6.jdk7u40=${jprt.my.linux.armv6.jdk7} jprt.my.linux.armv6=${jprt.my.linux.armv6.${jprt.tools.default.release}} jprt.my.linux.armvs.jdk8=linux_armvs_2.6 jprt.my.linux.armvs.jdk7=linux_armvs_2.6 -jprt.my.linux.armvs.jdk7u14=${jprt.my.linux.armvs.jdk7} +jprt.my.linux.armvs.jdk7u40=${jprt.my.linux.armvs.jdk7} jprt.my.linux.armvs=${jprt.my.linux.armvs.${jprt.tools.default.release}} jprt.my.linux.armvh.jdk8=linux_armvh_2.6 jprt.my.linux.armvh.jdk7=linux_armvh_2.6 -jprt.my.linux.armvh.jdk7u14=${jprt.my.linux.armvh.jdk7} +jprt.my.linux.armvh.jdk7u40=${jprt.my.linux.armvh.jdk7} jprt.my.linux.armvh=${jprt.my.linux.armvh.${jprt.tools.default.release}} jprt.my.linux.armsflt.jdk8=linux_armsflt_2.6 jprt.my.linux.armsflt.jdk7=linux_armsflt_2.6 -jprt.my.linux.armsflt.jdk7u14=${jprt.my.linux.armsflt.jdk7} +jprt.my.linux.armsflt.jdk7u40=${jprt.my.linux.armsflt.jdk7} jprt.my.linux.armsflt=${jprt.my.linux.armsflt.${jprt.tools.default.release}} jprt.my.macosx.x64.jdk8=macosx_x64_10.7 jprt.my.macosx.x64.jdk7=macosx_x64_10.7 -jprt.my.macosx.x64.jdk7u14=${jprt.my.macosx.x64.jdk7} +jprt.my.macosx.x64.jdk7u40=${jprt.my.macosx.x64.jdk7} jprt.my.macosx.x64=${jprt.my.macosx.x64.${jprt.tools.default.release}} jprt.my.windows.i586.jdk8=windows_i586_5.1 jprt.my.windows.i586.jdk7=windows_i586_5.1 -jprt.my.windows.i586.jdk7u14=${jprt.my.windows.i586.jdk7} +jprt.my.windows.i586.jdk7u40=${jprt.my.windows.i586.jdk7} jprt.my.windows.i586=${jprt.my.windows.i586.${jprt.tools.default.release}} jprt.my.windows.x64.jdk8=windows_x64_5.2 jprt.my.windows.x64.jdk7=windows_x64_5.2 -jprt.my.windows.x64.jdk7u14=${jprt.my.windows.x64.jdk7} +jprt.my.windows.x64.jdk7u40=${jprt.my.windows.x64.jdk7} jprt.my.windows.x64=${jprt.my.windows.x64.${jprt.tools.default.release}} # Standard list of jprt build targets for this source tree @@ -183,7 +183,7 @@ jprt.build.targets.jdk8=${jprt.build.targets.all} jprt.build.targets.jdk7=${jprt.build.targets.all} -jprt.build.targets.jdk7u14=${jprt.build.targets.all} +jprt.build.targets.jdk7u40=${jprt.build.targets.all} jprt.build.targets=${jprt.build.targets.${jprt.tools.default.release}} # Subset lists of test targets for this source tree @@ -476,7 +476,7 @@ jprt.test.targets.jdk8=${jprt.test.targets.standard} jprt.test.targets.jdk7=${jprt.test.targets.standard} -jprt.test.targets.jdk7u14=${jprt.test.targets.jdk7} +jprt.test.targets.jdk7u40=${jprt.test.targets.jdk7} jprt.test.targets=${jprt.test.targets.${jprt.tools.default.release}} # The default test/Makefile targets that should be run @@ -536,7 +536,7 @@ jprt.make.rule.test.targets.jdk8=${jprt.make.rule.test.targets.standard} jprt.make.rule.test.targets.jdk7=${jprt.make.rule.test.targets.standard} -jprt.make.rule.test.targets.jdk7u14=${jprt.make.rule.test.targets.jdk7} +jprt.make.rule.test.targets.jdk7u40=${jprt.make.rule.test.targets.jdk7} jprt.make.rule.test.targets=${jprt.make.rule.test.targets.${jprt.tools.default.release}} # 7155453: Work-around to prevent popups on OSX from blocking test completion
--- a/src/os/posix/vm/os_posix.cpp Wed May 22 16:01:50 2013 -0700 +++ b/src/os/posix/vm/os_posix.cpp Thu May 23 13:57:41 2013 -0700 @@ -134,6 +134,10 @@ return aligned_base; } +bool os::can_release_partial_region() { + return true; +} + void os::Posix::print_load_average(outputStream* st) { st->print("load average:"); double loadavg[3];
--- a/src/os/windows/vm/os_windows.cpp Wed May 22 16:01:50 2013 -0700 +++ b/src/os/windows/vm/os_windows.cpp Thu May 23 13:57:41 2013 -0700 @@ -2971,6 +2971,10 @@ } } +bool os::can_release_partial_region() { + return false; +} + // Multiple threads can race in this code but it's not possible to unmap small sections of // virtual space to get requested alignment, like posix-like os's. // Windows prevents multiple thread from remapping over each other so this loop is thread-safe.
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Wed May 22 16:01:50 2013 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Thu May 23 13:57:41 2013 -0700 @@ -285,6 +285,7 @@ _bt.verify_not_unallocated((HeapWord*)fc, fc->size()); _indexedFreeList[mr.word_size()].return_chunk_at_head(fc); } + coalBirth(mr.word_size()); } _promoInfo.reset(); _smallLinearAllocBlock._ptr = NULL;
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Wed May 22 16:01:50 2013 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Thu May 23 13:57:41 2013 -0700 @@ -62,7 +62,8 @@ // statics CMSCollector* ConcurrentMarkSweepGeneration::_collector = NULL; -bool CMSCollector::_full_gc_requested = false; +bool CMSCollector::_full_gc_requested = false; +GCCause::Cause CMSCollector::_full_gc_cause = GCCause::_no_gc; ////////////////////////////////////////////////////////////////// // In support of CMS/VM thread synchronization @@ -1683,12 +1684,13 @@ } -void CMSCollector::request_full_gc(unsigned int full_gc_count) { +void CMSCollector::request_full_gc(unsigned int full_gc_count, GCCause::Cause cause) { GenCollectedHeap* gch = GenCollectedHeap::heap(); unsigned int gc_count = gch->total_full_collections(); if (gc_count == full_gc_count) { MutexLockerEx y(CGC_lock, Mutex::_no_safepoint_check_flag); _full_gc_requested = true; + _full_gc_cause = cause; CGC_lock->notify(); // nudge CMS thread } else { assert(gc_count > full_gc_count, "Error: causal loop"); @@ -1886,6 +1888,14 @@ // Reference objects are active. ref_processor()->clean_up_discovered_references(); + if (first_state > Idling) { + save_heap_summary(); + } + + if (first_state > Idling) { + save_heap_summary(); + } + do_compaction_work(clear_all_soft_refs); // Has the GC time limit been exceeded? @@ -2123,7 +2133,7 @@ // required. _collectorState = FinalMarking; } - collect_in_foreground(clear_all_soft_refs); + collect_in_foreground(clear_all_soft_refs, GenCollectedHeap::heap()->gc_cause()); // For a mark-sweep, compute_new_size() will be called // in the heap's do_collection() method. @@ -2186,7 +2196,7 @@ // one "collect" method between the background collector and the foreground // collector but the if-then-else required made it cleaner to have // separate methods. -void CMSCollector::collect_in_background(bool clear_all_soft_refs) { +void CMSCollector::collect_in_background(bool clear_all_soft_refs, GCCause::Cause cause) { assert(Thread::current()->is_ConcurrentGC_thread(), "A CMS asynchronous collection is only allowed on a CMS thread."); @@ -2205,7 +2215,7 @@ } else { assert(_collectorState == Idling, "Should be idling before start."); _collectorState = InitialMarking; - register_gc_start(GCCause::_cms_concurrent_mark); + register_gc_start(cause); // Reset the expansion cause, now that we are about to begin // a new cycle. clear_expansion_cause(); @@ -2214,6 +2224,7 @@ // ensuing concurrent GC cycle. update_should_unload_classes(); _full_gc_requested = false; // acks all outstanding full gc requests + _full_gc_cause = GCCause::_no_gc; // Signal that we are about to start a collection gch->increment_total_full_collections(); // ... starting a collection cycle _collection_count_start = gch->total_full_collections(); @@ -2460,7 +2471,7 @@ _gc_tracer_cm->report_gc_heap_summary(when, _last_heap_summary, _last_perm_gen_summary); } -void CMSCollector::collect_in_foreground(bool clear_all_soft_refs) { +void CMSCollector::collect_in_foreground(bool clear_all_soft_refs, GCCause::Cause cause) { assert(_foregroundGCIsActive && !_foregroundGCShouldWait, "Foreground collector should be waiting, not executing"); assert(Thread::current()->is_VM_thread(), "A foreground collection" @@ -2493,7 +2504,7 @@ } switch (_collectorState) { case InitialMarking: - register_foreground_gc_start(GenCollectedHeap::heap()->gc_cause()); + register_foreground_gc_start(cause); init_mark_was_synchronous = true; // fact to be exploited in re-mark checkpointRootsInitial(false); assert(_collectorState == Marking, "Collector state should have changed" @@ -6396,7 +6407,6 @@ } void CMSCollector::do_CMS_operation(CMS_op_type op, GCCause::Cause gc_cause) { - gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps); TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); GCTraceTime t(GCCauseString("GC", gc_cause), PrintGC, !PrintGCDetails, NULL); TraceCollectorStats tcs(counters());
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Wed May 22 16:01:50 2013 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Thu May 23 13:57:41 2013 -0700 @@ -573,8 +573,9 @@ bool _completed_initialization; // In support of ExplicitGCInvokesConcurrent - static bool _full_gc_requested; - unsigned int _collection_count_start; + static bool _full_gc_requested; + static GCCause::Cause _full_gc_cause; + unsigned int _collection_count_start; // Should we unload classes this concurrent cycle? bool _should_unload_classes; @@ -905,11 +906,11 @@ bool clear_all_soft_refs, size_t size, bool tlab); - void collect_in_background(bool clear_all_soft_refs); - void collect_in_foreground(bool clear_all_soft_refs); + void collect_in_background(bool clear_all_soft_refs, GCCause::Cause cause); + void collect_in_foreground(bool clear_all_soft_refs, GCCause::Cause cause); // In support of ExplicitGCInvokesConcurrent - static void request_full_gc(unsigned int full_gc_count); + static void request_full_gc(unsigned int full_gc_count, GCCause::Cause cause); // Should we unload classes in a particular concurrent cycle? bool should_unload_classes() const { return _should_unload_classes;
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cpp Wed May 22 16:01:50 2013 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.cpp Thu May 23 13:57:41 2013 -0700 @@ -140,7 +140,9 @@ while (!_should_terminate) { sleepBeforeNextCycle(); if (_should_terminate) break; - _collector->collect_in_background(false); // !clear_all_soft_refs + GCCause::Cause cause = _collector->_full_gc_requested ? + _collector->_full_gc_cause : GCCause::_cms_concurrent_mark; + _collector->collect_in_background(false, cause); } assert(_should_terminate, "just checking"); // Check that the state of any protocol for synchronization
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp Wed May 22 16:01:50 2013 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/vmCMSOperations.cpp Thu May 23 13:57:41 2013 -0700 @@ -241,7 +241,7 @@ // In case CMS thread was in icms_wait(), wake it up. CMSCollector::start_icms(); // Nudge the CMS thread to start a concurrent collection. - CMSCollector::request_full_gc(_full_gc_count_before); + CMSCollector::request_full_gc(_full_gc_count_before, _gc_cause); } else { assert(_full_gc_count_before < gch->total_full_collections(), "Error"); FullGCCount_lock->notify_all(); // Inform the Java thread its work is done
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed May 22 16:01:50 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu May 23 13:57:41 2013 -0700 @@ -1310,7 +1310,6 @@ // Timing assert(gc_cause() != GCCause::_java_lang_system_gc || explicit_gc, "invariant"); - gclog_or_tty->date_stamp(G1Log::fine() && PrintGCDateStamps); TraceCPUTime tcpu(G1Log::finer(), true, gclog_or_tty); {
--- a/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp Wed May 22 16:01:50 2013 -0700 +++ b/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp Thu May 23 13:57:41 2013 -0700 @@ -227,7 +227,6 @@ } void VM_CGC_Operation::doit() { - gclog_or_tty->date_stamp(G1Log::fine() && PrintGCDateStamps); TraceCPUTime tcpu(G1Log::finer(), true, gclog_or_tty); GCTraceTime t(_printGCMessage, G1Log::fine(), true, G1CollectedHeap::heap()->gc_timer_cm()); SharedHeap* sh = SharedHeap::heap();
--- a/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Wed May 22 16:01:50 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Thu May 23 13:57:41 2013 -0700 @@ -170,7 +170,6 @@ { HandleMark hm; - gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps); TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); GCTraceTime t1(GCCauseString("Full GC", gc_cause), PrintGC, !PrintGCDetails, NULL); TraceCollectorStats tcs(counters());
--- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Wed May 22 16:01:50 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Thu May 23 13:57:41 2013 -0700 @@ -2062,7 +2062,6 @@ gc_task_manager()->task_idle_workers(); heap->set_par_threads(gc_task_manager()->active_workers()); - gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps); TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); GCTraceTime t1(GCCauseString("Full GC", gc_cause), PrintGC, !PrintGCDetails, NULL); TraceCollectorStats tcs(counters());
--- a/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Wed May 22 16:01:50 2013 -0700 +++ b/src/share/vm/gc_implementation/parallelScavenge/psScavenge.cpp Thu May 23 13:57:41 2013 -0700 @@ -333,7 +333,6 @@ ResourceMark rm; HandleMark hm; - gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps); TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); GCTraceTime t1(GCCauseString("GC", gc_cause), PrintGC, !PrintGCDetails, NULL); TraceCollectorStats tcs(counters());
--- a/src/share/vm/gc_implementation/shared/gcTrace.cpp Wed May 22 16:01:50 2013 -0700 +++ b/src/share/vm/gc_implementation/shared/gcTrace.cpp Thu May 23 13:57:41 2013 -0700 @@ -91,24 +91,32 @@ send_reference_stats_event(REF_PHANTOM, rps.phantom_count()); } -class ObjectCountEventSenderClosure : public KlassInfoClosure { - GCTracer* _gc_tracer; - public: - ObjectCountEventSenderClosure(GCTracer* gc_tracer) : _gc_tracer(gc_tracer) {} - private: - void do_cinfo(KlassInfoEntry* entry) { - if (is_visible_klass(entry->klass())) { - _gc_tracer->send_object_count_after_gc_event(entry->klass(), entry->count(), - entry->words() * BytesPerWord); - } +void ObjectCountEventSenderClosure::do_cinfo(KlassInfoEntry* entry) { + if (should_send_event(entry)) { + send_event(entry); } +} +void ObjectCountEventSenderClosure::send_event(KlassInfoEntry* entry) { + _gc_tracer->send_object_count_after_gc_event(entry->klass(), entry->count(), + entry->words() * BytesPerWord); +} + +bool ObjectCountEventSenderClosure::should_send_event(KlassInfoEntry* entry) const { + double percentage_of_heap = ((double) entry->words()) / _total_size_in_words; + return percentage_of_heap > _size_threshold_percentage; +} + +bool ObjectCountFilter::do_object_b(oop obj) { + bool is_alive = _is_alive == NULL? true : _is_alive->do_object_b(obj); + return is_alive && is_externally_visible_klass(obj->klass()); +} + +bool ObjectCountFilter::is_externally_visible_klass(klassOop k) const { // Do not expose internal implementation specific classes - bool is_visible_klass(klassOop k) { - return k->klass_part()->oop_is_instance() || - (k->klass_part()->oop_is_array() && k != Universe::systemObjArrayKlassObj()); - } -}; + return (k->klass_part()->oop_is_instance() || k->klass_part()->oop_is_array()) && + k != Universe::systemObjArrayKlassObj(); +} void GCTracer::report_object_count_after_gc(BoolObjectClosure *is_alive_cl) { if (should_send_object_count_after_gc_event()) { @@ -116,8 +124,11 @@ KlassInfoTable cit(HeapInspection::start_of_perm_gen()); if (!cit.allocation_failed()) { - ObjectCountEventSenderClosure event_sender(this); - HeapInspection::instance_inspection(&cit, &event_sender, false, is_alive_cl); + ObjectCountFilter object_filter(is_alive_cl); + HeapInspection::populate_table(&cit, false, &object_filter); + + ObjectCountEventSenderClosure event_sender(this, cit.size_of_instances_in_words()); + cit.iterate(&event_sender); } } }
--- a/src/share/vm/gc_implementation/shared/gcTrace.hpp Wed May 22 16:01:50 2013 -0700 +++ b/src/share/vm/gc_implementation/shared/gcTrace.hpp Thu May 23 13:57:41 2013 -0700 @@ -30,6 +30,7 @@ #include "gc_implementation/shared/gcWhen.hpp" #include "gc_implementation/shared/copyFailedInfo.hpp" #include "memory/allocation.hpp" +#include "memory/klassInfoClosure.hpp" #include "memory/referenceType.hpp" #ifndef SERIALGC #include "gc_implementation/g1/g1YCTypes.hpp" @@ -139,6 +140,33 @@ bool should_send_object_count_after_gc_event() const; }; +class ObjectCountEventSenderClosure : public KlassInfoClosure { + GCTracer* _gc_tracer; + const double _size_threshold_percentage; + const size_t _total_size_in_words; + public: + ObjectCountEventSenderClosure(GCTracer* gc_tracer, size_t total_size_in_words) : + _gc_tracer(gc_tracer), + _size_threshold_percentage(ObjectCountCutOffPercent / 100), + _total_size_in_words(total_size_in_words) + {} + virtual void do_cinfo(KlassInfoEntry* entry); + protected: + virtual void send_event(KlassInfoEntry* entry); + private: + bool should_send_event(KlassInfoEntry* entry) const; +}; + +class ObjectCountFilter : public BoolObjectClosure { + BoolObjectClosure* _is_alive; + public: + ObjectCountFilter(BoolObjectClosure* is_alive = NULL) : _is_alive(is_alive) {} + bool do_object_b(oop obj); + void do_object(oop obj) { ShouldNotReachHere(); } + private: + bool is_externally_visible_klass(klassOop k) const; +}; + class YoungGCTracer : public GCTracer { static const uint UNSET_TENURING_THRESHOLD = (uint) -1;
--- a/src/share/vm/gc_implementation/shared/gcTraceTime.cpp Wed May 22 16:01:50 2013 -0700 +++ b/src/share/vm/gc_implementation/shared/gcTraceTime.cpp Thu May 23 13:57:41 2013 -0700 @@ -58,10 +58,8 @@ } if (_doit) { - if (PrintGCTimeStamps) { - gclog_or_tty->stamp(); - gclog_or_tty->print(": "); - } + gclog_or_tty->date_stamp(PrintGCDateStamps); + gclog_or_tty->stamp(PrintGCTimeStamps); gclog_or_tty->print("[%s", title); gclog_or_tty->flush(); }
--- a/src/share/vm/memory/allocation.hpp Wed May 22 16:01:50 2013 -0700 +++ b/src/share/vm/memory/allocation.hpp Thu May 23 13:57:41 2013 -0700 @@ -555,4 +555,23 @@ void check() PRODUCT_RETURN; }; +// Helper class to allocate arrays that may become large. +// Uses the OS malloc for allocations smaller than ArrayAllocatorMallocLimit +// and uses mapped memory for larger allocations. +// Most OS mallocs do something similar but Solaris malloc does not revert +// to mapped memory for large allocations. By default ArrayAllocatorMallocLimit +// is set so that we always use malloc except for Solaris where we set the +// limit to get mapped memory. +template <class E, MEMFLAGS F> +class ArrayAllocator : StackObj { + char* _addr; + bool _use_malloc; + size_t _size; + public: + ArrayAllocator() : _addr(NULL), _use_malloc(false), _size(0) { } + ~ArrayAllocator() { free(); } + E* allocate(size_t length); + void free(); +}; + #endif // SHARE_VM_MEMORY_ALLOCATION_HPP
--- a/src/share/vm/memory/allocation.inline.hpp Wed May 22 16:01:50 2013 -0700 +++ b/src/share/vm/memory/allocation.inline.hpp Thu May 23 13:57:41 2013 -0700 @@ -103,5 +103,49 @@ FreeHeap(p, F); } +template <class E, MEMFLAGS F> +E* ArrayAllocator<E, F>::allocate(size_t length) { + assert(_addr == NULL, "Already in use"); + + _size = sizeof(E) * length; + _use_malloc = _size < ArrayAllocatorMallocLimit; + + if (_use_malloc) { + _addr = AllocateHeap(_size, F); + if (_addr == NULL && _size >= (size_t)os::vm_allocation_granularity()) { + // malloc failed let's try with mmap instead + _use_malloc = false; + } else { + return (E*)_addr; + } + } + + int alignment = os::vm_allocation_granularity(); + _size = align_size_up(_size, alignment); + + _addr = os::reserve_memory(_size, NULL, alignment, F); + if (_addr == NULL) { + vm_exit_out_of_memory(_size, "Allocator (reserve)"); + } + + bool success = os::commit_memory(_addr, _size, false /* executable */); + if (!success) { + vm_exit_out_of_memory(_size, "Allocator (commit)"); + } + + return (E*)_addr; +} + +template<class E, MEMFLAGS F> +void ArrayAllocator<E, F>::free() { + if (_addr != NULL) { + if (_use_malloc) { + FreeHeap(_addr, F); + } else { + os::release_memory(_addr, _size); + } + _addr = NULL; + } +} #endif // SHARE_VM_MEMORY_ALLOCATION_INLINE_HPP
--- a/src/share/vm/memory/genCollectedHeap.cpp Wed May 22 16:01:50 2013 -0700 +++ b/src/share/vm/memory/genCollectedHeap.cpp Thu May 23 13:57:41 2013 -0700 @@ -477,7 +477,6 @@ bool complete = full && (max_level == (n_gens()-1)); const char* gc_cause_prefix = complete ? "Full GC" : "GC"; - gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps); TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); GCTraceTime t(GCCauseString(gc_cause_prefix, gc_cause()), PrintGCDetails, false, NULL);
--- a/src/share/vm/memory/heapInspection.cpp Wed May 22 16:01:50 2013 -0700 +++ b/src/share/vm/memory/heapInspection.cpp Thu May 23 13:57:41 2013 -0700 @@ -113,9 +113,8 @@ } } -KlassInfoTable::KlassInfoTable(HeapWord* ref) { - _size = 0; - _ref = ref; +KlassInfoTable::KlassInfoTable(HeapWord* ref) : + _size(0), _ref(ref), _size_of_instances_in_words(0) { _buckets = (KlassInfoBucket *) os::malloc(sizeof(KlassInfoBucket) * _num_buckets, mtInternal); if (_buckets != NULL) { _size = _num_buckets; @@ -160,6 +159,7 @@ if (elt != NULL) { elt->set_count(elt->count() + 1); elt->set_words(elt->words() + obj->size()); + _size_of_instances_in_words += obj->size(); return true; } else { return false; @@ -173,6 +173,10 @@ } } +size_t KlassInfoTable::size_of_instances_in_words() const { + return _size_of_instances_in_words; +} + int KlassInfoHisto::sort_helper(KlassInfoEntry** e1, KlassInfoEntry** e2) { return (*e1)->compare(*e1,*e2); } @@ -282,10 +286,9 @@ } } -size_t HeapInspection::instance_inspection(KlassInfoTable* cit, - KlassInfoClosure* cl, - bool need_prologue, - BoolObjectClosure* filter) { +size_t HeapInspection::populate_table(KlassInfoTable* cit, + bool need_prologue, + BoolObjectClosure *filter) { ResourceMark rm; if (need_prologue) { @@ -294,7 +297,6 @@ RecordInstanceClosure ric(cit, filter); Universe::heap()->object_iterate(&ric); - cit->iterate(cl); // need to run epilogue if we run prologue if (need_prologue) { @@ -309,17 +311,20 @@ KlassInfoTable cit(start_of_perm_gen()); if (!cit.allocation_failed()) { + size_t missed_count = populate_table(&cit, need_prologue); + if (missed_count != 0) { + st->print_cr("WARNING: Ran out of C-heap; undercounted " SIZE_FORMAT + " total instances in data below", + missed_count); + } + KlassInfoHisto histo("\n" " num #instances #bytes class name\n" "----------------------------------------------"); HistoClosure hc(&histo); - size_t missed_count = instance_inspection(&cit, &hc, need_prologue); - if (missed_count != 0) { - st->print_cr("WARNING: Ran out of C-heap; undercounted " SIZE_FORMAT - " total instances in data below", - missed_count); - } + cit.iterate(&hc); + histo.sort(); histo.print_on(st); } else {
--- a/src/share/vm/memory/heapInspection.hpp Wed May 22 16:01:50 2013 -0700 +++ b/src/share/vm/memory/heapInspection.hpp Thu May 23 13:57:41 2013 -0700 @@ -26,6 +26,7 @@ #define SHARE_VM_MEMORY_HEAPINSPECTION_HPP #include "memory/allocation.inline.hpp" +#include "memory/klassInfoClosure.hpp" #include "oops/oop.inline.hpp" @@ -64,12 +65,6 @@ void print_on(outputStream* st) const; }; -class KlassInfoClosure: public StackObj { - public: - // Called for each KlassInfoEntry. - virtual void do_cinfo(KlassInfoEntry* cie) = 0; -}; - class KlassInfoBucket: public CHeapObj<mtInternal> { private: KlassInfoEntry* _list; @@ -86,6 +81,7 @@ private: int _size; static const int _num_buckets = 20011; + size_t _size_of_instances_in_words; // An aligned reference address (typically the least // address in the perm gen) used for hashing klass @@ -102,6 +98,7 @@ bool record_instance(const oop obj); void iterate(KlassInfoClosure* cic); bool allocation_failed() { return _buckets == NULL; } + size_t size_of_instances_in_words() const; }; class KlassInfoHisto : public StackObj { @@ -125,10 +122,9 @@ class HeapInspection : public AllStatic { public: static void heap_inspection(outputStream* st, bool need_prologue); - static size_t instance_inspection(KlassInfoTable* cit, - KlassInfoClosure* cl, - bool need_prologue, - BoolObjectClosure* filter = NULL); + static size_t populate_table(KlassInfoTable* cit, + bool need_prologue, + BoolObjectClosure* filter = NULL); static HeapWord* start_of_perm_gen(); static void find_instances_at_safepoint(klassOop k, GrowableArray<oop>* result); private:
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/memory/klassInfoClosure.hpp Thu May 23 13:57:41 2013 -0700 @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_MEMORY_KLASSINFOCLOSURE_HPP +#define SHARE_VM_MEMORY_KLASSINFOCLOSURE_HPP + +class KlassInfoEntry; + +class KlassInfoClosure : public StackObj { + public: + // Called for each KlassInfoEntry. + virtual void do_cinfo(KlassInfoEntry* cie) = 0; +}; + +#endif // SHARE_VM_MEMORY_KLASSINFOCLOSURE_HPP
--- a/src/share/vm/runtime/globals.hpp Wed May 22 16:01:50 2013 -0700 +++ b/src/share/vm/runtime/globals.hpp Thu May 23 13:57:41 2013 -0700 @@ -2302,6 +2302,10 @@ "Print diagnostic message when GC is stalled" \ "by JNI critical section") \ \ + experimental(double, ObjectCountCutOffPercent, 0.5, \ + "The percentage of the used heap that the instances of a class " \ + "must occupy for the class to generate a trace event.") \ + \ /* GC log rotation setting */ \ \ product(bool, UseGCLogFileRotation, false, \ @@ -3633,6 +3637,11 @@ product(bool, PrintGCCause, true, \ "Include GC cause in GC logging") \ \ + experimental(uintx, ArrayAllocatorMallocLimit, \ + SOLARIS_ONLY(64*K) NOT_SOLARIS(max_uintx), \ + "Allocation less than this value will be allocated " \ + "using malloc. Larger allocations will use mmap.") \ + \ product(bool, EnableTracing, false, \ "Enable event-based tracing") \ product(bool, UseLockedTracing, false, \
--- a/src/share/vm/runtime/os.cpp Wed May 22 16:01:50 2013 -0700 +++ b/src/share/vm/runtime/os.cpp Thu May 23 13:57:41 2013 -0700 @@ -1461,6 +1461,12 @@ return res; } +bool os::release_or_uncommit_partial_region(char * addr, size_t bytes) { + if (can_release_partial_region()) { + return release_memory(addr, bytes); + } + return uncommit_memory(addr, bytes); +} char* os::map_memory(int fd, const char* file_name, size_t file_offset, char *addr, size_t bytes, bool read_only,
--- a/src/share/vm/runtime/os.hpp Wed May 22 16:01:50 2013 -0700 +++ b/src/share/vm/runtime/os.hpp Thu May 23 13:57:41 2013 -0700 @@ -266,6 +266,8 @@ bool executable = false); static bool uncommit_memory(char* addr, size_t bytes); static bool release_memory(char* addr, size_t bytes); + static bool can_release_partial_region(); + static bool release_or_uncommit_partial_region(char* addr, size_t bytes); enum ProtType { MEM_PROT_NONE, MEM_PROT_READ, MEM_PROT_RW, MEM_PROT_RWX }; static bool protect_memory(char* addr, size_t bytes, ProtType prot,
--- a/src/share/vm/runtime/virtualspace.cpp Wed May 22 16:01:50 2013 -0700 +++ b/src/share/vm/runtime/virtualspace.cpp Thu May 23 13:57:41 2013 -0700 @@ -81,17 +81,41 @@ const size_t end_delta = len - (beg_delta + required_size); if (beg_delta != 0) { - os::release_memory(addr, beg_delta); + os::release_or_uncommit_partial_region(addr, beg_delta); } if (end_delta != 0) { char* release_addr = (char*) (s + beg_delta + required_size); - os::release_memory(release_addr, end_delta); + os::release_or_uncommit_partial_region(release_addr, end_delta); } return (char*) (s + beg_delta); } +void ReservedSpace::set_raw_base_and_size(char * const raw_base, + size_t raw_size) { + assert(raw_base == NULL || !os::can_release_partial_region(), "sanity"); + _raw_base = raw_base; + _raw_size = raw_size; +} + +// On some systems (e.g., windows), the address returned by os::reserve_memory() +// is the only addr that can be passed to os::release_memory(). If alignment +// was done by this class, that original address is _raw_base. +void ReservedSpace::release_memory(char* default_addr, size_t default_size) { + bool ok; + if (_raw_base == NULL) { + ok = os::release_memory(default_addr, default_size); + } else { + assert(!os::can_release_partial_region(), "sanity"); + ok = os::release_memory(_raw_base, _raw_size); + } + if (!ok) { + fatal("os::release_memory failed"); + } + set_raw_base_and_size(NULL, 0); +} + char* ReservedSpace::reserve_and_align(const size_t reserve_size, const size_t prefix_size, const size_t prefix_align, @@ -110,6 +134,10 @@ fatal("os::release_memory failed"); } + if (!os::can_release_partial_region()) { + set_raw_base_and_size(raw_addr, reserve_size); + } + #ifdef ASSERT if (result != NULL) { const size_t raw = size_t(raw_addr); @@ -127,8 +155,10 @@ } // Helper method. -static bool failed_to_reserve_as_requested(char* base, char* requested_address, - const size_t size, bool special) +bool ReservedSpace::failed_to_reserve_as_requested(char* base, + char* requested_address, + const size_t size, + bool special) { if (base == requested_address || requested_address == NULL) return false; // did not fail @@ -147,9 +177,7 @@ fatal("os::release_memory_special failed"); } } else { - if (!os::release_memory(base, size)) { - fatal("os::release_memory failed"); - } + release_memory(base, size); } } return true; @@ -177,6 +205,8 @@ assert(noaccess_prefix == 0 || noaccess_prefix == prefix_align, "noaccess prefix wrong"); + set_raw_base_and_size(NULL, 0); + // Add in noaccess_prefix to prefix_size; const size_t adjusted_prefix_size = prefix_size + noaccess_prefix; const size_t size = adjusted_prefix_size + suffix_size; @@ -224,9 +254,7 @@ // result is often the same address (if the kernel hands out virtual // addresses from low to high), or an address that is offset by the increase // in size. Exploit that to minimize the amount of extra space requested. - if (!os::release_memory(addr, size)) { - fatal("os::release_memory failed"); - } + release_memory(addr, size); const size_t extra = MAX2(ofs, suffix_align - ofs); addr = reserve_and_align(size + extra, adjusted_prefix_size, prefix_align, @@ -265,6 +293,8 @@ assert(alignment == 0 || is_power_of_2((intptr_t)alignment), "not a power of 2"); + set_raw_base_and_size(NULL, 0); + alignment = MAX2(alignment, (size_t)os::vm_page_size()); // Assert that if noaccess_prefix is used, it is the same as alignment. @@ -340,7 +370,8 @@ // Check alignment constraints if ((((size_t)base + noaccess_prefix) & (alignment - 1)) != 0) { // Base not aligned, retry - if (!os::release_memory(base, size)) fatal("os::release_memory failed"); + release_memory(base, size); + // Make sure that size is aligned size = align_size_up(size, alignment); base = os::reserve_memory_aligned(size, alignment); @@ -378,6 +409,7 @@ "size not allocation aligned"); _base = base; _size = size; + set_raw_base_and_size(NULL, 0); _alignment = alignment; _noaccess_prefix = 0; _special = special; @@ -433,7 +465,7 @@ if (special()) { os::release_memory_special(real_base, real_size); } else{ - os::release_memory(real_base, real_size); + release_memory(real_base, real_size); } _base = NULL; _size = 0;
--- a/src/share/vm/runtime/virtualspace.hpp Wed May 22 16:01:50 2013 -0700 +++ b/src/share/vm/runtime/virtualspace.hpp Thu May 23 13:57:41 2013 -0700 @@ -35,6 +35,12 @@ char* _base; size_t _size; size_t _noaccess_prefix; + + // The base and size prior to any alignment done by this class; used only on + // systems that cannot release part of a region. + char* _raw_base; + size_t _raw_size; + size_t _alignment; bool _special; bool _executable; @@ -42,11 +48,20 @@ // ReservedSpace ReservedSpace(char* base, size_t size, size_t alignment, bool special, bool executable); + + bool failed_to_reserve_as_requested(char* base, char* requested_address, + const size_t size, bool special); void initialize(size_t size, size_t alignment, bool large, char* requested_address, const size_t noaccess_prefix, bool executable); + inline void set_raw_base_and_size(char * const raw_base, size_t raw_size); + + // Release virtual address space. If alignment was done, use the saved + // address and size when releasing. + void release_memory(char * default_addr, size_t default_size); + // Release parts of an already-reserved memory region [addr, addr + len) to // get a new region that has "compound alignment." Return the start of the // resulting region, or NULL on failure.
--- a/src/share/vm/utilities/taskqueue.hpp Wed May 22 16:01:50 2013 -0700 +++ b/src/share/vm/utilities/taskqueue.hpp Thu May 23 13:57:41 2013 -0700 @@ -253,6 +253,7 @@ template <class E, MEMFLAGS F, unsigned int N = TASKQUEUE_SIZE> class GenericTaskQueue: public TaskQueueSuper<N, F> { + ArrayAllocator<E, F> _array_allocator; protected: typedef typename TaskQueueSuper<N, F>::Age Age; typedef typename TaskQueueSuper<N, F>::idx_t idx_t; @@ -314,7 +315,7 @@ template<class E, MEMFLAGS F, unsigned int N> void GenericTaskQueue<E, F, N>::initialize() { - _elems = NEW_C_HEAP_ARRAY(E, N, F); + _elems = _array_allocator.allocate(N); } template<class E, MEMFLAGS F, unsigned int N>