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