Skip to content
Snippets Groups Projects
Commit 1815aaab authored by Sergei Zharko's avatar Sergei Zharko Committed by Sergey Gorbunov
Browse files

Ca: multithreaded track finding

parent 89bb762a
No related branches found
No related tags found
1 merge request!1661CA: multithreaded execution of timeslice reconstruction
......@@ -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};
......
......@@ -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;
}
......@@ -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
......
......@@ -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;
}
}
}
......
......@@ -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
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment