Skip to content

Commit 7e30c95

Browse files
committed
DPL: hide InputSpan from common headers
InputSpan usage of std::function causes an avalanche of template instantiantions, resulting (at least) in a rather large slowdown of Framework/Core compilation. With this patch we go from Compilation (452 times): Parsing (frontend): 1686.8 s Codegen & opts (backend): 1120.7 s to Compilation (452 times): Parsing (frontend): 1441.4 s Codegen & opts (backend): 842.8 s
1 parent 5f086d1 commit 7e30c95

18 files changed

Lines changed: 161 additions & 107 deletions

Detectors/Raw/include/DetectorsRaw/SimpleSTF.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <gsl/span>
2020
#include "Framework/InputRoute.h"
2121
#include "Framework/InputRecord.h"
22+
#include "Framework/InputSpan.h"
2223

2324
namespace o2
2425
{
@@ -44,6 +45,7 @@ struct SimpleSTF {
4445
std::vector<o2f::InputRoute> schema;
4546
PartsRef partsRef; // i-th entry is the 1st entry and N parts of multipart for i-th channel in the messages
4647
Messages messages;
48+
o2f::InputSpan span;
4749
o2f::InputRecord record;
4850
};
4951

Detectors/Raw/src/SimpleSTF.cxx

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,19 @@
1717
using namespace o2::raw;
1818

1919
SimpleSTF::SimpleSTF(std::vector<o2f::InputRoute>&& sch, PartsRef&& pref, Messages&& msg)
20-
: schema{std::move(sch)}, partsRef{std::move(pref)}, messages{std::move(msg)}, record{schema, {[this](size_t i, size_t part) { // getter for the DataRef of a part in the input "i"
21-
auto ref = this->partsRef[i].first + (part << 1); // entry of the header for this part, the payload follows
22-
auto header = static_cast<char const*>(this->messages[ref]->data());
23-
auto payload = static_cast<char const*>(this->messages[ref + 1]->data());
24-
return o2f::DataRef{nullptr, header, payload};
25-
},
26-
[this](size_t i) { // getter for the nparts in the input "i"
27-
return i < partsRef.size() ? partsRef[i].second : 0;
28-
},
29-
this->partsRef.size()}}
20+
: schema{std::move(sch)},
21+
partsRef{std::move(pref)},
22+
messages{std::move(msg)},
23+
span{[this](size_t i, size_t part) { // getter for the DataRef of a part in the input "i"
24+
auto ref = this->partsRef[i].first + (part << 1); // entry of the header for this part, the payload follows
25+
auto header = static_cast<char const*>(this->messages[ref]->data());
26+
auto payload = static_cast<char const*>(this->messages[ref + 1]->data());
27+
return o2f::DataRef{nullptr, header, payload};
28+
},
29+
[this](size_t i) { // getter for the nparts in the input "i"
30+
return i < partsRef.size() ? partsRef[i].second : 0;
31+
},
32+
this->partsRef.size()},
33+
record{schema, span}
3034
{
3135
}

Detectors/TPC/workflow/readers/include/TPCReaderWorkflow/TPCSectorCompletionPolicy.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include "Framework/CompletionPolicy.h"
1919
#include "Framework/InputSpec.h"
20+
#include "Framework/InputSpan.h"
2021
#include "Framework/DeviceSpec.h"
2122
#include "DataFormatsTPC/TPCSectorHeader.h"
2223
#include "Headers/DataHeaderHelpers.h"
@@ -87,7 +88,7 @@ class TPCSectorCompletionPolicy
8788
return std::regex_match(device.name.begin(), device.name.end(), std::regex(expression.c_str()));
8889
};
8990

90-
auto callback = [bRequireAll = mRequireAll, inputMatchers = mInputMatchers, externalInputMatchers = mExternalInputMatchers, pTpcSectorMask = mTpcSectorMask](framework::CompletionPolicy::InputSet inputs) -> framework::CompletionPolicy::CompletionOp {
91+
auto callback = [bRequireAll = mRequireAll, inputMatchers = mInputMatchers, externalInputMatchers = mExternalInputMatchers, pTpcSectorMask = mTpcSectorMask](framework::InputSpan const& inputs) -> framework::CompletionPolicy::CompletionOp {
9192
unsigned long tpcSectorMask = pTpcSectorMask ? *pTpcSectorMask : 0xFFFFFFFFF;
9293
std::bitset<NSectors> validSectors = 0;
9394
bool haveMatchedInput = false;

Framework/Core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ o2_add_library(Framework
6565
src/GraphvizHelpers.cxx
6666
src/HTTPParser.cxx
6767
src/InputRecord.cxx
68+
src/InputSpan.cxx
6869
src/InputSpec.cxx
6970
src/OutputSpec.cxx
7071
src/LifetimeHelpers.cxx

Framework/Core/include/Framework/CompletionPolicy.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
#define FRAMEWORK_COMPLETIONPOLICY_H
1212

1313
#include "Framework/DataRef.h"
14-
#include "Framework/InputSpan.h"
1514

1615
#include <functional>
1716
#include <string>
@@ -24,6 +23,7 @@ namespace framework
2423

2524
struct DeviceSpec;
2625
struct InputRecord;
26+
struct InputSpan;
2727

2828
/// Policy to describe what to do for a matching DeviceSpec
2929
/// whenever a new message arrives. The InputRecord being passed to
@@ -50,8 +50,7 @@ struct CompletionPolicy {
5050

5151
using Matcher = std::function<bool(DeviceSpec const& device)>;
5252
using InputSetElement = DataRef;
53-
using InputSet = InputSpan const&;
54-
using Callback = std::function<CompletionOp(InputSet)>;
53+
using Callback = std::function<CompletionOp(InputSpan const&)>;
5554

5655
/// Name of the policy itself.
5756
std::string name = "";

Framework/Core/include/Framework/InputRecord.h

Lines changed: 6 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#include "Framework/DataRefUtils.h"
1515
#include "Framework/InputRoute.h"
1616
#include "Framework/TypeTraits.h"
17-
#include "Framework/InputSpan.h"
1817
#include "Framework/TableConsumer.h"
1918
#include "Framework/Traits.h"
2019
#include "Framework/RuntimeError.h"
@@ -40,6 +39,7 @@ namespace framework
4039
{
4140

4241
struct InputSpec;
42+
struct InputSpan;
4343

4444
/// @class InputRecord
4545
/// @brief The input API of the Data Processing Layer
@@ -98,7 +98,7 @@ class InputRecord
9898
using DataHeader = o2::header::DataHeader;
9999

100100
InputRecord(std::vector<InputRoute> const& inputs,
101-
InputSpan&& span);
101+
InputSpan& span);
102102

103103
/// A deleter type to be used with unique_ptr, which can be marked that
104104
/// it does not own the underlying resource and thus should not delete it.
@@ -176,30 +176,9 @@ class InputRecord
176176
int getPos(const char* name) const;
177177
int getPos(const std::string& name) const;
178178

179-
DataRef getByPos(int pos, int part = 0) const
180-
{
181-
if (pos >= mSpan.size() || pos < 0) {
182-
throw runtime_error_f("Unknown message requested at position %d", pos);
183-
}
184-
if (part > 0 && part >= getNofParts(pos)) {
185-
throw runtime_error_f("Invalid message part index at %d:%d", pos, part);
186-
}
187-
if (pos >= mInputsSchema.size()) {
188-
throw runtime_error_f("Unknown schema at position %d", pos);
189-
}
190-
auto ref = mSpan.get(pos, part);
191-
ref.spec = &mInputsSchema[pos].matcher;
192-
return ref;
193-
}
194-
195-
size_t getNofParts(int pos) const
196-
{
197-
if (pos < 0 || pos >= mSpan.size()) {
198-
return 0;
199-
}
200-
return mSpan.getNofParts(pos);
201-
}
179+
DataRef getByPos(int pos, int part = 0) const;
202180

181+
size_t getNofParts(int pos) const;
203182
/// Get the object of specified type T for the binding R.
204183
/// If R is a string like object, we look up by name the InputSpec and
205184
/// return the data associated to the given label.
@@ -458,10 +437,7 @@ class InputRecord
458437
/// @return the total number of inputs in the InputRecord. Notice that these will include
459438
/// both valid and invalid inputs (i.e. inputs which have not arrived yet), depending
460439
/// on the CompletionPolicy you have (using the default policy all inputs will be valid).
461-
size_t size() const
462-
{
463-
return mSpan.size();
464-
}
440+
size_t size() const;
465441

466442
/// @return the total number of valid inputs in the InputRecord.
467443
/// Invalid inputs might happen if the CompletionPolicy allows
@@ -649,7 +625,7 @@ class InputRecord
649625

650626
private:
651627
std::vector<InputRoute> const& mInputsSchema;
652-
InputSpan mSpan;
628+
InputSpan& mSpan;
653629
};
654630

655631
} // namespace framework

Framework/Core/include/Framework/InputSpan.h

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@
1313
#include "Framework/DataRef.h"
1414
#include <functional>
1515

16-
namespace o2
17-
{
18-
namespace framework
16+
extern template class std::function<o2::framework::DataRef(size_t)>;
17+
extern template class std::function<o2::framework::DataRef(size_t, size_t)>;
18+
19+
namespace o2::framework
1920
{
2021

2122
/// Mapping helper between the store of all inputs being processed and the
@@ -33,30 +34,18 @@ class InputSpan
3334
/// @a getter is the mapping between an element of the span referred by
3435
/// index and the buffer associated.
3536
/// @a size is the number of elements in the span.
36-
InputSpan(std::function<DataRef(size_t)> getter, size_t size)
37-
: mGetter{}, mNofPartsGetter{}, mSize{size}
38-
{
39-
mGetter = [getter](size_t index, size_t) -> DataRef {
40-
return getter(index);
41-
};
42-
}
37+
InputSpan(std::function<DataRef(size_t)> getter, size_t size);
4338

4439
/// @a getter is the mapping between an element of the span referred by
4540
/// index and the buffer associated.
4641
/// @a size is the number of elements in the span.
47-
InputSpan(std::function<DataRef(size_t, size_t)> getter, size_t size)
48-
: mGetter{getter}, mNofPartsGetter{}, mSize{size}
49-
{
50-
}
42+
InputSpan(std::function<DataRef(size_t, size_t)> getter, size_t size);
5143

5244
/// @a getter is the mapping between an element of the span referred by
5345
/// index and the buffer associated.
5446
/// @nofPartsGetter is the getter for the number of parts associated with an index
5547
/// @a size is the number of elements in the span.
56-
InputSpan(std::function<DataRef(size_t, size_t)> getter, std::function<size_t(size_t)> nofPartsGetter, size_t size)
57-
: mGetter{getter}, mNofPartsGetter{nofPartsGetter}, mSize{size}
58-
{
59-
}
48+
InputSpan(std::function<DataRef(size_t, size_t)> getter, std::function<size_t(size_t)> nofPartsGetter, size_t size);
6049

6150
/// @a i-th element of the InputSpan
6251
DataRef get(size_t i, size_t partidx = 0) const
@@ -250,7 +239,6 @@ class InputSpan
250239
size_t mSize;
251240
};
252241

253-
} // namespace framework
254-
} // namespace o2
242+
} // namespace o2::framework
255243

256244
#endif // FRAMEWORK_INPUTSSPAN_H

Framework/Core/src/CompletionPolicyHelpers.cxx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include "Framework/CompletionPolicyHelpers.h"
1212
#include "Framework/CompletionPolicy.h"
13+
#include "Framework/InputSpan.h"
1314
#include "Framework/DeviceSpec.h"
1415
#include "Framework/CompilerBuiltins.h"
1516
#include "Framework/Logger.h"
@@ -30,7 +31,7 @@ CompletionPolicy CompletionPolicyHelpers::defineByNameOrigin(std::string const&
3031

3132
auto originReceived = std::make_shared<std::vector<uint64_t>>();
3233

33-
auto callback = [originReceived, origin, op](CompletionPolicy::InputSet inputRefs) -> CompletionPolicy::CompletionOp {
34+
auto callback = [originReceived, origin, op](InputSpan const& inputRefs) -> CompletionPolicy::CompletionOp {
3435
// update list of the start times of inputs with origin @origin
3536
for (auto& ref : inputRefs) {
3637
if (ref.header != nullptr) {
@@ -72,7 +73,7 @@ CompletionPolicy CompletionPolicyHelpers::defineByName(std::string const& name,
7273
auto matcher = [name](DeviceSpec const& device) -> bool {
7374
return std::regex_match(device.name.begin(), device.name.end(), std::regex(name));
7475
};
75-
auto callback = [op](CompletionPolicy::InputSet) -> CompletionPolicy::CompletionOp {
76+
auto callback = [op](InputSpan const&) -> CompletionPolicy::CompletionOp {
7677
return op;
7778
};
7879
switch (op) {
@@ -94,7 +95,7 @@ CompletionPolicy CompletionPolicyHelpers::defineByName(std::string const& name,
9495

9596
CompletionPolicy CompletionPolicyHelpers::consumeWhenAll(const char* name, CompletionPolicy::Matcher matcher)
9697
{
97-
auto callback = [](CompletionPolicy::InputSet inputs) -> CompletionPolicy::CompletionOp {
98+
auto callback = [](InputSpan const& inputs) -> CompletionPolicy::CompletionOp {
9899
for (auto& input : inputs) {
99100
if (input.header == nullptr) {
100101
return CompletionPolicy::CompletionOp::Wait;
@@ -107,7 +108,7 @@ CompletionPolicy CompletionPolicyHelpers::consumeWhenAll(const char* name, Compl
107108

108109
CompletionPolicy CompletionPolicyHelpers::consumeWhenAny(const char* name, CompletionPolicy::Matcher matcher)
109110
{
110-
auto callback = [](CompletionPolicy::InputSet inputs) -> CompletionPolicy::CompletionOp {
111+
auto callback = [](InputSpan const& inputs) -> CompletionPolicy::CompletionOp {
111112
for (auto& input : inputs) {
112113
if (input.header != nullptr) {
113114
return CompletionPolicy::CompletionOp::Consume;
@@ -120,7 +121,7 @@ CompletionPolicy CompletionPolicyHelpers::consumeWhenAny(const char* name, Compl
120121

121122
CompletionPolicy CompletionPolicyHelpers::processWhenAny(const char* name, CompletionPolicy::Matcher matcher)
122123
{
123-
auto callback = [](CompletionPolicy::InputSet inputs) -> CompletionPolicy::CompletionOp {
124+
auto callback = [](InputSpan const& inputs) -> CompletionPolicy::CompletionOp {
124125
size_t present = 0;
125126
for (auto& input : inputs) {
126127
if (input.header != nullptr) {

Framework/Core/src/DataProcessingDevice.cxx

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "Framework/CallbackService.h"
3131
#include "Framework/TMessageSerializer.h"
3232
#include "Framework/InputRecord.h"
33+
#include "Framework/InputSpan.h"
3334
#include "Framework/Signpost.h"
3435
#include "Framework/SourceInfoHeader.h"
3536
#include "Framework/Logger.h"
@@ -934,12 +935,9 @@ bool DataProcessingDevice::tryDispatchComputation(DataProcessorContext& context,
934935
return completed;
935936
};
936937

937-
// This is needed to convert from a pair of pointers to an actual DataRef
938-
// and to make sure the ownership is moved from the cache in the relayer to
939-
// the execution.
940-
auto fillInputs = [&relayer = context.relayer,
941-
&spec = context.deviceContext->spec,
942-
&currentSetOfInputs](TimesliceSlot slot) -> InputRecord {
938+
//
939+
auto getInputSpan = [&relayer = context.relayer,
940+
&currentSetOfInputs](TimesliceSlot slot) {
943941
currentSetOfInputs = std::move(relayer->getInputsForTimeslice(slot));
944942
auto getter = [&currentSetOfInputs](size_t i, size_t partindex) -> DataRef {
945943
if (currentSetOfInputs[i].size() > partindex) {
@@ -952,8 +950,7 @@ bool DataProcessingDevice::tryDispatchComputation(DataProcessorContext& context,
952950
auto nofPartsGetter = [&currentSetOfInputs](size_t i) -> size_t {
953951
return currentSetOfInputs[i].size();
954952
};
955-
InputSpan span{getter, nofPartsGetter, currentSetOfInputs.size()};
956-
return InputRecord{spec->inputs, std::move(span)};
953+
return InputSpan{getter, nofPartsGetter, currentSetOfInputs.size()};
957954
};
958955

959956
auto markInputsAsDone = [&relayer = context.relayer](TimesliceSlot slot) -> void {
@@ -1135,7 +1132,8 @@ bool DataProcessingDevice::tryDispatchComputation(DataProcessorContext& context,
11351132
}
11361133

11371134
prepareAllocatorForCurrentTimeSlice(TimesliceSlot{action.slot});
1138-
InputRecord record = fillInputs(action.slot);
1135+
InputSpan span = getInputSpan(action.slot);
1136+
InputRecord record{context.deviceContext->spec->inputs, span};
11391137
ProcessingContext processContext{record, *context.registry, *context.allocator};
11401138
{
11411139
ZoneScopedN("service pre processing");

Framework/Core/src/DataRelayer.cxx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "Framework/DataProcessingHeader.h"
1616
#include "Framework/DataRef.h"
1717
#include "Framework/InputRecord.h"
18+
#include "Framework/InputSpan.h"
1819
#include "Framework/CompletionPolicy.h"
1920
#include "Framework/Logger.h"
2021
#include "Framework/PartRef.h"
@@ -474,7 +475,8 @@ void DataRelayer::getReadyToProcess(std::vector<DataRelayer::RecordAction>& comp
474475
auto nPartsGetter = [&partial](size_t idx) {
475476
return partial[idx].size();
476477
};
477-
auto action = mCompletionPolicy.callback({getter, nPartsGetter, static_cast<size_t>(partial.size())});
478+
InputSpan span{getter, nPartsGetter, static_cast<size_t>(partial.size())};
479+
auto action = mCompletionPolicy.callback(span);
478480
switch (action) {
479481
case CompletionPolicy::CompletionOp::Consume:
480482
case CompletionPolicy::CompletionOp::Process:

0 commit comments

Comments
 (0)