Loading [MathJax]/extensions/TeX/AMSsymbols.js
 deal.II version GIT relicensing-2791-g2e2a880805 2025-03-11 02:00:00+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\}}\)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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#include <deal.II/base/types.h>
19
20#include <algorithm>
21#include <cstdlib> // for std::getenv
22#include <mutex>
23#include <thread>
24
25#ifdef DEAL_II_WITH_TBB
26# ifdef DEAL_II_TBB_WITH_ONEAPI
27# include <tbb/global_control.h>
28# else
29# include <tbb/task_scheduler_init.h>
30# endif
31#endif
32
33
34#ifdef DEAL_II_WITH_TASKFLOW
35# include <taskflow/taskflow.hpp>
36#endif
37
39
40
41unsigned int
43{
44 // There is a slight semantic change between our n_cores() call and the
45 // std::thread alternative: in case of an error the latter one returns 0
46 // in contrast to a 1 that n_cores() used to do. For compatibility, let's
47 // translate to our numbering scheme:
48 const unsigned int n_cores = std::thread::hardware_concurrency();
49 return n_cores == 0 ? 1 : n_cores;
50}
51
52
53void
54MultithreadInfo::set_thread_limit(const unsigned int max_threads)
55{
56 // set the maximal number of threads to the given value as specified
57 n_max_threads = max_threads;
58
59 // then also see if something was given in the environment
60 {
61 if (const char *penv = std::getenv("DEAL_II_NUM_THREADS"))
62 {
63 unsigned int max_threads_env = numbers::invalid_unsigned_int;
64 try
65 {
66 max_threads_env = Utilities::string_to_int(std::string(penv));
67 }
68 catch (...)
69 {
71 false,
73 std::string(
74 "When specifying the <DEAL_II_NUM_THREADS> environment "
75 "variable, it needs to be something that can be interpreted "
76 "as an integer. The text you have in the environment "
77 "variable is <") +
78 penv + ">"));
79 }
80
81 AssertThrow(max_threads_env > 0,
83 "When specifying the <DEAL_II_NUM_THREADS> environment "
84 "variable, it needs to be a positive number."));
85
87 n_max_threads = std::min(n_max_threads, max_threads_env);
88 else
89 n_max_threads = max_threads_env;
90 }
91 }
92
93 // If we have not set the number of allowed threads yet, just default to
94 // the number of available cores
97
98#ifdef DEAL_II_WITH_TBB
99# ifdef DEAL_II_TBB_WITH_ONEAPI
100 // tbb::global_control is a class that affects the specified behavior of
101 // tbb during its lifetime. Thus, in order to set a global thread limit
102 // for tbb we have to maintain the object throughout the execution of the
103 // program. We do this by maintaining a static std::unique_ptr.
104 //
105 // A std::unique_ptr is a good choice here because tbb::global_control
106 // does not provide a mechanism to override its setting - we can only
107 // delete the old and replace it with a new one.
108 static std::unique_ptr<tbb::global_control> tbb_global_control;
109 tbb_global_control = std::make_unique<tbb::global_control>(
110 tbb::global_control::max_allowed_parallelism, n_max_threads);
111
112# else
113 // Initialize the scheduler and destroy the old one before doing so
114 static tbb::task_scheduler_init dummy(tbb::task_scheduler_init::deferred);
115 if (dummy.is_active())
116 dummy.terminate();
117 dummy.initialize(n_max_threads);
118# endif
119#endif
120
121#ifdef DEAL_II_WITH_TASKFLOW
122 executor = std::make_unique<tf::Executor>(n_max_threads);
123#endif
124}
125
126
127
128unsigned int
134
135
136
137bool
142
143
144
145std::size_t
147{
148 // only simple data elements, so use sizeof operator
149 return sizeof(MultithreadInfo);
150}
151
152
153
154void
156{
157 static std::once_flag is_initialized;
158 std::call_once(is_initialized, []() {
160 });
161}
162
163
164
165#ifdef DEAL_II_WITH_TASKFLOW
166tf::Executor &
168{
169 // This should not trigger in normal user code, because we initialize the
170 // Executor in the static DoOnce struct at the end of this file unless you
171 // ask for the Executor before this static object gets constructed.
172 Assert(
173 executor.get() != nullptr,
175 "Please initialize multithreading using MultithreadInfo::set_thread_limit() first."));
176 return *(executor.get());
177}
178
179std::unique_ptr<tf::Executor> MultithreadInfo::executor = nullptr;
180#endif
181
183
184namespace
185{
186 // Force the first call to set_thread_limit happen before any tasks in TBB are
187 // used. This is necessary as tbb::task_scheduler_init has no effect if TBB
188 // got automatically initialized (which happens the first time we use it).
189 struct DoOnce
190 {
191 DoOnce()
192 {
194 }
195 } do_once;
196} // namespace
197
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:40
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:41
#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:598
constexpr unsigned int invalid_unsigned_int
Definition types.h:232
::VectorizedArray< Number, width > min(const ::VectorizedArray< Number, width > &, const ::VectorizedArray< Number, width > &)