diff --git a/algo/ca/core/tracking/CaFramework.h b/algo/ca/core/tracking/CaFramework.h index 50e1a7069f01a47f4f1f27da8cc674198e2e93ec..9d9ec0488b9a6466dfb73b74effda4f4157a3289 100644 --- a/algo/ca/core/tracking/CaFramework.h +++ b/algo/ca/core/tracking/CaFramework.h @@ -226,7 +226,7 @@ namespace cbm::algo::ca TrackingMonitorData fMonitorData{}; ///< Tracking monitor data (statistics per call) - int fNofThreads = 1; ///< Number of threads to execute the track-finder + int fNofThreads = 10; ///< Number of threads to execute the track-finder public: Vector<CaHitTimeInfo> fHitTimeInfo; @@ -243,11 +243,6 @@ namespace cbm::algo::ca Vector<Track> fRecoTracks{"Framework::fRecoTracks"}; ///< reconstructed tracks Vector<ca::HitIndex_t> fRecoHits{"Framework::fRecoHits"}; ///< packed hits of reconstructed tracks - - // WARN: Potential race conditions -> - Vector<int> fHitKeyToTrack{"Framework::fHitKeyToTrack"}; // strip to track pointers - - fvec EventTime{0.f}; fvec Err{0.f}; diff --git a/algo/ca/core/tracking/CaTrackFinder.cxx b/algo/ca/core/tracking/CaTrackFinder.cxx index e7679e3efe809a3d45eb55a6fc2b1fb24c35b413..2dfedb8f9ae5cb4e402104574a6f1a5e4ee297c8 100644 --- a/algo/ca/core/tracking/CaTrackFinder.cxx +++ b/algo/ca/core/tracking/CaTrackFinder.cxx @@ -23,6 +23,7 @@ #include "CaTrack.h" #include <chrono> +#include <thread> using namespace cbm::algo::ca; @@ -57,12 +58,15 @@ void TrackFinder::FindTracks() // ----- Reset data arrays ------------------------------------------------------------------------------------------- frAlgo.fvHitKeyFlags.reset(frAlgo.fInputData.GetNhitKeys(), 0); - frAlgo.fRecoTracks.clear(); - frAlgo.fRecoHits.clear(); - frAlgo.fRecoHits.reserve(2 * frAlgo.fInputData.GetNhits()); - frAlgo.fRecoTracks.reserve(2 * frAlgo.fInputData.GetNhits() / frAlgo.GetParameters().GetNstationsActive()); + size_t nHitsExpected = 2 * frAlgo.fInputData.GetNhits(); + size_t nTracksExpected = 2 * frAlgo.fInputData.GetNhits() / frAlgo.GetParameters().GetNstationsActive(); for (int iThread = 0; iThread < frAlgo.GetNofThreads(); ++iThread) { + fvRecoTracks[iThread].clear(); + fvRecoTracks[iThread].reserve(nTracksExpected / frAlgo.GetNofThreads()); + fvRecoHitIndices[iThread].clear(); + fvRecoHitIndices[iThread].reserve(nHitsExpected / frAlgo.GetNofThreads()); + frAlgo.fvTrackFinderWindow[iThread].InitTimeslice(); for (int iS = 0; iS < frAlgo.GetParameters().GetNstationsActive(); ++iS) { frAlgo.fvWData[iThread].TsHitIndices(iS).clear(); frAlgo.fvWData[iThread].TsHitIndices(iS).reserve(frAlgo.fInputData.GetNhits()); @@ -70,7 +74,6 @@ void TrackFinder::FindTracks() } frAlgo.fvHitKeyFlags.reset(frAlgo.fInputData.GetNhitKeys(), 0); - frAlgo.fHitKeyToTrack.reset(frAlgo.fInputData.GetNhitKeys(), -1); frAlgo.fHitTimeInfo.reset(frAlgo.fInputData.GetNhits()); @@ -207,8 +210,32 @@ void TrackFinder::FindTracks() << fvWindowEndThread[iThread] / 1.e6 << " ms"; } - for (int iThread = 0; iThread < frAlgo.GetNofThreads(); ++iThread) { - this->FindTracksThread(iThread); + // Save tracks + frAlgo.fRecoTracks.clear(); + frAlgo.fRecoHits.clear(); + if (frAlgo.GetNofThreads() == 1) { + this->FindTracksThread(0); + frAlgo.fRecoTracks = std::move(fvRecoTracks[0]); + frAlgo.fRecoHits = std::move(fvRecoHitIndices[0]); + } + else { + std::vector<std::thread> vThreadList; + vThreadList.reserve(frAlgo.GetNofThreads()); + for (int iTh = 0; iTh < frAlgo.GetNofThreads(); ++iTh) { + vThreadList.emplace_back(&TrackFinder::FindTracksThread, this, iTh); + } + for (auto& th: vThreadList) { + if (th.joinable()) { th.join(); } + } + auto Operation = [](size_t acc, const Vector<auto>& v) { return acc + v.size(); }; + int nRecoTracks = std::accumulate(fvRecoTracks.begin(), fvRecoTracks.end(), 0, Operation); + int nRecoHits = std::accumulate(fvRecoHitIndices.begin(), fvRecoHitIndices.end(), 0, Operation); + frAlgo.fRecoTracks.reserve(nRecoTracks); + frAlgo.fRecoHits.reserve(nRecoHits); + for (int iTh = 0; iTh < frAlgo.GetNofThreads(); ++iTh) { + frAlgo.fRecoTracks.insert(frAlgo.fRecoTracks.end(), fvRecoTracks[iTh].begin(), fvRecoTracks[iTh].end()); + frAlgo.fRecoHits.insert(frAlgo.fRecoHits.end(), fvRecoHitIndices[iTh].begin(), fvRecoHitIndices[iTh].end()); + } } frAlgo.fMonitorData.StopTimer(ETimer::FindTracks); @@ -331,7 +358,7 @@ void TrackFinder::FindTracksThread(int iThread) << statNwindowHits << " hits. " << " Processing " << dataRead << " % of the TS time and " << 100. * fvStatNhitsProcessed[iThread] / fStatNhitsTotal << " % of TS hits." - << " Already reconstructed " << frAlgo.fRecoTracks.size() << " tracks "; + << " Already reconstructed " << fvRecoTracks[iThread].size() << " tracks on thread #" << iThread; } } @@ -389,14 +416,14 @@ void TrackFinder::FindTracksThread(int iThread) } } else { // save the track - frAlgo.fRecoTracks.push_back(track); + fvRecoTracks[iThread].push_back(track); // mark the track hits as used for (int i = 0; i < track.fNofHits; i++) { int caHitId = frAlgo.fvWData[iThread].RecoHitIndex(trackFirstHit + i); const auto& h = frAlgo.fInputData.GetHit(caHitId); frAlgo.fvHitKeyFlags[h.FrontKey()] = 1; frAlgo.fvHitKeyFlags[h.BackKey()] = 1; - frAlgo.fRecoHits.push_back(caHitId); + fvRecoHitIndices[iThread].push_back(caHitId); } } trackFirstHit += track.fNofHits; @@ -421,12 +448,20 @@ void TrackFinder::Init() fvWindowEndThread.clear(); fvStatNwindows.clear(); fvStatNhitsProcessed.clear(); - + fvRecoTracks.clear(); + fvRecoHitIndices.clear(); + fvWindowStartThread.resize(frAlgo.GetNofThreads()); fvWindowEndThread.resize(frAlgo.GetNofThreads()); fvStatNwindows.resize(frAlgo.GetNofThreads()); fvStatNhitsProcessed.resize(frAlgo.GetNofThreads()); + fvRecoTracks.resize(frAlgo.GetNofThreads()); + fvRecoHitIndices.resize(frAlgo.GetNofThreads()); + for (int iThread = 0; iThread < frAlgo.GetNofThreads(); ++iThread) { + fvRecoTracks[iThread].SetName(std::string("TrackFinder::fvRecoTracks_") + std::to_string(iThread)); + fvRecoHitIndices[iThread].SetName(std::string("TrackFinder::fvRecoHitIndices_") + std::to_string(iThread)); + } fWindowLength = (ca::Framework::TrackingMode::kMcbm == frAlgo.fTrackingMode) ? 500 : 10000; } diff --git a/algo/ca/core/tracking/CaTrackFinder.h b/algo/ca/core/tracking/CaTrackFinder.h index ba5eca97e06eb0d213c63a92419b4a8914577988..a8f33ab701376ca9f2841369dd6e97181e6cb0b5 100644 --- a/algo/ca/core/tracking/CaTrackFinder.h +++ b/algo/ca/core/tracking/CaTrackFinder.h @@ -70,6 +70,9 @@ namespace cbm::algo::ca std::vector<int> fvStatNwindows; std::vector<int> fvStatNhitsProcessed; + std::vector<Vector<Track>> fvRecoTracks; ///< reconstructed tracks + std::vector<Vector<ca::HitIndex_t>> fvRecoHitIndices; ///< packed hits of reconstructed tracks + float fWindowLength = 0.; float fWindowOverlap = 15.; // ns diff --git a/algo/ca/core/tracking/CaTrackFinderWindow.cxx b/algo/ca/core/tracking/CaTrackFinderWindow.cxx index f25135dc4c5ea703a04e6299231947a67c3cefb1..5e8f2676091102d6a8441263310984e6f093534f 100644 --- a/algo/ca/core/tracking/CaTrackFinderWindow.cxx +++ b/algo/ca/core/tracking/CaTrackFinderWindow.cxx @@ -119,6 +119,10 @@ bool TrackFinderWindow::checkTripletMatch(const ca::Triplet& l, const ca::Triple return true; } +void TrackFinderWindow::InitTimeslice() +{ + fvHitKeyToTrack.reset(frAlgo.fInputData.GetNhitKeys(), -1); +} // ************************************************************************************************** // * * @@ -428,8 +432,8 @@ void TrackFinderWindow::CaTrackFinderSlice() fvTrackCandidates.clear(); for (const auto& h : frWData.Hits()) { - frAlgo.fHitKeyToTrack[h.FrontKey()] = -1; - frAlgo.fHitKeyToTrack[h.BackKey()] = -1; + fvHitKeyToTrack[h.FrontKey()] = -1; + fvHitKeyToTrack[h.BackKey()] = -1; } //== Loop over triplets with the required level, find and store track candidates @@ -542,7 +546,7 @@ void TrackFinderWindow::CaTrackFinderSlice() const ca::Hit& h = frAlgo.fInputData.GetHit(hitId); bool isAlive = true; { // front strip - auto& stripF = (frAlgo.fHitKeyToTrack)[h.FrontKey()]; + auto& stripF = fvHitKeyToTrack[h.FrontKey()]; if ((stripF >= 0) && (stripF != tr.Id())) { // strip is used by other candidate const auto& other = fvTrackCandidates[stripF]; if (!other.IsAlive() && tr.IsBetterThan(other)) { @@ -561,7 +565,7 @@ void TrackFinderWindow::CaTrackFinderSlice() } { // back strip - auto& stripB = (frAlgo.fHitKeyToTrack)[h.BackKey()]; + auto& stripB = fvHitKeyToTrack[h.BackKey()]; if ((stripB >= 0) && (stripB != tr.Id())) { // strip is used by other candidate const auto& other = fvTrackCandidates[stripB]; if (!other.IsAlive() && tr.IsBetterThan(other)) { @@ -591,18 +595,18 @@ void TrackFinderWindow::CaTrackFinderSlice() tr.SetAlive(true); for (int iHit = 0; tr.IsAlive() && (iHit < (int) tr.Hits().size()); ++iHit) { const ca::Hit& h = frAlgo.fInputData.GetHit(tr.Hits()[iHit]); - tr.SetAlive(tr.IsAlive() && ((frAlgo.fHitKeyToTrack)[h.FrontKey()] == tr.Id()) - && ((frAlgo.fHitKeyToTrack)[h.BackKey()] == tr.Id())); + tr.SetAlive(tr.IsAlive() && (fvHitKeyToTrack[h.FrontKey()] == tr.Id()) + && (fvHitKeyToTrack[h.BackKey()] == tr.Id())); } if (!tr.IsAlive()) { // release strips for (auto hitId : tr.Hits()) { const ca::Hit& h = frAlgo.fInputData.GetHit(hitId); - if (frAlgo.fHitKeyToTrack[h.FrontKey()] == tr.Id()) { - frAlgo.fHitKeyToTrack[h.FrontKey()] = -1; + if (fvHitKeyToTrack[h.FrontKey()] == tr.Id()) { + fvHitKeyToTrack[h.FrontKey()] = -1; } - if (frAlgo.fHitKeyToTrack[h.BackKey()] == tr.Id()) { - frAlgo.fHitKeyToTrack[h.BackKey()] = -1; + if (fvHitKeyToTrack[h.BackKey()] == tr.Id()) { + fvHitKeyToTrack[h.BackKey()] = -1; } } } diff --git a/algo/ca/core/tracking/CaTrackFinderWindow.h b/algo/ca/core/tracking/CaTrackFinderWindow.h index 2813e5ccc22e73344a0a03a3a27453ad823f71ee..b47eab980768024cf7493cd1921770ab5ddb65bd 100644 --- a/algo/ca/core/tracking/CaTrackFinderWindow.h +++ b/algo/ca/core/tracking/CaTrackFinderWindow.h @@ -60,6 +60,9 @@ namespace cbm::algo::ca void CAFindTrack(int ista, ca::Branch& best_tr, const ca::Triplet* curr_trip, ca::Branch& curr_tr, unsigned char min_best_l, ca::Branch* new_tr); + /// \note The function initializes global arrays for a given thread + void InitTimeslice(); + private: ///------------------------------- /// Private methods @@ -78,8 +81,11 @@ namespace cbm::algo::ca /// \note The candidates may share any amount of hits. Vector<ca::Branch> fvTrackCandidates{"TrackFinderWindow::fTrackCandidates"}; - Vector<int> fvHitFirstTriplet{"Framework::fHitFirstTriplet"}; /// link hit -> first triplet { hit, *, *} - Vector<int> fvHitNofTriplets{"Framework::fHitNofTriplets"}; /// link hit ->n triplets { hit, *, *} + Vector<int> fvHitFirstTriplet{"TrackFinderWindow::fvHitFirstTriplet"}; /// link hit -> first triplet { hit, *, *} + Vector<int> fvHitNofTriplets{"TrackFinderWindow::fvHitNofTriplets"}; /// link hit ->n triplets { hit, *, *} + + /// \note Global array for a given thread + Vector<int> fvHitKeyToTrack{"TrackFinderWindow::fvHitKeyToTrack"}; ca::Framework& frAlgo; ///< Reference to the main track finder algorithm class static constexpr bool fDebug = false; // print debug info