Skip to content

Commit

Permalink
Merge pull request #37563 from makortel/conditionalTaskSwitchProducer
Browse files Browse the repository at this point in the history
Make SwitchProducer work with ConditionalTask
  • Loading branch information
cmsbuild authored Apr 20, 2022
2 parents 06c3102 + ecdb11a commit 9554e9c
Show file tree
Hide file tree
Showing 13 changed files with 550 additions and 234 deletions.
201 changes: 5 additions & 196 deletions FWCore/Framework/src/Schedule.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
#include <sstream>

#include "make_shared_noexcept_false.h"
#include "processEDAliases.h"

namespace edm {

Expand Down Expand Up @@ -146,201 +147,6 @@ namespace edm {
}
}

void checkAndInsertAlias(std::string const& friendlyClassName,
std::string const& moduleLabel,
std::string const& productInstanceName,
std::string const& processName,
std::string const& alias,
std::string const& instanceAlias,
ProductRegistry const& preg,
std::multimap<BranchKey, BranchKey>& aliasMap,
std::map<BranchKey, BranchKey>& aliasKeys) {
std::string const star("*");

BranchKey key(friendlyClassName, moduleLabel, productInstanceName, processName);
if (preg.productList().find(key) == preg.productList().end()) {
// No product was found matching the alias.
// We throw an exception only if a module with the specified module label was created in this process.
for (auto const& product : preg.productList()) {
if (moduleLabel == product.first.moduleLabel() && processName == product.first.processName()) {
throw Exception(errors::Configuration, "EDAlias does not match data\n")
<< "There are no products of type '" << friendlyClassName << "'\n"
<< "with module label '" << moduleLabel << "' and instance name '" << productInstanceName << "'.\n";
}
}
}

if (auto iter = aliasMap.find(key); iter != aliasMap.end()) {
// If the same EDAlias defines multiple products pointing to the same product, throw
if (iter->second.moduleLabel() == alias) {
throw Exception(errors::Configuration, "EDAlias conflict\n")
<< "The module label alias '" << alias << "' is used for multiple products of type '" << friendlyClassName
<< "' with module label '" << moduleLabel << "' and instance name '" << productInstanceName
<< "'. One alias has the instance name '" << iter->first.productInstanceName()
<< "' and the other has the instance name '" << instanceAlias << "'.";
}
}

std::string const& theInstanceAlias(instanceAlias == star ? productInstanceName : instanceAlias);
BranchKey aliasKey(friendlyClassName, alias, theInstanceAlias, processName);
if (preg.productList().find(aliasKey) != preg.productList().end()) {
throw Exception(errors::Configuration, "EDAlias conflicts with data\n")
<< "A product of type '" << friendlyClassName << "'\n"
<< "with module label '" << alias << "' and instance name '" << theInstanceAlias << "'\n"
<< "already exists.\n";
}
auto iter = aliasKeys.find(aliasKey);
if (iter != aliasKeys.end()) {
// The alias matches a previous one. If the same alias is used for different product, throw.
if (iter->second != key) {
throw Exception(errors::Configuration, "EDAlias conflict\n")
<< "The module label alias '" << alias << "' and product instance alias '" << theInstanceAlias << "'\n"
<< "are used for multiple products of type '" << friendlyClassName << "'\n"
<< "One has module label '" << moduleLabel << "' and product instance name '" << productInstanceName
<< "',\n"
<< "the other has module label '" << iter->second.moduleLabel() << "' and product instance name '"
<< iter->second.productInstanceName() << "'.\n";
}
} else {
auto prodIter = preg.productList().find(key);
if (prodIter != preg.productList().end()) {
if (!prodIter->second.produced()) {
throw Exception(errors::Configuration, "EDAlias\n")
<< "The module label alias '" << alias << "' and product instance alias '" << theInstanceAlias << "'\n"
<< "are used for a product of type '" << friendlyClassName << "'\n"
<< "with module label '" << moduleLabel << "' and product instance name '" << productInstanceName
<< "',\n"
<< "An EDAlias can only be used for products produced in the current process. This one is not.\n";
}
aliasMap.insert(std::make_pair(key, aliasKey));
aliasKeys.insert(std::make_pair(aliasKey, key));
}
}
}

void processEDAliases(ParameterSet const& proc_pset, std::string const& processName, ProductRegistry& preg) {
std::vector<std::string> aliases = proc_pset.getParameter<std::vector<std::string>>("@all_aliases");
if (aliases.empty()) {
return;
}
std::string const star("*");
std::string const empty("");
ParameterSetDescription desc;
desc.add<std::string>("type");
desc.add<std::string>("fromProductInstance", star);
desc.add<std::string>("toProductInstance", star);

std::multimap<BranchKey, BranchKey> aliasMap;

std::map<BranchKey, BranchKey> aliasKeys; // Used to search for duplicates or clashes.

// Auxiliary search structure to support wildcard for friendlyClassName
std::multimap<std::string, BranchKey> moduleLabelToBranches;
for (auto const& prod : preg.productList()) {
if (processName == prod.second.processName()) {
moduleLabelToBranches.emplace(prod.first.moduleLabel(), prod.first);
}
}

// Now, loop over the alias information and store it in aliasMap.
for (std::string const& alias : aliases) {
ParameterSet const& aliasPSet = proc_pset.getParameterSet(alias);
std::vector<std::string> vPSetNames = aliasPSet.getParameterNamesForType<VParameterSet>();
for (std::string const& moduleLabel : vPSetNames) {
VParameterSet vPSet = aliasPSet.getParameter<VParameterSet>(moduleLabel);
for (ParameterSet& pset : vPSet) {
desc.validate(pset);
std::string friendlyClassName = pset.getParameter<std::string>("type");
std::string productInstanceName = pset.getParameter<std::string>("fromProductInstance");
std::string instanceAlias = pset.getParameter<std::string>("toProductInstance");

if (friendlyClassName == star) {
bool processHasLabel = false;
bool match = false;
for (auto it = moduleLabelToBranches.lower_bound(moduleLabel);
it != moduleLabelToBranches.end() && it->first == moduleLabel;
++it) {
processHasLabel = true;
if (productInstanceName != star and productInstanceName != it->second.productInstanceName()) {
continue;
}
match = true;

checkAndInsertAlias(it->second.friendlyClassName(),
moduleLabel,
it->second.productInstanceName(),
processName,
alias,
instanceAlias,
preg,
aliasMap,
aliasKeys);
}
if (not match and processHasLabel) {
// No product was found matching the alias.
// We throw an exception only if a module with the specified module label was created in this process.
// Note that if that condition is ever relatex, it might be best to throw an exception with different
// message (omitting productInstanceName) in case 'productInstanceName == start'
throw Exception(errors::Configuration, "EDAlias parameter set mismatch\n")
<< "There are no products with module label '" << moduleLabel << "' and product instance name '"
<< productInstanceName << "'.\n";
}
} else if (productInstanceName == star) {
bool match = false;
BranchKey lowerBound(friendlyClassName, moduleLabel, empty, empty);
for (ProductRegistry::ProductList::const_iterator it = preg.productList().lower_bound(lowerBound);
it != preg.productList().end() && it->first.friendlyClassName() == friendlyClassName &&
it->first.moduleLabel() == moduleLabel;
++it) {
if (it->first.processName() != processName) {
continue;
}
match = true;

checkAndInsertAlias(friendlyClassName,
moduleLabel,
it->first.productInstanceName(),
processName,
alias,
instanceAlias,
preg,
aliasMap,
aliasKeys);
}
if (!match) {
// No product was found matching the alias.
// We throw an exception only if a module with the specified module label was created in this process.
for (auto const& product : preg.productList()) {
if (moduleLabel == product.first.moduleLabel() && processName == product.first.processName()) {
throw Exception(errors::Configuration, "EDAlias parameter set mismatch\n")
<< "There are no products of type '" << friendlyClassName << "'\n"
<< "with module label '" << moduleLabel << "'.\n";
}
}
}
} else {
checkAndInsertAlias(friendlyClassName,
moduleLabel,
productInstanceName,
processName,
alias,
instanceAlias,
preg,
aliasMap,
aliasKeys);
}
}
}
}

// Now add the new alias entries to the product registry.
for (auto const& aliasEntry : aliasMap) {
ProductRegistry::ProductList::const_iterator it = preg.productList().find(aliasEntry.first);
assert(it != preg.productList().end());
preg.addLabelAlias(it->second, aliasEntry.second.moduleLabel(), aliasEntry.second.productInstanceName());
}
}

typedef std::vector<std::string> vstring;

void processSwitchProducers(ParameterSet const& proc_pset, std::string const& processName, ProductRegistry& preg) {
Expand Down Expand Up @@ -772,7 +578,10 @@ namespace edm {
std::vector<std::string> modulesInConfig(proc_pset.getParameter<std::vector<std::string>>("@all_modules"));
std::map<std::string, std::vector<std::pair<std::string, int>>> outputModulePathPositions;
reduceParameterSet(proc_pset, tns.getEndPaths(), modulesInConfig, usedModuleLabels, outputModulePathPositions);
processEDAliases(proc_pset, processConfiguration->processName(), preg);
{
std::vector<std::string> aliases = proc_pset.getParameter<std::vector<std::string>>("@all_aliases");
detail::processEDAliases(aliases, {}, proc_pset, processConfiguration->processName(), preg);
}

// At this point all BranchDescriptions are created. Mark now the
// ones of unscheduled workers to be on-demand.
Expand Down
53 changes: 40 additions & 13 deletions FWCore/Framework/src/StreamSchedule.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "FWCore/Concurrency/interface/WaitingTaskHolder.h"

#include "LuminosityBlockProcessingStatus.h"
#include "processEDAliases.h"

#include <algorithm>
#include <cassert>
Expand Down Expand Up @@ -485,6 +486,10 @@ namespace edm {
}
if (productFromConditionalModule) {
itFound = conditionalModules.find(productModuleLabel);
//check that the alias-for conditional module has not been used
if (itFound == conditionalModules.end()) {
continue;
}
}
} else {
//need to check the rest of the data product info
Expand Down Expand Up @@ -573,24 +578,46 @@ namespace edm {
auto aliasedToModuleLabels = info.getParameterNames();
for (auto const& mod : aliasedToModuleLabels) {
if (not mod.empty() and mod[0] != '@' and conditionalmods.find(mod) != conditionalmods.end()) {
auto aliasPSet = proc_pset.getParameter<edm::ParameterSet>(mod);
std::string type = star;
std::string instance = star;
std::string originalInstance = star;
if (aliasPSet.exists("type")) {
type = aliasPSet.getParameter<std::string>("type");
}
if (aliasPSet.exists("toProductInstance")) {
instance = aliasPSet.getParameter<std::string>("toProductInstance");
auto aliasVPSet = info.getParameter<std::vector<edm::ParameterSet>>(mod);
for (auto const& aliasPSet : aliasVPSet) {
std::string type = star;
std::string instance = star;
std::string originalInstance = star;
if (aliasPSet.exists("type")) {
type = aliasPSet.getParameter<std::string>("type");
}
if (aliasPSet.exists("toProductInstance")) {
instance = aliasPSet.getParameter<std::string>("toProductInstance");
}
if (aliasPSet.exists("fromProductInstance")) {
originalInstance = aliasPSet.getParameter<std::string>("fromProductInstance");
}

aliasMap.emplace(alias, AliasInfo{type, instance, originalInstance, mod});
}
if (aliasPSet.exists("fromProductInstance")) {
originalInstance = aliasPSet.getParameter<std::string>("fromProductInstance");
}
}
}
}
//find SwitchProducers whose chosen case is an alias
{
auto const& all_modules = proc_pset.getParameter<std::vector<std::string>>("@all_modules");
std::vector<std::string> switchEDAliases;
for (auto const& module : all_modules) {
auto const& mod_pset = proc_pset.getParameter<edm::ParameterSet>(module);
if (mod_pset.getParameter<std::string>("@module_type") == "SwitchProducer") {
auto const& chosen_case = mod_pset.getUntrackedParameter<std::string>("@chosen_case");
auto range = aliasMap.equal_range(chosen_case);
if (range.first != range.second) {
switchEDAliases.push_back(chosen_case);
for (auto it = range.first; it != range.second; ++it) {
aliasMap.emplace(module, it->second);
}

aliasMap.emplace(alias, AliasInfo{type, instance, originalInstance, mod});
}
}
}
detail::processEDAliases(
switchEDAliases, conditionalmods, proc_pset, processConfiguration->processName(), preg);
}
{
//find branches created by the conditional modules
Expand Down
Loading

0 comments on commit 9554e9c

Please sign in to comment.