1 /*
   2  * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #include "precompiled.hpp"
  26 #include "jfr/recorder/storage/jfrStorageControl.hpp"
  27 #include "runtime/atomic.inline.hpp"
  28 #include "runtime/mutexLocker.hpp"
  29 #include "runtime/orderAccess.inline.hpp"
  30 
  31 // returns the updated value
  32 static jlong atomic_add(size_t value, size_t volatile* const dest) {
  33   size_t compare_value;
  34   size_t exchange_value;
  35   do {
  36     compare_value = OrderAccess::load_ptr_acquire((intptr_t*)dest);
  37     exchange_value = compare_value + value;
  38   } while ((unsigned long)Atomic::cmpxchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest, (intptr_t)compare_value) != compare_value);
  39   return exchange_value;
  40 }
  41 
  42 static jlong atomic_dec(size_t volatile* const dest) {
  43   size_t compare_value;
  44   size_t exchange_value;
  45   do {
  46     compare_value = OrderAccess::load_ptr_acquire((intptr_t*)dest);
  47     assert(compare_value >= 1, "invariant");
  48     exchange_value = compare_value - 1;
  49   } while ((unsigned long)Atomic::cmpxchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest, (intptr_t)compare_value) != compare_value);
  50   return exchange_value;
  51 }
  52 
  53 const size_t max_lease_factor = 2;
  54 JfrStorageControl::JfrStorageControl(size_t global_count_total, size_t in_memory_discard_threshold) :
  55   _global_count_total(global_count_total),
  56   _full_count(0),
  57   _global_lease_count(0),
  58   _dead_count(0),
  59   _to_disk_threshold(0),
  60   _in_memory_discard_threshold(in_memory_discard_threshold),
  61   _global_lease_threshold(global_count_total / max_lease_factor),
  62   _scavenge_threshold(0),
  63   _to_disk(false) {}
  64 
  65 bool JfrStorageControl::to_disk() const {
  66   return _to_disk;
  67 }
  68 
  69 void JfrStorageControl::set_to_disk(bool enable) {
  70   _to_disk = enable;
  71 }
  72 
  73 size_t JfrStorageControl::full_count() const {
  74   return _full_count;
  75 }
  76 
  77 // mutexed access
  78 size_t JfrStorageControl::increment_full() {
  79   assert(JfrBuffer_lock->owned_by_self(), "invariant");
  80   return ++_full_count;
  81 }
  82 
  83 size_t JfrStorageControl::decrement_full() {
  84   assert(JfrBuffer_lock->owned_by_self(), "invariant");
  85   assert(_full_count > 0, "invariant");
  86   return --_full_count;
  87 }
  88 
  89 void JfrStorageControl::reset_full() {
  90   assert(JfrBuffer_lock->owned_by_self(), "invariant");
  91   _full_count = 0;
  92 }
  93 
  94 bool JfrStorageControl::should_post_buffer_full_message() const {
  95   return to_disk() && (full_count() > _to_disk_threshold);
  96 }
  97 
  98 bool JfrStorageControl::should_discard() const {
  99   return !to_disk() && full_count() >= _in_memory_discard_threshold;
 100 }
 101 
 102 // concurrent with accuracy requirement
 103 
 104 size_t JfrStorageControl::global_lease_count() const {
 105   return (size_t)OrderAccess::load_ptr_acquire((intptr_t*)&_global_lease_count);
 106 }
 107 
 108 size_t JfrStorageControl::increment_leased() {
 109   return atomic_add(1, &_global_lease_count);
 110 }
 111 
 112 size_t JfrStorageControl::decrement_leased() {
 113   return atomic_dec(&_global_lease_count);
 114 }
 115 
 116 bool JfrStorageControl::is_global_lease_allowed() const {
 117   return global_lease_count() <= _global_lease_threshold;
 118 }
 119 
 120 // concurrent with lax requirement
 121 
 122 size_t JfrStorageControl::dead_count() const {
 123   return _dead_count;
 124 }
 125 
 126 size_t JfrStorageControl::increment_dead() {
 127   return atomic_add(1, &_dead_count);
 128 }
 129 
 130 size_t JfrStorageControl::decrement_dead() {
 131   return atomic_dec(&_dead_count);
 132 }
 133 
 134 bool JfrStorageControl::should_scavenge() const {
 135   return dead_count() >= _scavenge_threshold;
 136 }
 137 
 138 void JfrStorageControl::set_scavenge_threshold(size_t number_of_dead_buffers) {
 139   _scavenge_threshold = number_of_dead_buffers;
 140 }
 141