duke@435: /* drchase@6680: * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * trims@1907: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA trims@1907: * or visit www.oracle.com if you need additional information or have any trims@1907: * questions. duke@435: * duke@435: */ duke@435: stefank@2314: #include "precompiled.hpp" stefank@2314: #include "classfile/systemDictionary.hpp" stefank@2314: #include "classfile/vmSymbols.hpp" stefank@2314: #include "oops/oop.inline.hpp" stefank@2314: #include "runtime/interfaceSupport.hpp" stefank@2314: #include "runtime/java.hpp" stefank@2314: #include "runtime/javaCalls.hpp" stefank@2314: #include "runtime/mutex.hpp" stefank@2314: #include "runtime/mutexLocker.hpp" stefank@2314: #include "services/lowMemoryDetector.hpp" stefank@2314: #include "services/management.hpp" duke@435: duke@435: volatile bool LowMemoryDetector::_enabled_for_collected_pools = false; duke@435: volatile jint LowMemoryDetector::_disabled_count = 0; duke@435: duke@435: bool LowMemoryDetector::has_pending_requests() { kamg@2511: assert(Service_lock->owned_by_self(), "Must own Service_lock"); duke@435: bool has_requests = false; duke@435: int num_memory_pools = MemoryService::num_memory_pools(); duke@435: for (int i = 0; i < num_memory_pools; i++) { duke@435: MemoryPool* pool = MemoryService::get_memory_pool(i); duke@435: SensorInfo* sensor = pool->usage_sensor(); duke@435: if (sensor != NULL) { duke@435: has_requests = has_requests || sensor->has_pending_requests(); duke@435: } duke@435: duke@435: SensorInfo* gc_sensor = pool->gc_usage_sensor(); duke@435: if (gc_sensor != NULL) { duke@435: has_requests = has_requests || gc_sensor->has_pending_requests(); duke@435: } duke@435: } duke@435: return has_requests; duke@435: } duke@435: kamg@2511: void LowMemoryDetector::process_sensor_changes(TRAPS) { kamg@2511: ResourceMark rm(THREAD); kamg@2511: HandleMark hm(THREAD); duke@435: kamg@2511: // No need to hold Service_lock to call out to Java kamg@2511: int num_memory_pools = MemoryService::num_memory_pools(); kamg@2511: for (int i = 0; i < num_memory_pools; i++) { kamg@2511: MemoryPool* pool = MemoryService::get_memory_pool(i); kamg@2511: SensorInfo* sensor = pool->usage_sensor(); kamg@2511: SensorInfo* gc_sensor = pool->gc_usage_sensor(); kamg@2511: if (sensor != NULL && sensor->has_pending_requests()) { kamg@2511: sensor->process_pending_requests(CHECK); duke@435: } kamg@2511: if (gc_sensor != NULL && gc_sensor->has_pending_requests()) { kamg@2511: gc_sensor->process_pending_requests(CHECK); duke@435: } duke@435: } duke@435: } duke@435: duke@435: // This method could be called from any Java threads duke@435: // and also VMThread. duke@435: void LowMemoryDetector::detect_low_memory() { kamg@2511: MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag); duke@435: duke@435: bool has_pending_requests = false; duke@435: int num_memory_pools = MemoryService::num_memory_pools(); duke@435: for (int i = 0; i < num_memory_pools; i++) { duke@435: MemoryPool* pool = MemoryService::get_memory_pool(i); duke@435: SensorInfo* sensor = pool->usage_sensor(); duke@435: if (sensor != NULL && duke@435: pool->usage_threshold()->is_high_threshold_supported() && duke@435: pool->usage_threshold()->high_threshold() != 0) { duke@435: MemoryUsage usage = pool->get_memory_usage(); duke@435: sensor->set_gauge_sensor_level(usage, duke@435: pool->usage_threshold()); duke@435: has_pending_requests = has_pending_requests || sensor->has_pending_requests(); duke@435: } duke@435: } duke@435: duke@435: if (has_pending_requests) { kamg@2511: Service_lock->notify_all(); duke@435: } duke@435: } duke@435: duke@435: // This method could be called from any Java threads duke@435: // and also VMThread. duke@435: void LowMemoryDetector::detect_low_memory(MemoryPool* pool) { duke@435: SensorInfo* sensor = pool->usage_sensor(); duke@435: if (sensor == NULL || duke@435: !pool->usage_threshold()->is_high_threshold_supported() || duke@435: pool->usage_threshold()->high_threshold() == 0) { duke@435: return; duke@435: } duke@435: duke@435: { kamg@2511: MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag); duke@435: duke@435: MemoryUsage usage = pool->get_memory_usage(); duke@435: sensor->set_gauge_sensor_level(usage, duke@435: pool->usage_threshold()); duke@435: if (sensor->has_pending_requests()) { duke@435: // notify sensor state update kamg@2511: Service_lock->notify_all(); duke@435: } duke@435: } duke@435: } duke@435: duke@435: // Only called by VMThread at GC time duke@435: void LowMemoryDetector::detect_after_gc_memory(MemoryPool* pool) { duke@435: SensorInfo* sensor = pool->gc_usage_sensor(); duke@435: if (sensor == NULL || duke@435: !pool->gc_usage_threshold()->is_high_threshold_supported() || duke@435: pool->gc_usage_threshold()->high_threshold() == 0) { duke@435: return; duke@435: } duke@435: duke@435: { kamg@2511: MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag); duke@435: duke@435: MemoryUsage usage = pool->get_last_collection_usage(); duke@435: sensor->set_counter_sensor_level(usage, pool->gc_usage_threshold()); duke@435: duke@435: if (sensor->has_pending_requests()) { duke@435: // notify sensor state update kamg@2511: Service_lock->notify_all(); duke@435: } duke@435: } duke@435: } duke@435: duke@435: // recompute enabled flag duke@435: void LowMemoryDetector::recompute_enabled_for_collected_pools() { duke@435: bool enabled = false; duke@435: int num_memory_pools = MemoryService::num_memory_pools(); duke@435: for (int i=0; iis_collected_pool() && is_enabled(pool)) { duke@435: enabled = true; duke@435: break; duke@435: } duke@435: } duke@435: _enabled_for_collected_pools = enabled; duke@435: } duke@435: duke@435: SensorInfo::SensorInfo() { duke@435: _sensor_obj = NULL; duke@435: _sensor_on = false; duke@435: _sensor_count = 0; duke@435: _pending_trigger_count = 0; duke@435: _pending_clear_count = 0; duke@435: } duke@435: duke@435: // When this method is used, the memory usage is monitored duke@435: // as a gauge attribute. Sensor notifications (trigger or duke@435: // clear) is only emitted at the first time it crosses duke@435: // a threshold. duke@435: // duke@435: // High and low thresholds are designed to provide a duke@435: // hysteresis mechanism to avoid repeated triggering duke@435: // of notifications when the attribute value makes small oscillations duke@435: // around the high or low threshold value. duke@435: // duke@435: // The sensor will be triggered if: duke@435: // (1) the usage is crossing above the high threshold and duke@435: // the sensor is currently off and no pending duke@435: // trigger requests; or duke@435: // (2) the usage is crossing above the high threshold and duke@435: // the sensor will be off (i.e. sensor is currently on duke@435: // and has pending clear requests). duke@435: // duke@435: // Subsequent crossings of the high threshold value do not cause duke@435: // any triggers unless the usage becomes less than the low threshold. duke@435: // duke@435: // The sensor will be cleared if: duke@435: // (1) the usage is crossing below the low threshold and duke@435: // the sensor is currently on and no pending duke@435: // clear requests; or duke@435: // (2) the usage is crossing below the low threshold and duke@435: // the sensor will be on (i.e. sensor is currently off duke@435: // and has pending trigger requests). duke@435: // duke@435: // Subsequent crossings of the low threshold value do not cause duke@435: // any clears unless the usage becomes greater than or equal duke@435: // to the high threshold. duke@435: // duke@435: // If the current level is between high and low threhsold, no change. duke@435: // duke@435: void SensorInfo::set_gauge_sensor_level(MemoryUsage usage, ThresholdSupport* high_low_threshold) { duke@435: assert(high_low_threshold->is_high_threshold_supported(), "just checking"); duke@435: duke@435: bool is_over_high = high_low_threshold->is_high_threshold_crossed(usage); duke@435: bool is_below_low = high_low_threshold->is_low_threshold_crossed(usage); duke@435: duke@435: assert(!(is_over_high && is_below_low), "Can't be both true"); duke@435: duke@435: if (is_over_high && duke@435: ((!_sensor_on && _pending_trigger_count == 0) || duke@435: _pending_clear_count > 0)) { duke@435: // low memory detected and need to increment the trigger pending count duke@435: // if the sensor is off or will be off due to _pending_clear_ > 0 duke@435: // Request to trigger the sensor duke@435: _pending_trigger_count++; duke@435: _usage = usage; duke@435: duke@435: if (_pending_clear_count > 0) { duke@435: // non-zero pending clear requests indicates that there are duke@435: // pending requests to clear this sensor. duke@435: // This trigger request needs to clear this clear count duke@435: // since the resulting sensor flag should be on. duke@435: _pending_clear_count = 0; duke@435: } duke@435: } else if (is_below_low && duke@435: ((_sensor_on && _pending_clear_count == 0) || duke@435: (_pending_trigger_count > 0 && _pending_clear_count == 0))) { duke@435: // memory usage returns below the threshold duke@435: // Request to clear the sensor if the sensor is on or will be on due to duke@435: // _pending_trigger_count > 0 and also no clear request duke@435: _pending_clear_count++; duke@435: } duke@435: } duke@435: duke@435: // When this method is used, the memory usage is monitored as a duke@435: // simple counter attribute. The sensor will be triggered duke@435: // whenever the usage is crossing the threshold to keep track duke@435: // of the number of times the VM detects such a condition occurs. duke@435: // duke@435: // High and low thresholds are designed to provide a duke@435: // hysteresis mechanism to avoid repeated triggering duke@435: // of notifications when the attribute value makes small oscillations duke@435: // around the high or low threshold value. duke@435: // duke@435: // The sensor will be triggered if: duke@435: // - the usage is crossing above the high threshold regardless duke@435: // of the current sensor state. duke@435: // duke@435: // The sensor will be cleared if: duke@435: // (1) the usage is crossing below the low threshold and duke@435: // the sensor is currently on; or duke@435: // (2) the usage is crossing below the low threshold and duke@435: // the sensor will be on (i.e. sensor is currently off duke@435: // and has pending trigger requests). duke@435: void SensorInfo::set_counter_sensor_level(MemoryUsage usage, ThresholdSupport* counter_threshold) { duke@435: assert(counter_threshold->is_high_threshold_supported(), "just checking"); duke@435: duke@435: bool is_over_high = counter_threshold->is_high_threshold_crossed(usage); duke@435: bool is_below_low = counter_threshold->is_low_threshold_crossed(usage); duke@435: duke@435: assert(!(is_over_high && is_below_low), "Can't be both true"); duke@435: duke@435: if (is_over_high) { duke@435: _pending_trigger_count++; duke@435: _usage = usage; duke@435: _pending_clear_count = 0; duke@435: } else if (is_below_low && (_sensor_on || _pending_trigger_count > 0)) { duke@435: _pending_clear_count++; duke@435: } duke@435: } duke@435: duke@435: void SensorInfo::oops_do(OopClosure* f) { duke@435: f->do_oop((oop*) &_sensor_obj); duke@435: } duke@435: duke@435: void SensorInfo::process_pending_requests(TRAPS) { duke@435: if (!has_pending_requests()) { duke@435: return; duke@435: } duke@435: duke@435: int pending_count = pending_trigger_count(); duke@435: if (pending_clear_count() > 0) { duke@435: clear(pending_count, CHECK); duke@435: } else { duke@435: trigger(pending_count, CHECK); duke@435: } duke@435: duke@435: } duke@435: duke@435: void SensorInfo::trigger(int count, TRAPS) { duke@435: assert(count <= _pending_trigger_count, "just checking"); duke@435: duke@435: if (_sensor_obj != NULL) { coleenp@4037: Klass* k = Management::sun_management_Sensor_klass(CHECK); duke@435: instanceKlassHandle sensorKlass (THREAD, k); duke@435: Handle sensor_h(THREAD, _sensor_obj); duke@435: Handle usage_h = MemoryService::create_MemoryUsage_obj(_usage, CHECK); duke@435: duke@435: JavaValue result(T_VOID); duke@435: JavaCallArguments args(sensor_h); duke@435: args.push_int((int) count); duke@435: args.push_oop(usage_h); duke@435: duke@435: JavaCalls::call_virtual(&result, duke@435: sensorKlass, coleenp@2497: vmSymbols::trigger_name(), coleenp@2497: vmSymbols::trigger_method_signature(), duke@435: &args, duke@435: CHECK); duke@435: } duke@435: duke@435: { kamg@2511: // Holds Service_lock and update the sensor state kamg@2511: MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag); duke@435: _sensor_on = true; duke@435: _sensor_count += count; duke@435: _pending_trigger_count = _pending_trigger_count - count; duke@435: } duke@435: } duke@435: duke@435: void SensorInfo::clear(int count, TRAPS) { duke@435: if (_sensor_obj != NULL) { coleenp@4037: Klass* k = Management::sun_management_Sensor_klass(CHECK); duke@435: instanceKlassHandle sensorKlass (THREAD, k); duke@435: Handle sensor(THREAD, _sensor_obj); duke@435: duke@435: JavaValue result(T_VOID); duke@435: JavaCallArguments args(sensor); duke@435: args.push_int((int) count); duke@435: JavaCalls::call_virtual(&result, duke@435: sensorKlass, coleenp@2497: vmSymbols::clear_name(), coleenp@2497: vmSymbols::int_void_signature(), duke@435: &args, duke@435: CHECK); duke@435: } duke@435: duke@435: { kamg@2511: // Holds Service_lock and update the sensor state kamg@2511: MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag); duke@435: _sensor_on = false; duke@435: _pending_clear_count = 0; duke@435: _pending_trigger_count = _pending_trigger_count - count; duke@435: } duke@435: } duke@435: duke@435: //-------------------------------------------------------------- duke@435: // Non-product code duke@435: duke@435: #ifndef PRODUCT duke@435: void SensorInfo::print() { drchase@6680: tty->print_cr("%s count = " SIZE_FORMAT " pending_triggers = %d pending_clears = %d", duke@435: (_sensor_on ? "on" : "off"), duke@435: _sensor_count, _pending_trigger_count, _pending_clear_count); duke@435: } duke@435: duke@435: #endif // PRODUCT