TransferBufferManager rewritten to move all the code into a non-generic subclass. STM32 test code size reduced to 176k (-O1)

This commit is contained in:
Pavel Kirienko 2014-04-09 11:52:05 +04:00
parent 9e5115948b
commit a8d12d2004
4 changed files with 217 additions and 232 deletions

View File

@ -57,7 +57,7 @@ class UAVCAN_EXPORT Node : public INode
return res;
}
NodeInitializer initializer(*this);
StaticAssert<(sizeof(initializer) < 1024)>::check();
StaticAssert<(sizeof(initializer) < 1200)>::check();
res = initializer.execute();
node_init_result = initializer.getResult();
return res;

View File

@ -162,7 +162,6 @@ public:
{ }
int read(unsigned offset, uint8_t* data, unsigned len) const;
int write(unsigned offset, const uint8_t* data, unsigned len);
void reset();
@ -203,7 +202,6 @@ public:
{ }
int read(unsigned offset, uint8_t* data, unsigned len) const;
int write(unsigned offset, const uint8_t* data, unsigned len);
bool migrateFrom(const TransferBufferManagerEntry* tbme);
@ -254,259 +252,63 @@ public:
/**
* Buffer manager implementation.
*/
template <unsigned MaxBufSize, unsigned NumStaticBufs>
class UAVCAN_EXPORT TransferBufferManager : public ITransferBufferManager, Noncopyable
class TransferBufferManagerImpl : public ITransferBufferManager, Noncopyable
{
typedef StaticTransferBufferManagerEntry<MaxBufSize> StaticBufferType;
StaticBufferType static_buffers_[NumStaticBufs];
LinkedListRoot<DynamicTransferBufferManagerEntry> dynamic_buffers_;
IAllocator& allocator_;
const unsigned max_buf_size_;
StaticBufferType* findFirstStatic(const TransferBufferManagerKey& key);
virtual StaticTransferBufferManagerEntryImpl* getStaticByIndex(unsigned index) const = 0;
StaticTransferBufferManagerEntryImpl* findFirstStatic(const TransferBufferManagerKey& key);
DynamicTransferBufferManagerEntry* findFirstDynamic(const TransferBufferManagerKey& key);
void optimizeStorage();
public:
TransferBufferManager(IAllocator& allocator)
TransferBufferManagerImpl(unsigned max_buf_size, IAllocator& allocator)
: allocator_(allocator)
{
StaticAssert<(MaxBufSize > 0)>::check();
StaticAssert<(NumStaticBufs > 0)>::check();
}
, max_buf_size_(max_buf_size)
{ }
~TransferBufferManager();
~TransferBufferManagerImpl();
ITransferBuffer* access(const TransferBufferManagerKey& key);
ITransferBuffer* create(const TransferBufferManagerKey& key);
void remove(const TransferBufferManagerKey& key);
bool isEmpty() const;
unsigned getNumDynamicBuffers() const;
unsigned getNumStaticBuffers() const;
};
template <unsigned MaxBufSize, unsigned NumStaticBufs>
class UAVCAN_EXPORT TransferBufferManager : public TransferBufferManagerImpl
{
mutable StaticTransferBufferManagerEntry<MaxBufSize> static_buffers_[NumStaticBufs]; // TODO: zero buffers support
StaticTransferBufferManagerEntry<MaxBufSize>* getStaticByIndex(unsigned index) const
{
return (index < NumStaticBufs) ? &static_buffers_[index] : NULL;
}
public:
TransferBufferManager(IAllocator& allocator)
: TransferBufferManagerImpl(MaxBufSize, allocator)
{
StaticAssert<(MaxBufSize > 0)>::check();
}
};
template <>
class UAVCAN_EXPORT TransferBufferManager<0, 0> : public ITransferBufferManager
{
public:
TransferBufferManager() { }
TransferBufferManager(IAllocator& allocator)
{
(void)allocator;
}
ITransferBuffer* access(const TransferBufferManagerKey& key)
{
(void)key;
return NULL;
}
ITransferBuffer* create(const TransferBufferManagerKey& key)
{
(void)key;
return NULL;
}
void remove(const TransferBufferManagerKey& key)
{
(void)key;
}
TransferBufferManager(IAllocator&) { }
ITransferBuffer* access(const TransferBufferManagerKey&) { return NULL; }
ITransferBuffer* create(const TransferBufferManagerKey&) { return NULL; }
void remove(const TransferBufferManagerKey&) { }
bool isEmpty() const { return true; }
};
// ----------------------------------------------------------------------------
/*
* TransferBufferManager<>
*/
template <unsigned MaxBufSize, unsigned NumStaticBufs>
typename TransferBufferManager<MaxBufSize, NumStaticBufs>::StaticBufferType*
TransferBufferManager<MaxBufSize, NumStaticBufs>::findFirstStatic(const TransferBufferManagerKey& key)
{
for (unsigned i = 0; i < NumStaticBufs; i++)
{
if (static_buffers_[i].getKey() == key)
{
return static_buffers_ + i;
}
}
return NULL;
}
template <unsigned MaxBufSize, unsigned NumStaticBufs>
DynamicTransferBufferManagerEntry*
TransferBufferManager<MaxBufSize, NumStaticBufs>::findFirstDynamic(const TransferBufferManagerKey& key)
{
DynamicTransferBufferManagerEntry* dyn = dynamic_buffers_.get();
while (dyn)
{
assert(!dyn->isEmpty());
if (dyn->getKey() == key)
{
return dyn;
}
dyn = dyn->getNextListNode();
}
return NULL;
}
template <unsigned MaxBufSize, unsigned NumStaticBufs>
void TransferBufferManager<MaxBufSize, NumStaticBufs>::optimizeStorage()
{
while (!dynamic_buffers_.isEmpty())
{
StaticBufferType* const sb = findFirstStatic(TransferBufferManagerKey());
if (sb == NULL)
{
break;
}
DynamicTransferBufferManagerEntry* dyn = dynamic_buffers_.get();
assert(dyn);
assert(!dyn->isEmpty());
if (sb->migrateFrom(dyn))
{
assert(!dyn->isEmpty());
UAVCAN_TRACE("TransferBufferManager", "Storage optimization: Migrated %s",
dyn->getKey().toString().c_str());
dynamic_buffers_.remove(dyn);
DynamicTransferBufferManagerEntry::destroy(dyn, allocator_);
}
else
{
/* Migration can fail if a dynamic buffer contains more data than a static buffer can accomodate.
* This should never happen during normal operation because dynamic buffers are limited in growth.
*/
UAVCAN_TRACE("TransferBufferManager", "Storage optimization: MIGRATION FAILURE %s MAXSIZE %u",
dyn->getKey().toString().c_str(), MaxBufSize);
assert(0);
sb->reset();
break;
}
}
}
template <unsigned MaxBufSize, unsigned NumStaticBufs>
TransferBufferManager<MaxBufSize, NumStaticBufs>::~TransferBufferManager()
{
DynamicTransferBufferManagerEntry* dyn = dynamic_buffers_.get();
while (dyn)
{
DynamicTransferBufferManagerEntry* const next = dyn->getNextListNode();
dynamic_buffers_.remove(dyn);
DynamicTransferBufferManagerEntry::destroy(dyn, allocator_);
dyn = next;
}
}
template <unsigned MaxBufSize, unsigned NumStaticBufs>
ITransferBuffer* TransferBufferManager<MaxBufSize, NumStaticBufs>::access(const TransferBufferManagerKey& key)
{
if (key.isEmpty())
{
assert(0);
return NULL;
}
TransferBufferManagerEntry* tbme = findFirstStatic(key);
if (tbme)
{
return tbme;
}
return findFirstDynamic(key);
}
template <unsigned MaxBufSize, unsigned NumStaticBufs>
ITransferBuffer* TransferBufferManager<MaxBufSize, NumStaticBufs>::create(const TransferBufferManagerKey& key)
{
if (key.isEmpty())
{
assert(0);
return NULL;
}
remove(key);
TransferBufferManagerEntry* tbme = findFirstStatic(TransferBufferManagerKey());
if (tbme == NULL)
{
DynamicTransferBufferManagerEntry* dyn =
DynamicTransferBufferManagerEntry::instantiate(allocator_, MaxBufSize);
tbme = dyn;
if (dyn == NULL)
{
return NULL; // Epic fail.
}
dynamic_buffers_.insert(dyn);
UAVCAN_TRACE("TransferBufferManager", "Dynamic buffer created [st=%u, dyn=%u], %s",
getNumStaticBuffers(), getNumDynamicBuffers(), key.toString().c_str());
}
else
{
UAVCAN_TRACE("TransferBufferManager", "Static buffer created [st=%u, dyn=%u], %s",
getNumStaticBuffers(), getNumDynamicBuffers(), key.toString().c_str());
}
if (tbme)
{
assert(tbme->isEmpty());
tbme->reset(key);
}
return tbme;
}
template <unsigned MaxBufSize, unsigned NumStaticBufs>
void TransferBufferManager<MaxBufSize, NumStaticBufs>::remove(const TransferBufferManagerKey& key)
{
assert(!key.isEmpty());
TransferBufferManagerEntry* const tbme = findFirstStatic(key);
if (tbme)
{
UAVCAN_TRACE("TransferBufferManager", "Static buffer deleted, %s", key.toString().c_str());
tbme->reset();
optimizeStorage();
return;
}
DynamicTransferBufferManagerEntry* dyn = findFirstDynamic(key);
if (dyn)
{
UAVCAN_TRACE("TransferBufferManager", "Dynamic buffer deleted, %s", key.toString().c_str());
dynamic_buffers_.remove(dyn);
DynamicTransferBufferManagerEntry::destroy(dyn, allocator_);
}
}
template <unsigned MaxBufSize, unsigned NumStaticBufs>
bool TransferBufferManager<MaxBufSize, NumStaticBufs>::isEmpty() const
{
return (getNumStaticBuffers() == 0) && (getNumDynamicBuffers() == 0);
}
template <unsigned MaxBufSize, unsigned NumStaticBufs>
unsigned TransferBufferManager<MaxBufSize, NumStaticBufs>::getNumDynamicBuffers() const
{
return dynamic_buffers_.getLength();
}
template <unsigned MaxBufSize, unsigned NumStaticBufs>
unsigned TransferBufferManager<MaxBufSize, NumStaticBufs>::getNumStaticBuffers() const
{
unsigned res = 0;
for (unsigned i = 0; i < NumStaticBufs; i++)
{
if (!static_buffers_[i].isEmpty())
{
res++;
}
}
return res;
}
}

View File

@ -211,7 +211,7 @@ int DynamicTransferBufferManagerEntry::write(unsigned offset, const uint8_t* dat
}
const int actually_written = len - left_to_write;
max_write_pos_ = std::max(offset + actually_written, max_write_pos_);
max_write_pos_ = std::max(offset + actually_written, unsigned(max_write_pos_));
return actually_written;
}
@ -255,7 +255,7 @@ int StaticTransferBufferImpl::write(unsigned offset, const uint8_t* data, unsign
}
assert((offset + len) <= size_);
std::copy(data, data + len, data_ + offset);
max_write_pos_ = std::max(offset + len, max_write_pos_);
max_write_pos_ = std::max(offset + len, unsigned(max_write_pos_));
return len;
}
@ -317,4 +317,187 @@ bool StaticTransferBufferManagerEntryImpl::migrateFrom(const TransferBufferManag
return true;
}
/*
* TransferBufferManagerImpl
*/
StaticTransferBufferManagerEntryImpl* TransferBufferManagerImpl::findFirstStatic(const TransferBufferManagerKey& key)
{
for (unsigned i = 0; true; i++)
{
StaticTransferBufferManagerEntryImpl* const sb = getStaticByIndex(i);
if (sb == NULL)
{
break;
}
if (sb->getKey() == key)
{
return sb;
}
}
return NULL;
}
DynamicTransferBufferManagerEntry* TransferBufferManagerImpl::findFirstDynamic(const TransferBufferManagerKey& key)
{
DynamicTransferBufferManagerEntry* dyn = dynamic_buffers_.get();
while (dyn)
{
assert(!dyn->isEmpty());
if (dyn->getKey() == key)
{
return dyn;
}
dyn = dyn->getNextListNode();
}
return NULL;
}
void TransferBufferManagerImpl::optimizeStorage()
{
while (!dynamic_buffers_.isEmpty())
{
StaticTransferBufferManagerEntryImpl* const sb = findFirstStatic(TransferBufferManagerKey());
if (sb == NULL)
{
break;
}
DynamicTransferBufferManagerEntry* dyn = dynamic_buffers_.get();
assert(dyn);
assert(!dyn->isEmpty());
if (sb->migrateFrom(dyn))
{
assert(!dyn->isEmpty());
UAVCAN_TRACE("TransferBufferManager", "Storage optimization: Migrated %s",
dyn->getKey().toString().c_str());
dynamic_buffers_.remove(dyn);
DynamicTransferBufferManagerEntry::destroy(dyn, allocator_);
}
else
{
/* Migration can fail if a dynamic buffer contains more data than a static buffer can accomodate.
* This should never happen during normal operation because dynamic buffers are limited in growth.
*/
UAVCAN_TRACE("TransferBufferManager", "Storage optimization: MIGRATION FAILURE %s MAXSIZE %u",
dyn->getKey().toString().c_str(), max_buf_size_);
assert(0);
sb->reset();
break;
}
}
}
TransferBufferManagerImpl::~TransferBufferManagerImpl()
{
DynamicTransferBufferManagerEntry* dyn = dynamic_buffers_.get();
while (dyn)
{
DynamicTransferBufferManagerEntry* const next = dyn->getNextListNode();
dynamic_buffers_.remove(dyn);
DynamicTransferBufferManagerEntry::destroy(dyn, allocator_);
dyn = next;
}
}
ITransferBuffer* TransferBufferManagerImpl::access(const TransferBufferManagerKey& key)
{
if (key.isEmpty())
{
assert(0);
return NULL;
}
TransferBufferManagerEntry* tbme = findFirstStatic(key);
if (tbme)
{
return tbme;
}
return findFirstDynamic(key);
}
ITransferBuffer* TransferBufferManagerImpl::create(const TransferBufferManagerKey& key)
{
if (key.isEmpty())
{
assert(0);
return NULL;
}
remove(key);
TransferBufferManagerEntry* tbme = findFirstStatic(TransferBufferManagerKey());
if (tbme == NULL)
{
DynamicTransferBufferManagerEntry* dyn =
DynamicTransferBufferManagerEntry::instantiate(allocator_, max_buf_size_);
tbme = dyn;
if (dyn == NULL)
{
return NULL; // Epic fail.
}
dynamic_buffers_.insert(dyn);
UAVCAN_TRACE("TransferBufferManager", "Dynamic buffer created [st=%u, dyn=%u], %s",
getNumStaticBuffers(), getNumDynamicBuffers(), key.toString().c_str());
}
else
{
UAVCAN_TRACE("TransferBufferManager", "Static buffer created [st=%u, dyn=%u], %s",
getNumStaticBuffers(), getNumDynamicBuffers(), key.toString().c_str());
}
if (tbme)
{
assert(tbme->isEmpty());
tbme->reset(key);
}
return tbme;
}
void TransferBufferManagerImpl::remove(const TransferBufferManagerKey& key)
{
assert(!key.isEmpty());
TransferBufferManagerEntry* const tbme = findFirstStatic(key);
if (tbme)
{
UAVCAN_TRACE("TransferBufferManager", "Static buffer deleted, %s", key.toString().c_str());
tbme->reset();
optimizeStorage();
return;
}
DynamicTransferBufferManagerEntry* dyn = findFirstDynamic(key);
if (dyn)
{
UAVCAN_TRACE("TransferBufferManager", "Dynamic buffer deleted, %s", key.toString().c_str());
dynamic_buffers_.remove(dyn);
DynamicTransferBufferManagerEntry::destroy(dyn, allocator_);
}
}
bool TransferBufferManagerImpl::isEmpty() const
{
return (getNumStaticBuffers() == 0) && (getNumDynamicBuffers() == 0);
}
unsigned TransferBufferManagerImpl::getNumDynamicBuffers() const
{
return dynamic_buffers_.getLength();
}
unsigned TransferBufferManagerImpl::getNumStaticBuffers() const
{
unsigned res = 0;
for (unsigned i = 0; true; i++)
{
StaticTransferBufferManagerEntryImpl* const sb = getStaticByIndex(i);
if (sb == NULL)
{
break;
}
if (!sb->isEmpty())
{
res++;
}
}
return res;
}
}

View File

@ -48,7 +48,7 @@ struct NodeInitializerRemoteContext
TEST(NodeInitializer, Size)
{
std::cout << "sizeof(uavcan::NodeInitializer): " << sizeof(uavcan::NodeInitializer) << std::endl;
ASSERT_TRUE(sizeof(uavcan::NodeInitializer) < 1024);
ASSERT_TRUE(sizeof(uavcan::NodeInitializer) < 2048);
}