Skip to content
Snippets Groups Projects
Commit 1b99bd31 authored by Martin Christoph Hierholzer's avatar Martin Christoph Hierholzer
Browse files

Slight optimisation: merge the 3 maps used in the updateLoop() into a single map with a struct.

This avoids multiple map lookups.
parent 817aeb58
No related branches found
No related tags found
No related merge requests found
......@@ -40,11 +40,15 @@ namespace ChimeraTK {
protected:
std::list<ChimeraTK::TransferElementAbstractor> _elementsToRead;
boost::thread _syncThread; // we have to use boost thread to use interruption points
// FIXME: make this an unordered map
std::map<ChimeraTK::TransferElementID, std::vector<std::function<void()>>> _toDoocsUpdateMap;
std::map<ChimeraTK::TransferElementID, std::vector<EqFct*>> _toDoocsEqFctMap;
std::map<ChimeraTK::TransferElementID, std::set<boost::shared_ptr<ChimeraTK::TransferElement>>>
_toDoocsAdditionalTransferElementsMap;
// Struct used to aggregate the information needed in the updateLoop when an update is received from the
// application.
struct ToDoocsUpdateDescriptor {
std::vector<std::function<void()>> updateFunctions;
std::vector<EqFct*> locations;
std::set<boost::shared_ptr<ChimeraTK::TransferElement>> additionalTransferElements;
};
std::map<ChimeraTK::TransferElementID, ToDoocsUpdateDescriptor> _toDoocsDescriptorMap;
};
} // namespace ChimeraTK
......
......@@ -7,25 +7,25 @@ namespace ChimeraTK {
void DoocsUpdater::addVariable(
TransferElementAbstractor variable, EqFct* eq_fct, std::function<void()> updaterFunction) {
// Don't add the transfer element twice into the list of elements to read.
// Don't add the transfer element twice into the list of elements to read (i.e. later into the ReadAnyGroup).
// To check if there is such an element we use the map with the lookup table
// which has a search function, instead of manually looking at the elements in
// the list and compare the ID.
if(_toDoocsUpdateMap.find(variable.getId()) == _toDoocsUpdateMap.end()) {
if(_toDoocsDescriptorMap.find(variable.getId()) == _toDoocsDescriptorMap.end()) {
_elementsToRead.push_back(variable);
}
else {
_toDoocsAdditionalTransferElementsMap[variable.getId()].insert(variable.getHighLevelImplElement());
_toDoocsDescriptorMap[variable.getId()].additionalTransferElements.insert(variable.getHighLevelImplElement());
}
_toDoocsUpdateMap[variable.getId()].push_back(updaterFunction);
_toDoocsEqFctMap[variable.getId()].push_back(eq_fct);
_toDoocsDescriptorMap[variable.getId()].updateFunctions.push_back(updaterFunction);
_toDoocsDescriptorMap[variable.getId()].locations.push_back(eq_fct);
}
void DoocsUpdater::update() {
for(auto& transferElem : _elementsToRead) {
if(transferElem.readLatest()) {
for(auto& updaterFunction : _toDoocsUpdateMap[transferElem.getId()]) {
for(auto& updaterFunction : _toDoocsDescriptorMap[transferElem.getId()].updateFunctions) {
updaterFunction();
}
}
......@@ -37,16 +37,21 @@ namespace ChimeraTK {
return;
}
// Worst-case: We need to lock all locations, so pre-allocate this here
std::unordered_set<EqFct*> locationsToLock;
locationsToLock.reserve(_toDoocsEqFctMap.size());
// preallocate locationsToLock to avoid breaking "realtime" behaivour
size_t nMaxLocationsToLock = 0;
for(auto& pair : _toDoocsDescriptorMap) {
nMaxLocationsToLock = std::max(nMaxLocationsToLock, pair.second.locations.size());
}
locationsToLock.reserve(nMaxLocationsToLock);
ReadAnyGroup group(_elementsToRead.begin(), _elementsToRead.end());
while(true) {
// Call preRead for all TEs on _toDoocsAdditionalTransferElementsMap. waitAny() is doing this for all
// Call preRead for all TEs on additional transfer elements. waitAny() is doing this for all
// elements in the ReadAnyGroup. Unnecessary calls to preRead are ignored anyway.
for(auto& pair : _toDoocsAdditionalTransferElementsMap) {
for(auto& elem : pair.second) {
for(auto& pair : _toDoocsDescriptorMap) {
for(auto& elem : pair.second.additionalTransferElements) {
elem->preRead(ChimeraTK::TransferType::read);
}
}
......@@ -54,23 +59,27 @@ namespace ChimeraTK {
// Wait until any variable got an update
auto notification = group.waitAny();
auto updatedElement = notification.getId();
auto& descriptor = _toDoocsDescriptorMap[updatedElement];
// Gather all involved locations in a unique set
for(auto& location : _toDoocsEqFctMap[updatedElement]) {
for(auto& location : descriptor.locations) {
if(locationsToLock.insert(location).second) location->lock();
}
// Complete the read transfer of the process variable
notification.accept();
// Call postRead for all TEs on _toDoocsAdditionalTransferElementsMap for the updated ID
for(auto& elem : _toDoocsAdditionalTransferElementsMap[updatedElement]) {
for(auto& elem : descriptor.additionalTransferElements) {
elem->postRead(ChimeraTK::TransferType::read, true);
}
// Call all updater functions
for(auto& updaterFunction : _toDoocsUpdateMap[updatedElement]) updaterFunction();
for(auto& updaterFunction : descriptor.updateFunctions) updaterFunction();
// Unlock all involved locations
for(auto& location : locationsToLock) location->unlock();
locationsToLock.clear();
// Allow shutting down this thread...
boost::this_thread::interruption_point();
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment