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