mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-04-14 10:07:39 +08:00
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:
parent
9e5115948b
commit
a8d12d2004
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user