1 /*
   2  * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2020 SAP SE. All rights reserved.
   4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5  *
   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.
   9  *
  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).
  15  *
  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.
  19  *
  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
  22  * questions.
  23  *
  24  */
  25 
  26 #ifndef SHARE_MEMORY_METASPACE_MSCOUNTER_HPP
  27 #define SHARE_MEMORY_METASPACE_MSCOUNTER_HPP
  28 
  29 #include "metaprogramming/isSigned.hpp"
  30 #include "runtime/atomic.hpp"
  31 #include "utilities/debug.hpp"
  32 #include "utilities/globalDefinitions.hpp"
  33 
  34 namespace metaspace {
  35 
  36 // We seem to be counting a lot of things which makes it worthwhile to
  37 // make helper classes for all that boilerplate coding.
  38 
  39 // AbstractCounter counts something and asserts overflow and underflow.
  40 template <class T>
  41 class AbstractCounter {
  42 
  43   T _c;
  44 
  45   // Only allow unsigned values for now
  46   STATIC_ASSERT(IsSigned<T>::value == false);
  47 
  48 public:
  49 
  50   AbstractCounter() : _c(0) {}
  51 
  52   T get() const           { return _c; }
  53 
  54   void increment() { increment_by(1); }
  55   void decrement() { decrement_by(1); }
  56 
  57   void increment_by(T v) {
  58 #ifdef ASSERT
  59     T old = _c;
  60     assert(old + v >= old,
  61         "overflow (" UINT64_FORMAT "+" UINT64_FORMAT ")", (uint64_t)old, (uint64_t)v);
  62 #endif
  63     _c += v;
  64   }
  65 
  66   void decrement_by(T v) {
  67     assert(_c >= v,
  68            "underflow (" UINT64_FORMAT "-" UINT64_FORMAT ")",
  69            (uint64_t)_c, (uint64_t)v);
  70     _c -= v;
  71   }
  72 
  73   void reset()                { _c = 0; }
  74 
  75 #ifdef ASSERT
  76   void check(T expected) const {
  77     assert(_c == expected, "Counter mismatch: %d, expected: %d.",
  78            (int)_c, (int)expected);
  79     }
  80 #endif
  81 
  82 };
  83 
  84 // Atomic variant of AbstractCounter.
  85 template <class T>
  86 class AbstractAtomicCounter {
  87 
  88   volatile T _c;
  89 
  90   // Only allow unsigned values for now
  91   STATIC_ASSERT(IsSigned<T>::value == false);
  92 
  93 public:
  94 
  95   AbstractAtomicCounter() : _c(0) {}
  96 
  97   T get() const               { return _c; }
  98 
  99   void increment() {
 100     Atomic::inc(&_c);
 101   }
 102 
 103   void decrement() {
 104 #ifdef ASSERT
 105     T old = Atomic::load_acquire(&_c);
 106     assert(old >= 1,
 107         "underflow (" UINT64_FORMAT "-1)", (uint64_t)old);
 108 #endif
 109     Atomic::dec(&_c);
 110   }
 111 
 112   void increment_by(T v) {
 113     Atomic::add(&_c, v);
 114   }
 115 
 116   void decrement_by(T v) {
 117 #ifdef ASSERT
 118     T old = Atomic::load_acquire(&_c);
 119     assert(old >= v,
 120         "underflow (" UINT64_FORMAT "+" UINT64_FORMAT ")", (uint64_t)old, (uint64_t)v);
 121 #endif
 122     Atomic::sub(&_c, v);
 123   }
 124 
 125 #ifdef ASSERT
 126   void check(T expected) const {
 127     assert(_c == expected, "Counter mismatch: %d, expected: %d.",
 128            (int)_c, (int)expected);
 129     }
 130 #endif
 131 
 132 };
 133 
 134 typedef AbstractCounter<size_t>   SizeCounter;
 135 typedef AbstractCounter<unsigned> IntCounter;
 136 
 137 typedef AbstractAtomicCounter<size_t> SizeAtomicCounter;
 138 
 139 // We often count memory ranges (blocks, chunks etc).
 140 // Make a helper class for that.
 141 template <class T_num, class T_size>
 142 class AbstractMemoryRangeCounter {
 143 
 144   AbstractCounter<T_num>  _count;
 145   AbstractCounter<T_size> _total_size;
 146 
 147 public:
 148 
 149   void add(T_size s) {
 150     if(s > 0) {
 151       _count.increment();
 152       _total_size.increment_by(s);
 153     }
 154   }
 155 
 156   void sub(T_size s) {
 157     if(s > 0) {
 158       _count.decrement();
 159       _total_size.decrement_by(s);
 160     }
 161   }
 162 
 163   T_num count() const       { return _count.get(); }
 164   T_size total_size() const { return _total_size.get(); }
 165 
 166 #ifdef ASSERT
 167   void check(T_num expected_count, T_size expected_size) const {
 168     _count.check(expected_count);
 169     _total_size.check(expected_size);
 170   }
 171   void check(const AbstractMemoryRangeCounter<T_num, T_size>& other) const {
 172     check(other.count(), other.total_size());
 173   }
 174 #endif
 175 
 176 };
 177 
 178 typedef AbstractMemoryRangeCounter<unsigned, size_t> MemRangeCounter;
 179 
 180 } // namespace metaspace
 181 
 182 #endif // SHARE_MEMORY_METASPACE_MSCOUNTER_HPP
 183