Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MT with LCIO input #71

Merged
merged 11 commits into from
Mar 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,11 @@ ctest
# Run specific test with verbose output
ctest --verbose -R test_clicReconstruction
```

## Using Event Data Model (EDM) converters

Please refer to [this doc](./doc/edmConverters.md) on how to convert between EDMs in k4MarlinWrapper

## Running in parallel: multi-thread support

Please refer to [this doc](./doc/howtoMultithread.md) on how to run with multi-thread support, and which options are supported.
123 changes: 123 additions & 0 deletions doc/howtoMultithread.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# How to run multithreading with k4MarlinWrapper (Gaudi)

**Supported**
- Reading LCIO events with `LcioEvent()`
- Writing LCIO events with `LcioEventOutput()`
- Running `MarlinProcessorWrapper`s with **no** converters
- Using `whiteboard` as `ExtSvc` (no k4DataSvc or EventDataSvc)

**Not supported**
- Using EDM converters `EDM4hep2LcioTool` and `Lcio2EDM4hepTool()`
- Reading EDM4hep events with `PodioInput()`
- Writing EDM4hep events with `PodioOutput()`
- Writing EDM4hep events with `MarlinProcessorWrapper` of type `LCIOOutputProcessor`
- Running non-thread algorithms/processors in parallel

## Running Gaudi with multithreading support

Gaudi uses [Intel TBB](https://oneapi-src.github.io/oneTBB/) under the hood for multithreading.

Gaudi exposes two main levels of parallelism:
- Inter-event parallelism: running multiple events in parallel
- Intra-event parallelism: running multiple algorithms in parallel, within an event

The two levels of parallelims can be combined: events can run in parallel, and algorithms within the events can run in parallel.

### How to run with inter-event parallelism

The following components are used to achieve parallelism:

```python
from Configurables import (HiveWhiteBoard, HiveSlimEventLoopMgr, AvalancheSchedulerSvc)
```

These 3 components need to be configued to adapt the level of parallelism to the sequence, algorithms and hardware to be used.

- Event Data Service: `HiveWhiteBoard`
+ *EventSlots*: Number of events that may run in parallel, each with its own EventStore
+ This is the Event Data Service, which needs the number of EventSlots
- Event Loop Manager: `HiveSlimEventLoopMgr`
+ Event Loop Manager with parallelism support
- Thread Scheduling config: `AvalancheSchedulerSvc`
+ Scheduler to indicate the number of threads to use
+ In needs the total number of threads to use: this determines how many events and algorithms can be in flight (run in parallel)
+ Default value is `-1` which indicate TBB to take over the machine with what it decides to be the optimal configuration


All these components can be set as follows in the options file:

```python
evtslots = 4
threads = 4

whiteboard = HiveWhiteBoard("EventDataSvc", EventSlots=evtslots)
slimeventloopmgr = HiveSlimEventLoopMgr(SchedulerName="AvalancheSchedulerSvc", OutputLevel=DEBUG)
scheduler = AvalancheSchedulerSvc(ThreadPoolSize=threads, OutputLevel=WARNING)

from Configurables import ApplicationMgr
ApplicationMgr( TopAlg = [seq],
EvtSel = 'NONE',
EvtMax = 10,
ExtSvc = [whiteboard],
EventLoop=slimeventloopmgr,
MessageSvcType="InertMessageSvc"
)
```

To only run events in parallel, with no parallelism between the algorithms within each event, the cardinality of the algorithms must be set:

- Given a list of algorithms, set the cardinality of all to be 1
- Create a `GaudiSequencer` with all the algorithms as `Members`
- Set the `GaudiSequencer` sequential property to true
- Pass the created `GaudiSequencer` to the Application Manager in the `TopAlg`: `TopAlg = [seq]`

```python
from Configurables import MarlinProcessorWrapper
from Configurables import (GaudiSequencer)

cardinality = 1

alg1 = MarlinProcessorWrapper("alg1")
alg2 = MarlinProcessorWrapper("alg2")
alg3 = MarlinProcessorWrapper("alg3")
alg4 = MarlinProcessorWrapper("alg4")

algList = []

algList.append(alg1)
algList.append(alg2)
algList.append(alg3)
algList.append(alg4)

for algo in algList:
algo.Cardinality = cardinality
algo.OutputLevel = DEBUG

seq = GaudiSequencer(
"createViewSeq",
Members=algList,
Sequential=True,
OutputLevel=VERBOSE)

from Configurables import ApplicationMgr
ApplicationMgr( TopAlg = [seq],
EvtSel = 'NONE',
EvtMax = 10,
ExtSvc = [whiteboard],
EventLoop=slimeventloopmgr,
MessageSvcType="InertMessageSvc"
)
```

## Running example

A multi-threaded CLIC Reconstruction can be run in multi-threaded mode, for LCIO input and output.
After successful compilation, from the build location:

```sh
# Check available tests
ctest -N

# Run multi-threaded clicReconstruction test
ctest -R clicRec_lcio_mt
```
1 change: 1 addition & 0 deletions k4MarlinWrapper/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ gaudi_install(SCRIPTS)
gaudi_add_module(k4MarlinWrapperPlugins
SOURCES
src/components/LcioEventAlgo.cpp
src/components/LcioEventOutput.cpp
LINK
Gaudi::GaudiAlgLib
${Marlin_LIBRARIES}
Expand Down
4 changes: 2 additions & 2 deletions k4MarlinWrapper/k4MarlinWrapper/LcioEventAlgo.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
#include <GaudiKernel/IEventProcessor.h>

#include <EVENT/LCIO.h>
#include <IOIMPL/LCFactory.h>
#include <MT/LCReader.h>

#include "k4MarlinWrapper/LCEventWrapper.h"

Expand All @@ -49,7 +49,7 @@ class LcioEvent : public GaudiAlgorithm {

private:
Gaudi::Property<std::vector<std::string>> m_fileNames{this, "Files", {}};
IO::LCReader* m_reader = nullptr;
MT::LCReader* m_reader = nullptr;
};

#endif
64 changes: 64 additions & 0 deletions k4MarlinWrapper/k4MarlinWrapper/LcioEventOutput.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* Copyright 2021 CERN
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* In applying this licence, CERN does not waive the privileges and immunities
* granted to it by virtue of its status as an Intergovernmental Organization
* or submit itself to any jurisdiction.
*
*/

#ifndef K4MARLINWRAPPER_LCIOEVENTOUTPUT_H
#define K4MARLINWRAPPER_LCIOEVENTOUTPUT_H

////////////////////////////////////////////
// LCEventOutput: Write out LCIO events using MT writer from LCIO
////////////////////////////////////////////

#include <iostream>

#include <GaudiAlg/GaudiAlgorithm.h>

#include <EVENT/LCIO.h>
#include <IMPL/LCCollectionVec.h>
#include <IMPL/LCEventImpl.h>
#include <MT/LCWriter.h>
#include <lcio.h>

#include "k4MarlinWrapper/LCEventWrapper.h"

class LcioEventOutput : public GaudiAlgorithm {
public:
explicit LcioEventOutput(const std::string& name, ISvcLocator* pSL);
virtual ~LcioEventOutput() = default;
virtual StatusCode initialize() override final;
virtual StatusCode execute() override final;
virtual StatusCode finalize() override final;

private:
MT::LCWriter* m_writer = nullptr;

Gaudi::Property<std::string> m_write_mode{this, "WriteMode", {}};
Gaudi::Property<std::string> m_filename{this, "OutputFileName", {}};
Gaudi::Property<std::vector<std::string>> m_drop_coll_names{this, "DropCollectionNames", {}};
Gaudi::Property<std::vector<std::string>> m_keep_coll_names{this, "KeepCollectionNames", {}};
Gaudi::Property<std::vector<std::string>> m_drop_coll_types{this, "DropCollectionTypes", {}};
Gaudi::Property<std::vector<std::string>> m_full_subset_colls{this, "FullSubsetCollections", {}};

void dropCollections(lcio::LCEventImpl* event, std::vector<lcio::LCCollectionVec*>& subsets);

void revertSubsets(const std::vector<lcio::LCCollectionVec*>& subsets);
};

#endif
6 changes: 3 additions & 3 deletions k4MarlinWrapper/src/components/LcioEventAlgo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ StatusCode LcioEvent::initialize() {
if (sc.isFailure())
return sc;

m_reader = IOIMPL::LCFactory::getInstance()->createLCReader();
m_reader = new MT::LCReader(0);
m_reader->open(m_fileNames);
info() << "Initialized the LcioEvent Algo: " << m_fileNames[0] << endmsg;
return StatusCode::SUCCESS;
Expand Down Expand Up @@ -62,8 +62,8 @@ StatusCode LcioEvent::execute() {
// wrappers
info() << "Reading from file: " << m_fileNames[0] << endmsg;

auto pO = std::make_unique<LCEventWrapper>(theEvent);
const StatusCode sc = eventSvc()->registerObject("/Event/LCEvent", pO.release());
auto myEvWr = new LCEventWrapper(theEvent.release());
const StatusCode sc = eventSvc()->registerObject("/Event/LCEvent", myEvWr);
if (sc.isFailure()) {
error() << "Failed to store the LCEvent" << endmsg;
return sc;
Expand Down
Loading