Skip to content

Draft: Use a container with flexible key type as cache for quadrature rules

Simon Praetorius requested to merge feature/quadrature-cache into master

Summary

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.

Discussion

  1. 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.

  2. 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;
}
Edited by Simon Praetorius

Merge request reports