Reference documentation for deal.II version GIT relicensing-372-g11f0589fc4 2024-04-12 18:50:02+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
multithread_info.cc
Go to the documentation of this file.
1// ------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: LGPL-2.1-or-later
4// Copyright (C) 2000 - 2023 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Part of the source code is dual licensed under Apache-2.0 WITH
9// LLVM-exception OR LGPL-2.1-or-later. Detailed license information
10// governing the source code and code contributions can be found in
11// LICENSE.md and CONTRIBUTING.md at the top level directory of deal.II.
12//
13// ------------------------------------------------------------------------
14
17
18#include <algorithm>
19#include <cstdlib> // for std::getenv
20#include <mutex>
21#include <thread>
22
23#ifdef DEAL_II_WITH_TBB
24# ifdef DEAL_II_TBB_WITH_ONEAPI
25# include <tbb/global_control.h>
26# else
27# include <tbb/task_scheduler_init.h>
28# endif
29#endif
30
31
32#ifdef DEAL_II_WITH_TASKFLOW
33# include <taskflow/taskflow.hpp>
34#endif
35
37
38
39unsigned int
41{
42 // There is a slight semantic change between our n_cores() call and the
43 // std::thread alternative: in case of an error the latter one returns 0
44 // in contrast to a 1 that n_cores() used to do. For compatibility, let's
45 // translate to our numbering scheme:
46 const unsigned int n_cores = std::thread::hardware_concurrency();
47 return n_cores == 0 ? 1 : n_cores;
48}
49
50
51void
52MultithreadInfo::set_thread_limit(const unsigned int max_threads)
53{
54 // set the maximal number of threads to the given value as specified
55 n_max_threads = max_threads;
56
57 // then also see if something was given in the environment
58 {
59 if (const char *penv = std::getenv("DEAL_II_NUM_THREADS"))
60 {
61 unsigned int max_threads_env = numbers::invalid_unsigned_int;
62 try
63 {
64 max_threads_env = Utilities::string_to_int(std::string(penv));
65 }
66 catch (...)
67 {
69 false,
71 std::string(
72 "When specifying the <DEAL_II_NUM_THREADS> environment "
73 "variable, it needs to be something that can be interpreted "
74 "as an integer. The text you have in the environment "
75 "variable is <") +
76 penv + ">"));
77 }
78
79 AssertThrow(max_threads_env > 0,
81 "When specifying the <DEAL_II_NUM_THREADS> environment "
82 "variable, it needs to be a positive number."));
83
85 n_max_threads = std::min(n_max_threads, max_threads_env);
86 else
87 n_max_threads = max_threads_env;
88 }
89 }
90
91 // If we have not set the number of allowed threads yet, just default to
92 // the number of available cores
95
96#ifdef DEAL_II_WITH_TBB
97# ifdef DEAL_II_TBB_WITH_ONEAPI
98 // tbb::global_control is a class that affects the specified behavior of
99 // tbb during its lifetime. Thus, in order to set a global thread limit
100 // for tbb we have to maintain the object throughout the execution of the
101 // program. We do this by maintaining a static std::unique_ptr.
102 //
103 // A std::unique_ptr is a good choice here because tbb::global_control
104 // does not provide a mechanism to override its setting - we can only
105 // delete the old and replace it with a new one.
106 static std::unique_ptr<tbb::global_control> tbb_global_control;
107 tbb_global_control = std::make_unique<tbb::global_control>(
108 tbb::global_control::max_allowed_parallelism, n_max_threads);
109
110# else
111 // Initialize the scheduler and destroy the old one before doing so
112 static tbb::task_scheduler_init dummy(tbb::task_scheduler_init::deferred);
113 if (dummy.is_active())
114 dummy.terminate();
115 dummy.initialize(n_max_threads);
116# endif
117#endif
118
119#ifdef DEAL_II_WITH_TASKFLOW
120 executor = std::make_unique<tf::Executor>(n_max_threads);
121#endif
122}
123
124
125
126unsigned int
132
133
134
135bool
140
141
142
143std::size_t
145{
146 // only simple data elements, so use sizeof operator
147 return sizeof(MultithreadInfo);
148}
149
150
151
152void
154{
155 static std::once_flag is_initialized;
156 std::call_once(is_initialized, []() {
158 });
159}
160
161
162
163#ifdef DEAL_II_WITH_TASKFLOW
164tf::Executor &
166{
167 // This should not trigger in normal user code, because we initialize the
168 // Executor in the static DoOnce struct at the end of this file unless you
169 // ask for the Executor before this static object gets constructed.
170 Assert(
171 executor.get() != nullptr,
173 "Please initialize multithreading using MultithreadInfo::set_thread_limit() first."));
174 return *(executor.get());
175}
176
177std::unique_ptr<tf::Executor> MultithreadInfo::executor = nullptr;
178#endif
179
181
182namespace
183{
184 // Force the first call to set_thread_limit happen before any tasks in TBB are
185 // used. This is necessary as tbb::task_scheduler_init has no effect if TBB
186 // got automatically initialized (which happens the first time we use it).
187 struct DoOnce
188 {
189 DoOnce()
190 {
192 }
193 } do_once;
194} // namespace
195
static unsigned int n_max_threads
MultithreadInfo()=delete
static bool is_running_single_threaded()
static std::unique_ptr< tf::Executor > executor
static void initialize_multithreading()
static unsigned int n_cores()
static unsigned int n_threads()
static void set_thread_limit(const unsigned int max_threads=numbers::invalid_unsigned_int)
static std::size_t memory_consumption()
static tf::Executor & get_taskflow_executor()
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:502
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:503
#define Assert(cond, exc)
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
int string_to_int(const std::string &s)
Definition utilities.cc:605
static const unsigned int invalid_unsigned_int
Definition types.h:220
::VectorizedArray< Number, width > min(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)