13
0

Implement memory-pool debug-dump

This will allow to trace "POOL OUT OF MEMORY" and see
which events fill up the event/memory pool.
This commit is contained in:
Robin Gareus 2022-07-07 04:42:48 +02:00
parent c7ec2bbe1f
commit 1694c71cd5
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
2 changed files with 36 additions and 15 deletions

View File

@ -2,7 +2,7 @@
* Copyright (C) 1998-2015 Paul Davis <paul@linuxaudiosystems.com>
* Copyright (C) 2009-2014 David Robillard <d@drobilla.net>
* Copyright (C) 2010 Carl Hetherington <carl@carlh.net>
* Copyright (C) 2015-2017 Robin Gareus <robin@gareus.org>
* Copyright (C) 2015-2022 Robin Gareus <robin@gareus.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -30,13 +30,15 @@
#include "pbd/libpbd_visibility.h"
#include "pbd/ringbuffer.h"
typedef void (*PoolDumpCallback)(size_t, void*);
/** A pool of data items that can be allocated, read from and written to
* without system memory allocation or locking.
*/
class LIBPBD_API Pool
{
public:
Pool (std::string name, unsigned long item_size, unsigned long nitems);
Pool (std::string name, unsigned long item_size, unsigned long nitems, PoolDumpCallback cb = NULL);
virtual ~Pool ();
virtual void *alloc ();
@ -48,11 +50,14 @@ class LIBPBD_API Pool
guint total() const { return free_list.bufsize(); }
protected:
PBD::RingBuffer<void*> free_list; ///< a list of pointers to free items within block
std::string _name;
private:
void *block; ///< data storage area
void* _block; ///< data storage area
PoolDumpCallback _dump; ///< callback to print pool contents
#ifndef NDEBUG
unsigned long max_usage;
#endif
@ -102,7 +107,7 @@ class LIBPBD_API PerThreadPool;
class LIBPBD_API CrossThreadPool : public Pool
{
public:
CrossThreadPool (std::string n, unsigned long isize, unsigned long nitems, PerThreadPool *);
CrossThreadPool (std::string n, unsigned long isize, unsigned long nitems, PerThreadPool*, PoolDumpCallback);
void* alloc ();
void push (void *);
@ -132,7 +137,8 @@ public:
const Glib::Threads::Private<CrossThreadPool>& key() const { return _key; }
void create_per_thread_pool (std::string name, unsigned long item_size, unsigned long nitems);
void create_per_thread_pool (std::string name, unsigned long item_size, unsigned long nitems, PoolDumpCallback cb = NULL);
CrossThreadPool* per_thread_pool (bool must_exist = true);
bool has_per_thread_pool ();
void set_trash (PBD::RingBuffer<CrossThreadPool*>* t);

View File

@ -3,7 +3,7 @@
* Copyright (C) 2008-2009 David Robillard <d@drobilla.net>
* Copyright (C) 2008-2011 Carl Hetherington <carl@carlh.net>
* Copyright (C) 1998-2015 Paul Davis <paul@linuxaudiosystems.com>
* Copyright (C) 2014-2015 Robin Gareus <robin@gareus.org>
* Copyright (C) 2014-2022 Robin Gareus <robin@gareus.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -20,6 +20,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <cstdlib>
@ -30,30 +31,34 @@
#include "pbd/error.h"
#include "pbd/debug.h"
#include "pbd/compose.h"
#include "pbd/stacktrace.h"
using namespace std;
using namespace PBD;
Pool::Pool (string n, unsigned long item_size, unsigned long nitems)
Pool::Pool (string n, unsigned long item_size, unsigned long nitems, PoolDumpCallback cb)
: free_list (nitems)
, _name (n)
, _dump (cb)
#ifndef NDEBUG
, max_usage (0)
#endif
{
_name = n;
/* adjust to actual size (power-of-two) */
nitems = free_list.bufsize ();
/* since some overloaded ::operator new() might use this,
its important that we use a "lower level" allocator to
get more space.
*/
block = malloc (nitems * item_size);
_block = malloc (nitems * item_size);
void **ptrlist = (void **) malloc (sizeof (void *) * nitems);
void **ptrlist = (void **) calloc (nitems, sizeof (void *));
for (unsigned long i = 0; i < nitems; i++) {
ptrlist[i] = static_cast<void *> (static_cast<char*>(block) + (i * item_size));
ptrlist[i] = static_cast<void *> (static_cast<char*>(_block) + (i * item_size));
}
free_list.write (ptrlist, nitems);
@ -63,7 +68,7 @@ Pool::Pool (string n, unsigned long item_size, unsigned long nitems)
Pool::~Pool ()
{
DEBUG_TRACE (DEBUG::Pool, string_compose ("Pool: '%1' max: %2 / %3\n", name(), max_usage, total()));
free (block);
free (_block);
}
/** Allocate an item's worth of memory in the Pool by taking one from the free list.
@ -81,6 +86,16 @@ Pool::alloc ()
#endif
if (free_list.read (&ptr, 1) < 1) {
PBD::stacktrace (std::cerr, 20);
if (_dump) {
void** _block = free_list.buffer ();
for (size_t i = 0; i < free_list.bufsize (); ++i) {
_dump (i, _block[i]);
}
printf ("RingBuffer write-idx: %u read-idx: %u\n", free_list.get_write_idx (), free_list.get_read_idx ());
}
fatal << "CRITICAL: " << _name << " POOL OUT OF MEMORY - RECOMPILE WITH LARGER SIZE!!" << endmsg;
abort(); /*NOTREACHED*/
return 0;
@ -182,9 +197,9 @@ PerThreadPool::PerThreadPool ()
* @param nitems Number of items in the pool.
*/
void
PerThreadPool::create_per_thread_pool (string n, unsigned long isize, unsigned long nitems)
PerThreadPool::create_per_thread_pool (string n, unsigned long isize, unsigned long nitems, PoolDumpCallback cb)
{
_key.set (new CrossThreadPool (n, isize, nitems, this));
_key.set (new CrossThreadPool (n, isize, nitems, this, cb));
}
/** @return True if CrossThreadPool for the current thread exists,
@ -240,8 +255,8 @@ PerThreadPool::add_to_trash (CrossThreadPool* p)
_trash->write (&p, 1);
}
CrossThreadPool::CrossThreadPool (string n, unsigned long isize, unsigned long nitems, PerThreadPool* p)
: Pool (n, isize, nitems)
CrossThreadPool::CrossThreadPool (string n, unsigned long isize, unsigned long nitems, PerThreadPool* p, PoolDumpCallback cb)
: Pool (n, isize, nitems, cb)
, pending (nitems)
, _parent (p)
{