Draft: Use a container with flexible key type as cache for quadrature rules
- Jul 04, 2021
-
-
Simon Praetorius authored
-
For a thread-safe cache of quadrature rules, currently a vector of vectors of vectors with several std::call_once
flags is used. This makes reading the code very complicated and does not necessarily lead to any better performance than the proposed solution in this MR. Replace the nested vector with a simple std::map
where the key allows to identify all quadrature rules and additionally makes it possible to extend quadrature rules properties in the future.
Instead of a std::map
container, any other associative container could be used. I have chose a simple map since comparison of three integers by <
is very simple to implement. The alternative std::unordered_map
would require a hash function. While this is possible, it requires more code. I do not expect a measurable performance difference.
The cache is implemented as thread_local
. This allows to omit more complicated locking mechanisms and should be thread-safe by definition. It is, however, unclear to me, whether this has negative performance consequences it threads are closed and reopened multiple times, i.e., if this makes it necessary to re-"compute"/re-fill the cache or whether this preserves the previously cached values. An alternative implementation uses the static
keyword:
// Container to store the cached values
static std::map<QuadratureKey, QuadratureRule> quadCache;
// mutex used to access the data in the container, necessary since
// access emplace is read-write.
using mutex_type = std::shared_timed_mutex;
static mutex_type access_mutex;
// define the quadrature key to be used to access the quadrature rule
const QuadratureKey key{t.id(),p,qt};
// first try to lock for read-only, if a quadratur rule for key is found, return it,
// if not, obtain a unique_lock to insert a new rule.
std::shared_lock<mutex_type> read_lock(access_mutex);
auto it = quadCache.find(key);
if (it != quadCache.end())
return it->second;
else {
read_lock.unlock();
QuadratureRule rule = QuadratureRuleFactory<ctype,dim>::rule(t,p,qt);
std::unique_lock<mutex_type> write_lock(access_mutex);
auto new_it = quadCache.emplace(key, std::move(rule));
return new_it.first->second;
}