[Bug libstdc++/96942] std::pmr::monotonic_buffer_resource causes CPU cache misses

redi at gcc dot gnu.org gcc-bugzilla@gcc.gnu.org
Tue Sep 8 11:48:03 GMT 2020


--- Comment #15 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Jonathan Wakely from comment #12)
> m_b_r really needs a "rewind()" member to mark all allocated memory as
> unused again, without actually deallocating it and returning it to the
> upstream resource.

Alternatively, you can use a pooling allocator as the upstream memory resource
for the std::m_b_r resource, so that when you call release() on the std::m_b_r
object it only releases it upstream, not back to malloc.

Here's an upstream allocator that only supports fundamental alignments and will
only allocate once, but keeps it around for reuse when the std::m_b_r

struct OnceResource : std::pmr::memory_resource
  void* do_allocate(std::size_t n, std::size_t alignment)
    if (alignment > alignof(std::max_align_t))
      throw std::bad_alloc();

    if (!m_ptr)
      m_ptr = std::malloc(n);
      if (m_ptr == nullptr)
        throw std::bad_alloc();
      m_size = n;
      m_free = true;
    else if (!m_free || n > m_size)
      throw std::bad_alloc();

    return m_ptr;

  void do_deallocate(void*, std::size_t, std::size_t)
  { m_free = true; }

  bool do_is_equal(const std::pmr::memory_resource& m) const noexcept
  { return std::addressof(m) == this; }

  { std::free(m_ptr); }

  void* m_ptr = nullptr;
  std::size_t m_size = 0;
  bool m_free = false;

and then ...

  OnceResource o;
  // Alloc then dealloc stretchdepth tree.
  int count = 0;
  for(int i = 0; i < 20; ++i)
    MemoryPool store (poolSize(stretch_depth), &o);

This makes a big difference.

More information about the Gcc-bugs mailing list