Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:11:47

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #pragma once
0010 
0011 #include <optional>
0012 
0013 #include <tbb/parallel_for.h>
0014 #include <tbb/queuing_mutex.h>
0015 #include <tbb/task_arena.h>
0016 
0017 /// Wrapper for most of the tbb functions that we use in Sequencer.
0018 ///
0019 /// It disables the use of tbb if nthreads=1.
0020 /// Note that only a small subset of tbb functions are implemented, and
0021 /// tbb::blocked_range (which doesn't require any thread setup) is still taken
0022 /// from the tbb library.
0023 ///
0024 /// Based on an idea from
0025 ///   https://stackoverflow.com/questions/59736661/how-to-completely-switch-off-threading-in-tbb-code
0026 
0027 namespace ActsExamples::tbbWrap {
0028 /// enableTBB keeps a record of whether we are multi-threaded (nthreads!=1) or
0029 /// not. This is set once in task_arena and stored globally.
0030 /// This means that enableTBB(nthreads) itself is not thread-safe. That should
0031 /// be fine because the task_arena is initialised before spawning any threads.
0032 /// If multi-threading is ever enabled, then it is not disabled.
0033 static bool enableTBB(int nthreads = -99) {
0034   static bool setting = false;
0035   if (nthreads != -99) {
0036     bool newSetting = (nthreads != 1);
0037     if (!setting && newSetting) {
0038       setting = newSetting;
0039     }
0040   }
0041   return setting;
0042 }
0043 
0044 /// Small wrapper for tbb::task_arena.
0045 /// Note that the tbbWrap::task_arena constructor is not thread-safe.
0046 /// That should be fine because the task_arena is initialised before spawning
0047 /// any threads.
0048 class task_arena {
0049   std::optional<tbb::task_arena> tbb;
0050 
0051  public:
0052   task_arena(int nthreads = tbb::task_arena::automatic, unsigned res = 1) {
0053     if (enableTBB(nthreads)) {
0054       tbb.emplace(nthreads, res);
0055     }
0056   }
0057 
0058   template <typename F>
0059   void execute(const F& f) {
0060     if (tbb) {
0061       tbb->execute(f);
0062     } else {
0063       f();
0064     }
0065   }
0066 };
0067 
0068 /// Small wrapper for tbb::parallel_for.
0069 class parallel_for {
0070  public:
0071   template <typename R, typename F>
0072   parallel_for(const R& r, const F& f) {
0073     if (enableTBB()) {
0074       tbb::parallel_for(r, f);
0075     } else {
0076       for (auto i = r.begin(); i != r.end(); ++i) {  // use default grainsize=1
0077         f(R(i, i + 1));
0078       }
0079     }
0080   }
0081 };
0082 
0083 /// Small wrapper for tbb::queuing_mutex and tbb::queuing_mutex::scoped_lock.
0084 class queuing_mutex {
0085   std::optional<tbb::queuing_mutex> tbb;
0086 
0087  public:
0088   queuing_mutex() {
0089     if (enableTBB()) {
0090       tbb.emplace();
0091     }
0092   }
0093 
0094   class scoped_lock {
0095     std::optional<tbb::queuing_mutex::scoped_lock> tbb;
0096 
0097    public:
0098     scoped_lock() {
0099       if (enableTBB()) {
0100         tbb.emplace();
0101       }
0102     }
0103 
0104     explicit scoped_lock(queuing_mutex& m) {
0105       if (enableTBB()) {
0106         tbb.emplace(*m.tbb);
0107       }
0108     }
0109   };
0110 };
0111 
0112 }  // namespace ActsExamples::tbbWrap