1 /* Copyright 2009-2016 Francesco Biscani (bluescarni@gmail.com) 2 3 This file is part of the Piranha library. 4 5 The Piranha library is free software; you can redistribute it and/or modify 6 it under the terms of either: 7 8 * the GNU Lesser General Public License as published by the Free 9 Software Foundation; either version 3 of the License, or (at your 10 option) any later version. 11 12 or 13 14 * the GNU General Public License as published by the Free Software 15 Foundation; either version 3 of the License, or (at your option) any 16 later version. 17 18 or both in parallel, as here. 19 20 The Piranha library is distributed in the hope that it will be useful, but 21 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 22 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 23 for more details. 24 25 You should have received copies of the GNU General Public License and the 26 GNU Lesser General Public License along with the Piranha library. If not, 27 see https://www.gnu.org/licenses/. */ 28 29 #ifndef PIRANHA_SETTINGS_HPP 30 #define PIRANHA_SETTINGS_HPP 31 32 #include <atomic> 33 #include <mutex> 34 #include <stdexcept> 35 36 #include "config.hpp" 37 #include "exceptions.hpp" 38 #include "runtime_info.hpp" 39 #include "thread_pool.hpp" 40 41 namespace piranha 42 { 43 44 namespace detail 45 { 46 47 template <typename = int> 48 struct base_settings { 49 static std::mutex m_mutex; 50 static unsigned m_cache_line_size; 51 static unsigned long m_max_term_output; 52 static const unsigned long m_default_max_term_output = 20ul; 53 static std::atomic_ullong s_min_work_per_thread; 54 // NOTE: this corresponds to circa 2% overhead from thread management on a common desktop 55 // machine around 2012 for the fastest series multiplication scenario. 56 static const unsigned long long s_default_min_work_per_thread = 250000ull; 57 }; 58 59 template <typename T> 60 std::mutex base_settings<T>::m_mutex; 61 62 template <typename T> 63 unsigned base_settings<T>::m_cache_line_size = runtime_info::get_cache_line_size(); 64 65 template <typename T> 66 unsigned long base_settings<T>::m_max_term_output = base_settings<T>::m_default_max_term_output; 67 68 template <typename T> 69 const unsigned long base_settings<T>::m_default_max_term_output; 70 71 template <typename T> 72 const unsigned long long base_settings<T>::s_default_min_work_per_thread; 73 74 template <typename T> 75 std::atomic_ullong base_settings<T>::s_min_work_per_thread(base_settings<T>::s_default_min_work_per_thread); 76 } 77 78 /// Global settings. 79 /** 80 * \note 81 * The template parameter in this class is unused: its only purpose is to prevent the instantiation 82 * of the class' methods if they are not explicitly used. Client code should always employ the 83 * piranha::settings alias. 84 * 85 * This class stores the global settings of piranha's runtime environment. 86 * The methods of this class are thread-safe. 87 */ 88 template <typename = void> 89 class settings_ : private detail::base_settings<> 90 { 91 public: 92 /// Get the number of threads available for use by piranha. 93 /** 94 * The initial value is set to the maximum between 1 and piranha::runtime_info::get_hardware_concurrency(). 95 * This function is equivalent to piranha::thread_pool::size(). 96 * 97 * @return the number of threads that will be available for use by piranha. 98 * 99 * @throws unspecified any exception thrown by piranha::thread_pool::size(). 100 */ get_n_threads()101 static unsigned get_n_threads() 102 { 103 return thread_pool::size(); 104 } 105 /// Set the number of threads available for use by piranha. 106 /** 107 * This function is equivalent to piranha::thread_pool::resize(). 108 * 109 * @param n the desired number of threads. 110 * 111 * @throws unspecified any exception thrown by piranha::thread_pool::resize(). 112 */ set_n_threads(unsigned n)113 static void set_n_threads(unsigned n) 114 { 115 thread_pool::resize(n); 116 } 117 /// Reset the number of threads available for use by piranha. 118 /** 119 * Will set the number of threads to the maximum between 1 and piranha::runtime_info::get_hardware_concurrency(). 120 * 121 * @throws unspecified any exception thrown by set_n_threads(). 122 */ reset_n_threads()123 static void reset_n_threads() 124 { 125 const auto candidate = runtime_info::get_hardware_concurrency(); 126 set_n_threads((candidate > 0u) ? candidate : 1u); 127 } 128 /// Set the thread binding policy. 129 /** 130 * This method is an alias for piranha::thread_pool::set_binding(). If \p flag is \p true, each 131 * thread used by piranha will be bound to a different processor/core. If \p flag is \p false, 132 * this method will unbind piranha's threads from any processor/core to which they might be bound. 133 * 134 * By default piranha's threads are not bound to any specific processor/core. 135 * 136 * @param flag the desired thread binding policy. 137 * 138 * @throws unspecified any exception thrown by piranha::thread_pool::set_binding(). 139 */ set_thread_binding(bool flag)140 static void set_thread_binding(bool flag) 141 { 142 thread_pool::set_binding(flag); 143 } 144 /// Get the thread binding policy. 145 /** 146 * This method is an alias for piranha::thread_pool::get_binding(). It will return the flag set by 147 * settings::set_thread_binding() (which is \p false by default on program startup). 148 * 149 * @return the active thread binding policy. 150 * 151 * @throws unspecified any exception thrown by piranha::thread_pool::get_binding(). 152 */ get_thread_binding()153 static bool get_thread_binding() 154 { 155 return thread_pool::get_binding(); 156 } 157 /// Get the cache line size. 158 /** 159 * The initial value is set to the output of piranha::runtime_info::get_cache_line_size(). The value 160 * can be overridden with set_cache_line_size() in case the detection fails and the value is set to zero. 161 * 162 * @return data cache line size (in bytes). 163 * 164 * @throws std::system_error in case of failure(s) by threading primitives. 165 */ get_cache_line_size()166 static unsigned get_cache_line_size() 167 { 168 std::lock_guard<std::mutex> lock(m_mutex); 169 return m_cache_line_size; 170 } 171 /// Set the cache line size. 172 /** 173 * Overrides the detected cache line size. This method should be used only if the automatic 174 * detection fails. 175 * 176 * @param n data cache line size (in bytes). 177 * 178 * @throws std::system_error in case of failure(s) by threading primitives. 179 */ set_cache_line_size(unsigned n)180 static void set_cache_line_size(unsigned n) 181 { 182 std::lock_guard<std::mutex> lock(m_mutex); 183 m_cache_line_size = n; 184 } 185 /// Reset the cache line size. 186 /** 187 * Will set the value to the output of piranha::runtime_info::get_cache_line_size(). 188 * 189 * @throws std::system_error in case of failure(s) by threading primitives. 190 */ reset_cache_line_size()191 static void reset_cache_line_size() 192 { 193 std::lock_guard<std::mutex> lock(m_mutex); 194 m_cache_line_size = runtime_info::get_cache_line_size(); 195 } 196 /// Get max term output. 197 /** 198 * @return maximum number of terms displayed when printing series. 199 * 200 * @throws std::system_error in case of failure(s) by threading primitives. 201 */ get_max_term_output()202 static unsigned long get_max_term_output() 203 { 204 std::lock_guard<std::mutex> lock(m_mutex); 205 return m_max_term_output; 206 } 207 /// Set max term output. 208 /** 209 * @param n maximum number of terms to be displayed when printing series. 210 * 211 * @throws std::system_error in case of failure(s) by threading primitives. 212 */ set_max_term_output(unsigned long n)213 static void set_max_term_output(unsigned long n) 214 { 215 std::lock_guard<std::mutex> lock(m_mutex); 216 m_max_term_output = n; 217 } 218 /// Reset max term output. 219 /** 220 * Will set the max term output value to the default. 221 * 222 * @throws std::system_error in case of failure(s) by threading primitives. 223 */ reset_max_term_output()224 static void reset_max_term_output() 225 { 226 std::lock_guard<std::mutex> lock(m_mutex); 227 m_max_term_output = m_default_max_term_output; 228 } 229 /// Get the minimum work per thread. 230 /** 231 * @return the minimum work per thread. 232 */ get_min_work_per_thread()233 static unsigned long long get_min_work_per_thread() 234 { 235 return s_min_work_per_thread.load(); 236 } 237 /// Set the minimum work per thread. 238 /** 239 * @param n the minimum work per thread. 240 * 241 * @throws std::invalid_argument if \n is zero. 242 */ set_min_work_per_thread(unsigned long long n)243 static void set_min_work_per_thread(unsigned long long n) 244 { 245 if (unlikely(n == 0u)) { 246 piranha_throw(std::invalid_argument, "the minimum work per thread value must be strictly positive"); 247 } 248 return s_min_work_per_thread.store(n); 249 } 250 /// Reset the minimum work per thread. 251 /** 252 * The value will be reset to the default initial value. 253 */ reset_min_work_per_thread()254 static void reset_min_work_per_thread() 255 { 256 s_min_work_per_thread.store(s_default_min_work_per_thread); 257 } 258 }; 259 260 /// Alias for piranha::settings_. 261 /** 262 * This is the alias through which the methods in piranha::settings_ should be called. 263 */ 264 using settings = settings_<>; 265 } 266 267 #endif 268