Skip to content

Commit f5bd904

Browse files
authored
Merge pull request cms-sw#36699 from makortel/useAccelerators_v2
Add a generic mechanism to specify compute accelerators to use in the configuration
2 parents 084abba + e0d39f3 commit f5bd904

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+976
-107
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import FWCore.ParameterSet.Config as cms
2+
3+
# This fragment is intended to collect all ProcessAccelerator objects
4+
# used in production
5+
6+
from HeterogeneousCore.CUDACore.ProcessAcceleratorCUDA_cfi import ProcessAcceleratorCUDA

Configuration/StandardSequences/python/Services_cff.py

+5-6
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,14 @@
88
# DQM store service
99
from DQMServices.Core.DQMStore_cfi import *
1010

11-
# load CUDA services when the "gpu" or "pixelNtupletFit" modifiers are enabled
12-
def _addCUDAServices(process):
13-
process.load("HeterogeneousCore.CUDAServices.CUDAService_cfi")
14-
process.load("FWCore.MessageService.MessageLogger_cfi")
15-
process.MessageLogger.CUDAService = cms.untracked.PSet()
11+
# load ProcessAccelerators (that set the e.g. the necessary CUDA
12+
# stuff) when the "gpu" or "pixelNtupletFit" modifiers are enabled
13+
def _addProcessAccelerators(process):
14+
process.load("Configuration.StandardSequences.Accelerators_cff")
1615

1716
from Configuration.ProcessModifiers.gpu_cff import gpu
1817
from Configuration.ProcessModifiers.pixelNtupletFit_cff import pixelNtupletFit
19-
modifyConfigurationStandardSequencesServicesAddCUDAServices_ = (gpu | pixelNtupletFit).makeProcessModifier(_addCUDAServices)
18+
modifyConfigurationStandardSequencesServicesAddProcessAccelerators_ = (gpu | pixelNtupletFit).makeProcessModifier(_addProcessAccelerators)
2019

2120
# load TritonService when SONIC workflow is enabled
2221
def _addTritonService(process):
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#include "FWCore/ParameterSet/interface/ParameterSet.h"
2+
3+
namespace edm {
4+
void ensureAvailableAccelerators(edm::ParameterSet const& parameterSet);
5+
}

FWCore/Framework/src/EventProcessor.cc

+2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "FWCore/Framework/interface/SharedResourcesRegistry.h"
3838
#include "FWCore/Framework/interface/streamTransitionAsync.h"
3939
#include "FWCore/Framework/interface/TransitionInfoTypes.h"
40+
#include "FWCore/Framework/interface/ensureAvailableAccelerators.h"
4041
#include "FWCore/Framework/interface/globalTransitionAsync.h"
4142

4243
#include "FWCore/MessageLogger/interface/MessageLogger.h"
@@ -372,6 +373,7 @@ namespace edm {
372373
fileModeNoMerge_ = (fileMode == "NOMERGE");
373374
}
374375
forceESCacheClearOnNewRun_ = optionsPset.getUntrackedParameter<bool>("forceEventSetupCacheClearOnNewRun");
376+
ensureAvailableAccelerators(*parameterSet);
375377

376378
//threading
377379
unsigned int nThreads = optionsPset.getUntrackedParameter<unsigned int>("numberOfThreads");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#include "FWCore/Framework/interface/ensureAvailableAccelerators.h"
2+
#include "FWCore/Utilities/interface/EDMException.h"
3+
4+
#include <algorithm>
5+
#include <vector>
6+
7+
namespace edm {
8+
void ensureAvailableAccelerators(edm::ParameterSet const& parameterSet) {
9+
auto const& selectedAccelerators =
10+
parameterSet.getUntrackedParameter<std::vector<std::string>>("@selected_accelerators");
11+
ParameterSet const& optionsPset(parameterSet.getUntrackedParameterSet("options"));
12+
if (selectedAccelerators.empty()) {
13+
Exception ex(errors::UnavailableAccelerator);
14+
ex << "The system has no compute accelerators that match the patterns specified in "
15+
"process.options.accelerators:\n";
16+
auto const& patterns = optionsPset.getUntrackedParameter<std::vector<std::string>>("accelerators");
17+
for (auto const& pat : patterns) {
18+
ex << " " << pat << "\n";
19+
}
20+
ex << "\nThe following compute accelerators are available:\n";
21+
auto const& availableAccelerators =
22+
parameterSet.getUntrackedParameter<std::vector<std::string>>("@available_accelerators");
23+
for (auto const& acc : availableAccelerators) {
24+
ex << " " << acc << "\n";
25+
}
26+
27+
throw ex;
28+
}
29+
}
30+
} // namespace edm

FWCore/Framework/test/test_module_delete_cfg.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,8 @@ class SwitchProducerTest(cms.SwitchProducer):
118118
def __init__(self, **kargs):
119119
super(SwitchProducerTest,self).__init__(
120120
dict(
121-
test1 = lambda: (True, -10),
122-
test2 = lambda: (True, -9)
121+
test1 = lambda accelerators: (True, -10),
122+
test2 = lambda accelerators: (True, -9)
123123
), **kargs)
124124
process.producerEventSwitchProducerNotConsumed = cms.EDProducer("edmtest::TestModuleDeleteProducer")
125125
process.producerEventSwitchProducerConsumed = intEventProducerMustRun.clone()

FWCore/Integration/test/BuildFile.xml

+12
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@
147147
<use name="FWCore/Utilities"/>
148148
</bin>
149149

150+
<test name="TestIntegrationProcessAccelerator" command="run_TestProcessAccelerator.sh"/>
151+
150152
<test name="CatchStdExceptiontest" command="CatchStdExceptiontest.sh"/>
151153

152154
<test name="CatchCmsExceptiontest" command="CatchCmsExceptiontest.sh"/>
@@ -177,6 +179,16 @@
177179
<use name="catch2"/>
178180
</bin>
179181

182+
<bin file="ProcessAccelerator_t.cpp">
183+
<use name="FWCore/Framework"/>
184+
<use name="FWCore/ParameterSet"/>
185+
<use name="FWCore/ParameterSetReader"/>
186+
<use name="FWCore/TestProcessor"/>
187+
<use name="DataFormats/Provenance"/>
188+
<use name="catch2"/>
189+
<use name="fmt"/>
190+
</bin>
191+
180192
<bin file="EDAlias_t.cpp">
181193
<use name="FWCore/Framework"/>
182194
<use name="FWCore/ParameterSet"/>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
#define CATCH_CONFIG_MAIN
2+
#include "catch.hpp"
3+
4+
#include "DataFormats/TestObjects/interface/ToyProducts.h"
5+
#include "FWCore/ParameterSet/interface/ParameterSet.h"
6+
#include "FWCore/ParameterSetReader/interface/ParameterSetReader.h"
7+
#include "FWCore/TestProcessor/interface/TestProcessor.h"
8+
9+
#include <fmt/format.h>
10+
11+
#include <iostream>
12+
#include <string_view>
13+
14+
static constexpr auto s_tag = "[ProcessAccelerator]";
15+
16+
namespace {
17+
std::string makeConfig(bool test2Enabled,
18+
std::string_view test1,
19+
std::string_view test2,
20+
std::string_view accelerator) {
21+
const std::string appendTest2 = test2Enabled ? "self._enabled.append('test2')" : "";
22+
return fmt::format(
23+
R"_(from FWCore.TestProcessor.TestProcess import *
24+
import FWCore.ParameterSet.Config as cms
25+
26+
class ProcessAcceleratorTest(cms.ProcessAccelerator):
27+
def __init__(self):
28+
super(ProcessAcceleratorTest,self).__init__()
29+
self._labels = ["test1", "test2"]
30+
self._enabled = ["test1"]
31+
{}
32+
def labels(self):
33+
return self._labels
34+
def enabledLabels(self):
35+
return self._enabled
36+
37+
class SwitchProducerTest(cms.SwitchProducer):
38+
def __init__(self, **kargs):
39+
super(SwitchProducerTest,self).__init__(
40+
dict(
41+
cpu = cms.SwitchProducer.getCpu(),
42+
test1 = lambda accelerators: ("test1" in accelerators, 2),
43+
test2 = lambda accelerators: ("test2" in accelerators, 3),
44+
), **kargs)
45+
46+
process = TestProcess()
47+
process.options.accelerators = ["{}"]
48+
process.ProcessAcceleratorTest = ProcessAcceleratorTest()
49+
process.s = SwitchProducerTest(
50+
cpu = cms.EDProducer('IntProducer', ivalue = cms.int32(0)),
51+
test1 = {},
52+
test2 = {}
53+
)
54+
process.moduleToTest(process.s)
55+
)_",
56+
appendTest2,
57+
accelerator,
58+
test1,
59+
test2);
60+
}
61+
} // namespace
62+
63+
TEST_CASE("Configuration", s_tag) {
64+
const std::string test1{"cms.EDProducer('IntProducer', ivalue = cms.int32(1))"};
65+
const std::string test2{"cms.EDProducer('ManyIntProducer', ivalue = cms.int32(2), values = cms.VPSet())"};
66+
67+
const std::string baseConfig_auto = makeConfig(true, test1, test2, "*");
68+
const std::string baseConfig_test1 = makeConfig(true, test1, test2, "test1");
69+
const std::string baseConfig_test2 = makeConfig(true, test1, test2, "test2");
70+
const std::string baseConfigTest2Disabled_auto = makeConfig(false, test1, test2, "*");
71+
const std::string baseConfigTest2Disabled_test1 = makeConfig(false, test1, test2, "test1");
72+
const std::string baseConfigTest2Disabled_test2 = makeConfig(false, test1, test2, "test2");
73+
74+
SECTION("Configuration hash is not changed") {
75+
auto pset_auto = edm::readConfig(baseConfig_auto);
76+
auto pset_test1 = edm::readConfig(baseConfig_test1);
77+
auto pset_test2 = edm::readConfig(baseConfig_test2);
78+
auto psetTest2Disabled_auto = edm::readConfig(baseConfigTest2Disabled_auto);
79+
auto psetTest2Disabled_test1 = edm::readConfig(baseConfigTest2Disabled_test1);
80+
auto psetTest2Disabled_test2 = edm::readConfig(baseConfigTest2Disabled_test2);
81+
pset_auto->registerIt();
82+
pset_test1->registerIt();
83+
pset_test2->registerIt();
84+
psetTest2Disabled_auto->registerIt();
85+
psetTest2Disabled_test1->registerIt();
86+
psetTest2Disabled_test2->registerIt();
87+
REQUIRE(pset_auto->id() == pset_test1->id());
88+
REQUIRE(pset_auto->id() == pset_test2->id());
89+
REQUIRE(pset_auto->id() == psetTest2Disabled_auto->id());
90+
REQUIRE(pset_auto->id() == psetTest2Disabled_test1->id());
91+
REQUIRE(pset_auto->id() == psetTest2Disabled_test2->id());
92+
}
93+
94+
edm::test::TestProcessor::Config config_auto{baseConfig_auto};
95+
edm::test::TestProcessor::Config config_test1{baseConfig_test1};
96+
edm::test::TestProcessor::Config config_test2{baseConfig_test2};
97+
edm::test::TestProcessor::Config configTest2Disabled_auto{baseConfigTest2Disabled_auto};
98+
edm::test::TestProcessor::Config configTest2Disabled_test1{baseConfigTest2Disabled_test1};
99+
edm::test::TestProcessor::Config configTest2Disabled_test2{baseConfigTest2Disabled_test2};
100+
101+
SECTION("Base configuration is OK") { REQUIRE_NOTHROW(edm::test::TestProcessor(config_auto)); }
102+
103+
SECTION("No event data") {
104+
edm::test::TestProcessor tester(config_auto);
105+
REQUIRE_NOTHROW(tester.test());
106+
}
107+
108+
SECTION("beginJob and endJob only") {
109+
edm::test::TestProcessor tester(config_auto);
110+
REQUIRE_NOTHROW(tester.testBeginAndEndJobOnly());
111+
}
112+
113+
SECTION("Run with no LuminosityBlocks") {
114+
edm::test::TestProcessor tester(config_auto);
115+
REQUIRE_NOTHROW(tester.testRunWithNoLuminosityBlocks());
116+
}
117+
118+
SECTION("LuminosityBlock with no Events") {
119+
edm::test::TestProcessor tester(config_auto);
120+
REQUIRE_NOTHROW(tester.testLuminosityBlockWithNoEvents());
121+
}
122+
123+
SECTION("Test2 enabled, acclerators=*") {
124+
edm::test::TestProcessor tester(config_auto);
125+
auto event = tester.test();
126+
REQUIRE(event.get<edmtest::IntProduct>()->value == 2);
127+
}
128+
129+
SECTION("Test2 enabled, acclerators=test1") {
130+
edm::test::TestProcessor tester(config_test1);
131+
auto event = tester.test();
132+
REQUIRE(event.get<edmtest::IntProduct>()->value == 1);
133+
}
134+
135+
SECTION("Test2 enabled, acclerators=test2") {
136+
edm::test::TestProcessor tester(config_test2);
137+
auto event = tester.test();
138+
REQUIRE(event.get<edmtest::IntProduct>()->value == 2);
139+
}
140+
141+
SECTION("Test2 disabled, accelerators=*") {
142+
edm::test::TestProcessor tester(configTest2Disabled_auto);
143+
auto event = tester.test();
144+
REQUIRE(event.get<edmtest::IntProduct>()->value == 1);
145+
}
146+
147+
SECTION("Test2 disabled, accelerators=test1") {
148+
edm::test::TestProcessor tester(configTest2Disabled_test1);
149+
auto event = tester.test();
150+
REQUIRE(event.get<edmtest::IntProduct>()->value == 1);
151+
}
152+
153+
SECTION("Test2 disabled, accelerators=test2") {
154+
REQUIRE_THROWS_WITH(
155+
edm::test::TestProcessor(configTest2Disabled_test2),
156+
Catch::Contains("The system has no compute accelerators that match the patterns") && Catch::Contains("test1"));
157+
}
158+
}

FWCore/Integration/test/SwitchProducer_t.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ class SwitchProducerTest(cms.SwitchProducer):
3131
def __init__(self, **kargs):
3232
super(SwitchProducerTest,self).__init__(
3333
dict(
34-
test1 = lambda: (True, -10),
35-
test2 = lambda: ()_"} +
34+
test1 = lambda accelerators: (True, -10),
35+
test2 = lambda accelerators: ()_"} +
3636
(test2Enabled ? "True" : "False") + ", -9)\n" +
3737
R"_( ), **kargs)
3838
process = TestProcess()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#!/bin/bash
2+
3+
test=testProcessAccelerator
4+
LOCAL_TEST_DIR=${CMSSW_BASE}/src/FWCore/Integration/test
5+
LOCAL_TMP_DIR=${CMSSW_BASE}/tmp/${SCRAM_ARCH}
6+
7+
function die { echo Failure $1: status $2 ; exit $2 ; }
8+
9+
pushd ${LOCAL_TMP_DIR}
10+
11+
echo "*************************************************"
12+
echo "accelerators=*"
13+
cmsRun ${LOCAL_TEST_DIR}/${test}_cfg.py || die "cmsRun ${test}_cfg.py" $?
14+
15+
echo "*************************************************"
16+
echo "accelerators=*, enableTest2"
17+
cmsRun ${LOCAL_TEST_DIR}/${test}_cfg.py -- --enableTest2 || die "cmsRun ${test}_cfg.py -- --enableTest2" $?
18+
19+
echo "*************************************************"
20+
echo "accelerators=test1"
21+
cmsRun ${LOCAL_TEST_DIR}/${test}_cfg.py -- --accelerators=test1 || die "cmsRun ${test}_cfg.py -- --accelerators=test1" $?
22+
23+
echo "*************************************************"
24+
echo "accelerators=test2"
25+
cmsRun -j testProcessAccelerators_jobreport.xml ${LOCAL_TEST_DIR}/${test}_cfg.py -- --accelerators=test2 && die "cmsRun ${test}_cfg.py -- --accelerators=test2 did not fail" 1
26+
EXIT_CODE=$(edmFjrDump --exitCode testProcessAccelerators_jobreport.xml)
27+
if [ "x${EXIT_CODE}" != "x8035" ]; then
28+
echo "ProcessAccelerator test for unavailable accelerator reported exit code ${EXIT_CODE} which is different from the expected 8035"
29+
exit 1
30+
fi
31+
32+
echo "*************************************************"
33+
echo "accelerators=test1, enableTest2"
34+
cmsRun ${LOCAL_TEST_DIR}/${test}_cfg.py -- --accelerators=test1 --enableTest2 || die "cmsRun ${test}_cfg.py -- --accelerators=test1 --enableTest2" $?
35+
36+
echo "*************************************************"
37+
echo "accelerators=test2, enableTest2"
38+
cmsRun ${LOCAL_TEST_DIR}/${test}_cfg.py -- --accelerators=test2 --enableTest2 || die "cmsRun ${test}_cfg.py -- --accelerators=test2 --enableTest2" $?
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import FWCore.ParameterSet.Config as cms
2+
3+
import argparse
4+
import sys
5+
6+
parser = argparse.ArgumentParser(prog=sys.argv[0], description='Test ProcessAccelerator.')
7+
8+
parser.add_argument("--enableTest2", help="Enable test2 accelerator", action="store_true")
9+
parser.add_argument("--accelerators", type=str, help="Comma-separated string for accelerators to enable")
10+
11+
argv = sys.argv[:]
12+
if '--' in argv:
13+
argv.remove("--")
14+
args, unknown = parser.parse_known_args(argv)
15+
16+
class ProcessAcceleratorTest(cms.ProcessAccelerator):
17+
def __init__(self):
18+
super(ProcessAcceleratorTest,self).__init__()
19+
self._labels = ["test1", "test2"]
20+
self._enabled = ["test1"]
21+
if args.enableTest2:
22+
self._enabled.append("test2")
23+
def labels(self):
24+
return self._labels
25+
def enabledLabels(self):
26+
return self._enabled
27+
28+
class SwitchProducerTest(cms.SwitchProducer):
29+
def __init__(self, **kargs):
30+
super(SwitchProducerTest,self).__init__(
31+
dict(
32+
cpu = cms.SwitchProducer.getCpu(),
33+
test1 = lambda accelerators: ("test1" in accelerators, 2),
34+
test2 = lambda accelerators: ("test2" in accelerators, 3),
35+
), **kargs)
36+
37+
process = cms.Process("PROD1")
38+
39+
process.add_(ProcessAcceleratorTest())
40+
41+
process.source = cms.Source("EmptySource")
42+
process.maxEvents.input = 3
43+
if args.accelerators is not None:
44+
process.options.accelerators = args.accelerators.split(",")
45+
46+
process.intProducer1 = cms.EDProducer("ManyIntProducer", ivalue = cms.int32(1))
47+
process.intProducer2 = cms.EDProducer("ManyIntProducer", ivalue = cms.int32(2))
48+
process.failIntProducer = cms.EDProducer("ManyIntProducer", ivalue = cms.int32(-1), throw = cms.untracked.bool(True))
49+
50+
if args.enableTest2 and ("test2" in process.options.accelerators or "*" in process.options.accelerators):
51+
process.intProducer1.throw = cms.untracked.bool(True)
52+
else:
53+
process.intProducer2.throw = cms.untracked.bool(True)
54+
55+
process.intProducer = SwitchProducerTest(
56+
cpu = cms.EDProducer("AddIntsProducer", labels = cms.VInputTag("failIntProducer")),
57+
test1 = cms.EDProducer("AddIntsProducer", labels = cms.VInputTag("intProducer1")),
58+
test2 = cms.EDProducer("AddIntsProducer", labels = cms.VInputTag("intProducer2"))
59+
)
60+
61+
process.intConsumer = cms.EDProducer("AddIntsProducer", labels = cms.VInputTag("intProducer"))
62+
63+
process.t = cms.Task(
64+
process.failIntProducer,
65+
process.intProducer1,
66+
process.intProducer2,
67+
process.intProducer,
68+
)
69+
process.p = cms.Path(
70+
process.intConsumer,
71+
process.t
72+
)

0 commit comments

Comments
 (0)