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