Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-05 08:11:53

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   explicit task_arena(int nthreads = tbb::task_arena::automatic,
0053                       unsigned res = 1) {
0054     if (enableTBB(nthreads)) {
0055       tbb.emplace(nthreads, res);
0056     }
0057   }
0058 
0059   template <typename F>
0060   void execute(const F& f) {
0061     if (tbb) {
0062       tbb->execute(f);
0063     } else {
0064       f();
0065     }
0066   }
0067 };
0068 
0069 /// Small wrapper for tbb::parallel_for.
0070 class parallel_for {
0071  public:
0072   template <typename R, typename F>
0073   parallel_for(const R& r, const F& f) {
0074     if (enableTBB()) {
0075       tbb::parallel_for(r, f);
0076     } else {
0077       for (auto i = r.begin(); i != r.end(); ++i) {  // use default grainsize=1
0078         f(R(i, i + 1));
0079       }
0080     }
0081   }
0082 };
0083 
0084 /// Small wrapper for tbb::queuing_mutex and tbb::queuing_mutex::scoped_lock.
0085 class queuing_mutex {
0086   std::optional<tbb::queuing_mutex> tbb;
0087 
0088  public:
0089   queuing_mutex() {
0090     if (enableTBB()) {
0091       tbb.emplace();
0092     }
0093   }
0094 
0095   class scoped_lock {
0096     std::optional<tbb::queuing_mutex::scoped_lock> tbb;
0097 
0098    public:
0099     scoped_lock() {
0100       if (enableTBB()) {
0101         tbb.emplace();
0102       }
0103     }
0104 
0105     explicit scoped_lock(queuing_mutex& m) {
0106       if (enableTBB()) {
0107         tbb.emplace(*m.tbb);
0108       }
0109     }
0110   };
0111 };
0112 
0113 }  // namespace ActsExamples::tbbWrap