[CPU] Reduce overhead of the executor storage (#23307)

By using a vector instead of a map.
To reduce an overhead of selecting an executor.
Since we know the exact mapping beforehand (by implementation Id): every
executor corresponds to
a particular implementation.
This commit is contained in:
Egor Duplenskii 2024-03-11 07:17:41 +01:00 committed by GitHub
parent 5b7d7c87a8
commit baf1c9d346
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 31 additions and 19 deletions

View File

@ -61,7 +61,8 @@ public:
m_postOps(postOps),
m_context(context),
m_suitableImplementations(filter(m_attrs, m_postOps, descriptors, implementationPriority)),
m_implementationRequiresFallback(m_suitableImplementations.size(), true) {}
m_implementationRequiresFallback(m_suitableImplementations.size(), true),
m_executors(m_suitableImplementations.size()) {}
/**
* @brief Retrieves the proper memory descriptors based on the provided memory descriptors.
@ -106,12 +107,8 @@ public:
*/
void preconfigure(const MemoryArgs& memory) {
executor::Config<Attrs> config{memoryDescsFromMemory(memory), m_attrs, m_postOps};
std::transform(m_suitableImplementations.begin(),
m_suitableImplementations.end(),
m_implementationRequiresFallback.begin(),
[&config](const std::reference_wrapper<const ExecutorImplementation<Attrs>>& impl) {
return impl.get().requiresFallback(config);
});
cacheFallbackStatus(config);
const size_t implId = select(memory, 0);
const auto& impl = m_suitableImplementations[implId].get();
@ -123,7 +120,7 @@ public:
}
}
(void)create(impl, memory, m_context);
(void)create(implId, memory, m_context);
}
/**
@ -154,7 +151,7 @@ public:
return fallback<Attrs, NodeT>(config, *fallbackConfig, memory, m_context, impl.name());
}
}
const auto executor = create(impl, memory, m_context);
const auto executor = create(implId, memory, m_context);
if (!executor->update(memory)) {
return nullptr;
}
@ -181,6 +178,19 @@ private:
return memoryDescs;
}
/**
* @brief Caches the fallback status for each suitable implementation.
*/
void cacheFallbackStatus(const executor::Config<Attrs>& config) {
std::transform(m_suitableImplementations.begin(),
m_suitableImplementations.end(),
m_implementationRequiresFallback.begin(),
[&config](const std::reference_wrapper<const ExecutorImplementation<Attrs>>& impl) {
return impl.get().requiresFallback(config);
});
}
/**
* @brief Filters and retrieves suitable implementations based on the provided executor configuration.
*
@ -249,18 +259,19 @@ private:
return std::distance(m_suitableImplementations.begin(), selectedImplementation);
}
ExecutorPtr create(const ExecutorImplementation<Attrs>& impl,
ExecutorPtr create(const size_t implId,
const MemoryArgs& memory,
const ExecutorContext::CPtr context) {
DEBUG_LOG("Creating executor using implementation: ", impl.name());
const auto& executorId = std::make_pair(impl.type(), impl.operationType());
auto factoryIt = m_executors.find(executorId);
if (factoryIt == m_executors.end()) {
factoryIt =
m_executors.insert(std::make_pair(executorId, impl.create(m_attrs, m_postOps, memory, context))).first;
}
assert(implId < m_executors.size());
auto executor = m_executors[implId];
if (executor)
return executor;
return factoryIt->second;
assert(implId < m_suitableImplementations.size());
const auto& impl = m_suitableImplementations[implId].get();
DEBUG_LOG("Creating executor using implementation: ", impl.name());
return impl.create(m_attrs, m_postOps, memory, context);
}
const Attrs& m_attrs;
@ -269,7 +280,8 @@ private:
std::vector<std::reference_wrapper<const ExecutorImplementation<Attrs>>> m_suitableImplementations;
// stores fallback status to avoid performing the check for every make() call
std::vector<bool> m_implementationRequiresFallback;
std::map<std::pair<ExecutorType, OperationType>, ExecutorPtr> m_executors;
// executors cache
std::vector<ExecutorPtr> m_executors;
};
template <typename Attrs, typename NodeT>