Skip to content

Commit

Permalink
Throw a specific, UnavailableAccelerator, exception if requested acce…
Browse files Browse the repository at this point in the history
…lerator is not available
  • Loading branch information
makortel committed Jan 10, 2022
1 parent 6a7e1a2 commit b705376
Show file tree
Hide file tree
Showing 11 changed files with 223 additions and 6 deletions.
5 changes: 5 additions & 0 deletions FWCore/Framework/interface/ensureAvailableAccelerators.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#include "FWCore/ParameterSet/interface/ParameterSet.h"

namespace edm {
void ensureAvailableAccelerators(edm::ParameterSet const& parameterSet);
}
2 changes: 2 additions & 0 deletions FWCore/Framework/src/EventProcessor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "FWCore/Framework/interface/SharedResourcesRegistry.h"
#include "FWCore/Framework/interface/streamTransitionAsync.h"
#include "FWCore/Framework/interface/TransitionInfoTypes.h"
#include "FWCore/Framework/interface/ensureAvailableAccelerators.h"
#include "FWCore/Framework/interface/globalTransitionAsync.h"

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

//threading
unsigned int nThreads = optionsPset.getUntrackedParameter<unsigned int>("numberOfThreads");
Expand Down
35 changes: 35 additions & 0 deletions FWCore/Framework/src/ensureAvailableAccelerators.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include "FWCore/Framework/interface/ensureAvailableAccelerators.h"
#include "FWCore/Utilities/interface/EDMException.h"

#include <algorithm>
#include <vector>

namespace edm {
void ensureAvailableAccelerators(edm::ParameterSet const& parameterSet) {
ParameterSet const& optionsPset(parameterSet.getUntrackedParameterSet("options"));
auto accelerators = optionsPset.getUntrackedParameter<std::vector<std::string>>("accelerators");
if (not accelerators.empty()) {
auto const& availableAccelerators = parameterSet.getUntrackedParameter<std::vector<std::string>>("@available_accelerators");
std::sort(accelerators.begin(), accelerators.end());
std::vector<std::string> unavailableAccelerators;
std::set_difference(accelerators.begin(), accelerators.end(),
availableAccelerators.begin(), availableAccelerators.end(),
std::back_inserter(unavailableAccelerators));
if (not unavailableAccelerators.empty()) {
Exception ex(errors::UnavailableAccelerator);
ex << "Compute accelerators ";
bool first = true;
for (auto const& acc : unavailableAccelerators) {
if (not first) {
ex << ", ";
} else {
first = true;
}
ex << acc;
}
ex << " were requested but are not available in this system.";
throw ex;
}
}
}
}
2 changes: 2 additions & 0 deletions FWCore/Integration/test/BuildFile.xml
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@
<use name="FWCore/Utilities"/>
</bin>

<test name="TestIntegrationProcessAccelerator" command="run_TestProcessAccelerator.sh"/>

<test name="CatchStdExceptiontest" command="CatchStdExceptiontest.sh"/>

<test name="CatchCmsExceptiontest" command="CatchCmsExceptiontest.sh"/>
Expand Down
35 changes: 35 additions & 0 deletions FWCore/Integration/test/ProcessAccelerator_t.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,39 @@ TEST_CASE("Configuration", s_tag) {
edm::test::TestProcessor tester(config_auto);
REQUIRE_NOTHROW(tester.testLuminosityBlockWithNoEvents());
}

SECTION("Test2 enabled, acclerators=auto") {
edm::test::TestProcessor tester(config_auto);
auto event = tester.test();
REQUIRE(event.get<edmtest::IntProduct>()->value == 2);
}

SECTION("Test2 enabled, acclerators=test1") {
edm::test::TestProcessor tester(config_test1);
auto event = tester.test();
REQUIRE(event.get<edmtest::IntProduct>()->value == 1);
}

SECTION("Test2 enabled, acclerators=test2") {
edm::test::TestProcessor tester(config_test2);
auto event = tester.test();
REQUIRE(event.get<edmtest::IntProduct>()->value == 2);
}

SECTION("Test2 disabled, accelerators=auto") {
edm::test::TestProcessor tester(configTest2Disabled_auto);
auto event = tester.test();
REQUIRE(event.get<edmtest::IntProduct>()->value == 1);
}

SECTION("Test2 disabled, accelerators=test1") {
edm::test::TestProcessor tester(configTest2Disabled_test1);
auto event = tester.test();
REQUIRE(event.get<edmtest::IntProduct>()->value == 1);
}

SECTION("Test2 disabled, accelerators=test2") {
REQUIRE_THROWS_WITH(edm::test::TestProcessor(configTest2Disabled_test2),
Catch::Contains("Compute accelerators test2 were requested but are not available"));
}
}
38 changes: 38 additions & 0 deletions FWCore/Integration/test/run_TestProcessAccelerator.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/bin/bash

test=testProcessAccelerator
LOCAL_TEST_DIR=${CMSSW_BASE}/src/FWCore/Integration/test
LOCAL_TMP_DIR=${CMSSW_BASE}/tmp/${SCRAM_ARCH}

function die { echo Failure $1: status $2 ; exit $2 ; }

pushd ${LOCAL_TMP_DIR}

echo "*************************************************"
echo "accelerators=auto"
cmsRun ${LOCAL_TEST_DIR}/${test}_cfg.py || die "cmsRun ${test}_cfg.py" $?

echo "*************************************************"
echo "accelerators=auto, enableTest2"
cmsRun ${LOCAL_TEST_DIR}/${test}_cfg.py || die "cmsRun ${test}_cfg.py" $?

echo "*************************************************"
echo "accelerators=test1"
cmsRun ${LOCAL_TEST_DIR}/${test}_cfg.py -- --accelerators=test1 || die "cmsRun ${test}_cfg.py -- --accelerators=test1" $?

echo "*************************************************"
echo "accelerators=test2"
cmsRun -j testProcessAccelerators_jobreport.xml ${LOCAL_TEST_DIR}/${test}_cfg.py -- --accelerators=test2 && die "cmsRun ${test}_cfg.py -- --accelerators=test2 did not fail" 1
EXIT_CODE=$(edmFjrDump --exitCode testProcessAccelerators_jobreport.xml)
if [ "x${EXIT_CODE}" != "x8035" ]; then
echo "ProcessAccelerator test for unavailable accelerator reported exit code ${EXIT_CODE} which is different from the expected 8035"
exit 1
fi

echo "*************************************************"
echo "accelerators=test1, enableTest2"
cmsRun ${LOCAL_TEST_DIR}/${test}_cfg.py -- --accelerators=test1 --enableTest2 || die "cmsRun ${test}_cfg.py -- --accelerators=test1 --enableTest2" $?

echo "*************************************************"
echo "accelerators=test2, enableTest2"
cmsRun ${LOCAL_TEST_DIR}/${test}_cfg.py -- --accelerators=test2 --enableTest2 || die "cmsRun ${test}_cfg.py -- --accelerators=test2 --enableTest2" $?
70 changes: 70 additions & 0 deletions FWCore/Integration/test/testProcessAccelerator_cfg.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import FWCore.ParameterSet.Config as cms

import argparse
import sys

parser = argparse.ArgumentParser(prog=sys.argv[0], description='Test ProcessAccelerator.')

parser.add_argument("--enableTest2", help="Enable test2 accelerator", action="store_true")
parser.add_argument("--accelerators", type=str, help="Comma-separated string for accelerators to enable")

argv = sys.argv[:]
if '--' in argv:
argv.remove("--")
args, unknown = parser.parse_known_args(argv)
if args.accelerators is not None:
args.accelerators = args.accelerators.split(",")

class ProcessAcceleratorTest(cms.ProcessAccelerator):
def __init__(self):
super(ProcessAcceleratorTest,self).__init__()
self._labels = ["test1", "test2"]
self._enabled = ["test1"]
if args.enableTest2:
self._enabled.append("test2")
def labels(self):
return self._labels
def enabledLabels(self):
return self._enabled

class SwitchProducerTest(cms.SwitchProducer):
def __init__(self, **kargs):
super(SwitchProducerTest,self).__init__(
dict(
test1 = lambda accelerators: ("test1" in accelerators, -10),
test2 = lambda accelerators: ("test2" in accelerators, -9),
), **kargs)

process = cms.Process("PROD1")

process.add_(ProcessAcceleratorTest())

process.source = cms.Source("EmptySource")
process.maxEvents.input = 3
if args.accelerators is not None:
process.options.accelerators = args.accelerators

process.intProducer1 = cms.EDProducer("ManyIntProducer", ivalue = cms.int32(1))
process.intProducer2 = cms.EDProducer("ManyIntProducer", ivalue = cms.int32(2))

if args.enableTest2 and ("test2" in args.accelerators or "auto" in args.accelerators):
process.intProducer1.throw = cms.untracked.bool(True)
else:
process.intProducer2.throw = cms.untracked.bool(True)

process.intProducer = SwitchProducerTest(
test1 = cms.EDProducer("AddIntsProducer", labels = cms.VInputTag("intProducer1")),
test2 = cms.EDProducer("AddIntsProducer", labels = cms.VInputTag("intProducer2"))
)

process.intConsumer = cms.EDProducer("AddIntsProducer", labels = cms.VInputTag("intProducer"))

process.t = cms.Task(
process.intProducer1,
process.intProducer2,
process.intProducer
)
process.p = cms.Path(
process.intConsumer,
process.t
)
36 changes: 30 additions & 6 deletions FWCore/ParameterSet/python/Config.py
Original file line number Diff line number Diff line change
Expand Up @@ -1388,8 +1388,8 @@ def __extractPSet(self,pset):
return pset

self.validate()
self.handleProcessAccelerators()
processPSet.addString(True, "@process_name", self.name_())
self.handleProcessAccelerators(processPSet)
all_modules = self.producers_().copy()
all_modules.update(self.filters_())
all_modules.update(self.analyzers_())
Expand Down Expand Up @@ -1442,7 +1442,7 @@ def validate(self):
# raise RuntimeError("No input source was found for this process")
pass

def handleProcessAccelerators(self):
def handleProcessAccelerators(self, parameterSet):
# Sanity check
useSet = set(self.options.accelerators.value())
accSet = set([label for acc in self.__dict__['_Process__accelerators'].values() for label in acc.labels()])
Expand All @@ -1455,15 +1455,19 @@ def handleProcessAccelerators(self):
invalid,
valid))

availableAccelerators = set()
for acc in self.__dict__['_Process__accelerators'].values():
for l in acc.enabledLabels():
availableAccelerators.add(l)
availableAccelerators = sorted(list(availableAccelerators))
parameterSet.addVString(False, "@available_accelerators", availableAccelerators)

# Resolve 'auto'
if "auto" in self.options.accelerators:
if len(self.options.accelerators) >= 2:
raise ValueError("process.options.accelerators may contain 'auto' only as the only element, now it has {} elements".format(len(self.options.accelerators)))
newValue = set()
for acc in self.__dict__['_Process__accelerators'].values():
for l in acc.enabledLabels():
newValue.add(l)
self.options.accelerators = list(newValue)
self.options.accelerators = list(availableAccelerators)

# Customize
for acc in self.__dict__['_Process__accelerators'].values():
Expand Down Expand Up @@ -4060,19 +4064,35 @@ def testProcessAccelerator(self):
self.assertTrue("test1" in accelerators)
self.assertTrue("test2" in accelerators)
self.assertEqual((True, "AcceleratorTestProducer"), p.values["acceleratorTestProducer"][1].values["@module_type"])
self.assertFalse(p.values["@available_accelerators"][0])
availableAccelerators = p.values["@available_accelerators"][1]
self.assertTrue("test1" in availableAccelerators)
self.assertTrue("test2" in availableAccelerators)

proc = Process("TEST")
proc.ProcessAcceleratorTest = ProcessAcceleratorTest(enabled=["test1"])
p = TestMakePSet()
proc.fillProcessDesc(p)
self.assertEqual(["test1"], p.values["options"][1].values["accelerators"][1])
self.assertEqual(["test1"], p.values["@available_accelerators"][1])

proc = Process("TEST")
proc.ProcessAcceleratorTest = ProcessAcceleratorTest()
proc.options.accelerators = ["test2"]
p = TestMakePSet()
proc.fillProcessDesc(p)
self.assertEqual(["test2"], p.values["options"][1].values["accelerators"][1])
availableAccelerators = p.values["@available_accelerators"][1]
self.assertTrue("test1" in availableAccelerators)
self.assertTrue("test2" in availableAccelerators)

proc = Process("TEST")
proc.ProcessAcceleratorTest = ProcessAcceleratorTest(enabled=["test1"])
proc.options.accelerators = ["test2"]
p = TestMakePSet()
proc.fillProcessDesc(p)
self.assertEqual(["test2"], p.values["options"][1].values["accelerators"][1])
self.assertEqual(["test1"], p.values["@available_accelerators"][1])

proc = Process("TEST")
proc.ProcessAcceleratorTest = ProcessAcceleratorTest()
Expand Down Expand Up @@ -4114,10 +4134,14 @@ def testProcessAccelerator(self):
p = TestMakePSet()
unpkl.fillProcessDesc(p)
self.assertEqual((False, "sp@test2"), p.values["sp"][1].values["@chosen_case"])
availableAccelerators = p.values["@available_accelerators"][1]
self.assertTrue("test1" in availableAccelerators)
self.assertTrue("test2" in availableAccelerators)
unpkl = pickle.loads(pkl)
unpkl.ProcessAcceleratorTest.setEnabled(["test1"])
p = TestMakePSet()
unpkl.fillProcessDesc(p)
self.assertEqual((False, "sp@test1"), p.values["sp"][1].values["@chosen_case"])
self.assertEqual(["test1"], p.values["@available_accelerators"][1])

unittest.main()
3 changes: 3 additions & 0 deletions FWCore/TestProcessor/src/TestProcessor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "FWCore/Framework/interface/TransitionInfoTypes.h"
#include "FWCore/Framework/interface/ProductPutterBase.h"
#include "FWCore/Framework/interface/DelayedReader.h"
#include "FWCore/Framework/interface/ensureAvailableAccelerators.h"

#include "FWCore/ServiceRegistry/interface/ServiceRegistry.h"
#include "FWCore/ServiceRegistry/interface/SystemBounds.h"
Expand Down Expand Up @@ -94,6 +95,8 @@ namespace edm {

validateTopLevelParameterSets(psetPtr.get());

ensureAvailableAccelerators(*psetPtr);

labelOfTestModule_ = psetPtr->getParameter<std::string>("@moduleToTest");

auto procDesc = desc.processDesc();
Expand Down
2 changes: 2 additions & 0 deletions FWCore/Utilities/interface/EDMException.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ namespace edm {

FileNameInconsistentWithGUID = 8034,

UnavailableAccelerator = 8035,

EventGenerationFailure = 8501,

CaughtSignal = 9000
Expand Down
1 change: 1 addition & 0 deletions FWCore/Utilities/src/EDMException.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ namespace edm {
FILLENTRY(ExceededResourceTime),
FILLENTRY(FileWriteError),
FILLENTRY(FileNameInconsistentWithGUID),
FILLENTRY(UnavailableAccelerator),
FILLENTRY(EventGenerationFailure),
FILLENTRY(CaughtSignal)};
static const std::string kUnknownCode("unknownCode");
Expand Down

0 comments on commit b705376

Please sign in to comment.