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