TransferReceiver optimization

This commit is contained in:
Pavel Kirienko
2015-06-20 22:39:39 +03:00
parent cb7f1ef460
commit 815337ab1f
3 changed files with 69 additions and 49 deletions
@@ -19,31 +19,41 @@ class UAVCAN_EXPORT TransferReceiver
public:
enum ResultCode { ResultNotComplete, ResultComplete, ResultSingleFrame };
static const uint32_t MinTransferIntervalUSec = 1 * 1000UL;
static const uint32_t MaxTransferIntervalUSec = 10 * 1000 * 1000UL;
static const uint32_t DefaultTransferIntervalUSec = 1 * 1000 * 1000UL;
static const uint16_t MinTransferIntervalMSec = 1;
static const uint16_t MaxTransferIntervalMSec = 0xFFFF;
static const uint16_t DefaultTransferIntervalMSec = 1000;
static MonotonicDuration getDefaultTransferInterval()
{
return MonotonicDuration::fromUSec(DefaultTransferIntervalUSec);
return MonotonicDuration::fromMSec(DefaultTransferIntervalMSec);
}
static MonotonicDuration getMinTransferInterval() { return MonotonicDuration::fromUSec(MinTransferIntervalUSec); }
static MonotonicDuration getMaxTransferInterval() { return MonotonicDuration::fromUSec(MaxTransferIntervalUSec); }
static MonotonicDuration getMinTransferInterval() { return MonotonicDuration::fromMSec(MinTransferIntervalMSec); }
static MonotonicDuration getMaxTransferInterval() { return MonotonicDuration::fromMSec(MaxTransferIntervalMSec); }
private:
enum TidRelation { TidSame, TidRepeat, TidFuture };
static const uint8_t IfaceIndexNotSet = 0xFF;
enum { IfaceIndexNotSet = MaxCanIfaces };
enum { BufferWritePosMask = 4095 };
enum { ErrorCntMask = 15 };
enum { IfaceIndexMask = MaxCanIfaces };
MonotonicTime prev_transfer_ts_;
MonotonicTime this_transfer_ts_;
UtcTime first_frame_ts_;
uint32_t transfer_interval_usec_;
uint16_t transfer_interval_msec_;
uint16_t this_transfer_crc_;
uint16_t buffer_write_pos_;
TransferID tid_;
uint8_t iface_index_;
uint8_t next_frame_index_;
mutable uint8_t error_cnt_;
// 2 byte aligned bitfields:
uint16_t buffer_write_pos_ : 12;
mutable uint16_t error_cnt_ : 4;
TransferID tid_; // 1 byte field
// 1 byte aligned bitfields:
uint8_t next_frame_index_ : 6;
uint8_t iface_index_ : 2;
bool isInitialized() const { return iface_index_ != IfaceIndexNotSet; }
@@ -59,14 +69,18 @@ private:
ResultCode receive(const RxFrame& frame, TransferBufferAccessor& tba);
public:
TransferReceiver()
: transfer_interval_usec_(DefaultTransferIntervalUSec)
, this_transfer_crc_(0)
, buffer_write_pos_(0)
, iface_index_(IfaceIndexNotSet)
, next_frame_index_(0)
, error_cnt_(0)
{ }
TransferReceiver() :
transfer_interval_msec_(DefaultTransferIntervalMSec),
this_transfer_crc_(0),
buffer_write_pos_(0),
error_cnt_(0),
next_frame_index_(0),
iface_index_(IfaceIndexNotSet)
{
#if UAVCAN_DEBUG
StaticAssert<sizeof(TransferReceiver) == 32>::check();
#endif
}
bool isTimedOut(MonotonicTime current_ts) const;
@@ -79,7 +93,7 @@ public:
uint16_t getLastTransferCrc() const { return this_transfer_crc_; }
MonotonicDuration getInterval() const { return MonotonicDuration::fromUSec(transfer_interval_usec_); }
MonotonicDuration getInterval() const { return MonotonicDuration::fromMSec(transfer_interval_msec_); }
};
UAVCAN_PACKED_END
@@ -11,21 +11,13 @@
namespace uavcan
{
const uint32_t TransferReceiver::MinTransferIntervalUSec;
const uint32_t TransferReceiver::MaxTransferIntervalUSec;
const uint32_t TransferReceiver::DefaultTransferIntervalUSec;
const uint8_t TransferReceiver::IfaceIndexNotSet;
const uint16_t TransferReceiver::MinTransferIntervalMSec;
const uint16_t TransferReceiver::MaxTransferIntervalMSec;
const uint16_t TransferReceiver::DefaultTransferIntervalMSec;
void TransferReceiver::registerError() const
{
if (error_cnt_ < 0xFF)
{
error_cnt_ = static_cast<uint8_t>(error_cnt_ + 1);
}
else
{
UAVCAN_ASSERT(0);
}
error_cnt_ = static_cast<uint8_t>(error_cnt_ + 1) & ErrorCntMask;
}
TransferReceiver::TidRelation TransferReceiver::getTidRelation(const RxFrame& frame) const
@@ -51,10 +43,10 @@ void TransferReceiver::updateTransferTimings()
if ((!prev_prev_ts.isZero()) && (!prev_transfer_ts_.isZero()) && (prev_transfer_ts_ >= prev_prev_ts))
{
uint64_t interval_usec = uint64_t((prev_transfer_ts_ - prev_prev_ts).toUSec());
interval_usec = min(interval_usec, uint64_t(MaxTransferIntervalUSec));
interval_usec = max(interval_usec, uint64_t(MinTransferIntervalUSec));
transfer_interval_usec_ = static_cast<uint32_t>((uint64_t(transfer_interval_usec_) * 7 + interval_usec) / 8);
uint64_t interval_msec = uint64_t((prev_transfer_ts_ - prev_prev_ts).toMSec());
interval_msec = min(interval_msec, uint64_t(MaxTransferIntervalMSec));
interval_msec = max(interval_msec, uint64_t(MinTransferIntervalMSec));
transfer_interval_msec_ = static_cast<uint16_t>((uint64_t(transfer_interval_msec_) * 7U + interval_msec) / 8U);
}
}
@@ -118,7 +110,7 @@ bool TransferReceiver::writePayload(const RxFrame& frame, ITransferBuffer& buf)
const bool success = res == static_cast<int>(effective_payload_len);
if (success)
{
buffer_write_pos_ = static_cast<uint16_t>(buffer_write_pos_ + effective_payload_len);
buffer_write_pos_ = static_cast<uint16_t>(buffer_write_pos_ + effective_payload_len) & BufferWritePosMask;
}
return success;
}
@@ -128,7 +120,7 @@ bool TransferReceiver::writePayload(const RxFrame& frame, ITransferBuffer& buf)
const bool success = res == static_cast<int>(payload_len);
if (success)
{
buffer_write_pos_ = static_cast<uint16_t>(buffer_write_pos_ + payload_len);
buffer_write_pos_ = static_cast<uint16_t>(buffer_write_pos_ + payload_len) & BufferWritePosMask;
}
return success;
}
@@ -186,12 +178,12 @@ TransferReceiver::ResultCode TransferReceiver::receive(const RxFrame& frame, Tra
bool TransferReceiver::isTimedOut(MonotonicTime current_ts) const
{
static const int64_t INTERVAL_MULT = (1 << TransferID::BitLen) / 2 + 1;
static const int64_t IntervalMult = (1 << TransferID::BitLen) / 2 + 1;
if (current_ts <= this_transfer_ts_)
{
return false;
}
return (current_ts - this_transfer_ts_).toUSec() > (int64_t(transfer_interval_usec_) * INTERVAL_MULT);
return (current_ts - this_transfer_ts_).toUSec() > (int64_t(transfer_interval_msec_) * 1000 * IntervalMult);
}
TransferReceiver::ResultCode TransferReceiver::addFrame(const RxFrame& frame, TransferBufferAccessor& tba)
@@ -209,7 +201,7 @@ TransferReceiver::ResultCode TransferReceiver::addFrame(const RxFrame& frame, Tr
const bool first_fame = frame.isFirst();
const TidRelation tid_rel = getTidRelation(frame);
const bool iface_timed_out =
(frame.getMonotonicTimestamp() - this_transfer_ts_).toUSec() > (int64_t(transfer_interval_usec_) * 2);
(frame.getMonotonicTimestamp() - this_transfer_ts_).toUSec() > (int64_t(transfer_interval_msec_) * 1000 * 2);
// FSM, the hard way
const bool need_restart =
@@ -230,7 +222,7 @@ TransferReceiver::ResultCode TransferReceiver::addFrame(const RxFrame& frame, Tr
int(not_initialized), int(iface_timed_out), int(receiver_timed_out), int(same_iface),
int(first_fame), int(tid_rel), frame.toString().c_str());
tba.remove();
iface_index_ = frame.getIfaceIndex();
iface_index_ = frame.getIfaceIndex() & IfaceIndexMask;
tid_ = frame.getTransferID();
next_frame_index_ = 0;
buffer_write_pos_ = 0;
+19 -5
View File
@@ -144,8 +144,8 @@ TEST(TransferReceiver, Basic)
ASSERT_TRUE(matchBufferContent(bufmgr.access(gen.bufmgr_key), "345678abcdefgh"));
ASSERT_EQ(0x789A, rcv.getLastTransferCrc());
ASSERT_GT(TransferReceiver::getDefaultTransferInterval(), rcv.getInterval());
ASSERT_LT(TransferReceiver::getMinTransferInterval(), rcv.getInterval());
ASSERT_GE(TransferReceiver::getDefaultTransferInterval(), rcv.getInterval());
ASSERT_LE(TransferReceiver::getMinTransferInterval(), rcv.getInterval());
ASSERT_EQ(1000, rcv.getLastTransferTimestampMonotonic().toUSec());
ASSERT_FALSE(rcv.isTimedOut(tsMono(1000)));
ASSERT_FALSE(rcv.isTimedOut(tsMono(5000)));
@@ -174,33 +174,47 @@ TEST(TransferReceiver, Basic)
CHECK_SINGLE_FRAME(rcv.addFrame(gen(0, "", 0, true, 4, 3600), bk));
ASSERT_EQ(3600, rcv.getLastTransferTimestampMonotonic().toUSec());
std::cout << "Interval: " << rcv.getInterval().toString() << std::endl;
/*
* Timeouts
*/
CHECK_NOT_COMPLETE(rcv.addFrame(gen(1, "qwe", 0, true, 1, 100000), bk)); // Wrong iface - ignored
CHECK_NOT_COMPLETE(rcv.addFrame(gen(1, "qwe", 0, true, 1, 5000), bk)); // Wrong iface - ignored
CHECK_SINGLE_FRAME(rcv.addFrame(gen(1, "qwe", 0, true, 6, 1500000), bk)); // Accepted due to iface timeout
ASSERT_EQ(1500000, rcv.getLastTransferTimestampMonotonic().toUSec());
std::cout << "Interval: " << rcv.getInterval().toString() << std::endl;
CHECK_NOT_COMPLETE(rcv.addFrame(gen(0, "qwe", 0, true, 7, 1500100), bk)); // Ignored - old iface 0
CHECK_SINGLE_FRAME(rcv.addFrame(gen(1, "qwe", 0, true, 7, 1500100), bk));
ASSERT_EQ(1500100, rcv.getLastTransferTimestampMonotonic().toUSec());
std::cout << "Interval: " << rcv.getInterval().toString() << std::endl;
CHECK_NOT_COMPLETE(rcv.addFrame(gen(1, "qwe", 0, true, 7, 1500100), bk)); // Old TID
CHECK_SINGLE_FRAME(rcv.addFrame(gen(0, "qwe", 0, true, 7, 100000000), bk)); // Accepted - global timeout
ASSERT_EQ(100000000, rcv.getLastTransferTimestampMonotonic().toUSec());
std::cout << "Interval: " << rcv.getInterval().toString() << std::endl;
CHECK_SINGLE_FRAME(rcv.addFrame(gen(0, "qwe", 0, true, 0, 100000100), bk));
ASSERT_EQ(100000100, rcv.getLastTransferTimestampMonotonic().toUSec());
std::cout << "Interval: " << rcv.getInterval().toString() << std::endl;
ASSERT_TRUE(rcv.isTimedOut(tsMono(900000000)));
CHECK_NOT_COMPLETE(rcv.addFrame(gen(1, "\x78\x56" "345678", 0, false, 0, 900000000), bk)); // Global timeout
CHECK_NOT_COMPLETE(rcv.addFrame(gen(0, "12345678", 0, false, 0, 900000100), bk)); // Wrong iface
CHECK_NOT_COMPLETE(rcv.addFrame(gen(0, "qwe", 1, true, 0, 900000200), bk)); // Wrong iface
CHECK_COMPLETE( rcv.addFrame(gen(1, "qwe", 1, true, 0, 900000200), bk));
ASSERT_EQ(900000000, rcv.getLastTransferTimestampMonotonic().toUSec());
std::cout << "Interval: " << rcv.getInterval().toString() << std::endl;
ASSERT_FALSE(rcv.isTimedOut(tsMono(1000)));
ASSERT_FALSE(rcv.isTimedOut(tsMono(900000200)));
ASSERT_TRUE(rcv.isTimedOut(tsMono(1000 * 1000000)));
ASSERT_FALSE(rcv.isTimedOut(tsMono(900000300)));
ASSERT_TRUE(rcv.isTimedOut(tsMono(990000000)));
ASSERT_LT(TransferReceiver::getDefaultTransferInterval(), rcv.getInterval());
ASSERT_LE(TransferReceiver::getMinTransferInterval(), rcv.getInterval());
ASSERT_GE(TransferReceiver::getMaxTransferInterval(), rcv.getInterval());