From 2798252fd442cc6ac47e921729d5deb5ca20e344 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Wed, 26 Mar 2014 18:17:25 +0400 Subject: [PATCH] CAN IO perf counters --- libuavcan/include/uavcan/driver/can.hpp | 4 +- libuavcan/include/uavcan/transport/can_io.hpp | 34 +++++++++++--- libuavcan/src/transport/can_io.cpp | 18 ++++++-- libuavcan/test/node/test_node.hpp | 2 +- libuavcan/test/transport/can/can.hpp | 2 +- libuavcan/test/transport/can/io.cpp | 45 ++++++++++++++----- libuavcan/test/transport/can/tx_queue.cpp | 14 +++--- 7 files changed, 89 insertions(+), 30 deletions(-) diff --git a/libuavcan/include/uavcan/driver/can.hpp b/libuavcan/include/uavcan/driver/can.hpp index d0a051035c..74171adf71 100644 --- a/libuavcan/include/uavcan/driver/can.hpp +++ b/libuavcan/include/uavcan/driver/can.hpp @@ -142,9 +142,9 @@ public: virtual int getNumFilters() const = 0; /** - * Continuously incrementing counter of detected hardware errors. + * Continuously incrementing counter of hardware errors. */ - virtual uint64_t getNumErrors() const = 0; + virtual uint64_t getErrorCount() const = 0; }; /** diff --git a/libuavcan/include/uavcan/transport/can_io.hpp b/libuavcan/include/uavcan/transport/can_io.hpp index c162566a37..c6a28daf1f 100644 --- a/libuavcan/include/uavcan/transport/can_io.hpp +++ b/libuavcan/include/uavcan/transport/can_io.hpp @@ -110,22 +110,44 @@ public: bool topPriorityHigherOrEqual(const CanFrame& rhs_frame) const; - uint32_t getNumRejectedFrames() const { return rejected_frames_cnt_; } + uint32_t getRejectedFrameCount() const { return rejected_frames_cnt_; } bool isEmpty() const { return queue_.isEmpty(); } }; +struct CanIfacePerfCounters +{ + uint64_t frames_tx; + uint64_t frames_rx; + uint64_t errors; + + CanIfacePerfCounters() + : frames_tx(0) + , frames_rx(0) + , errors(0) + { } +}; + + class CanIOManager : Noncopyable { + struct IfaceFrameCounters + { + uint64_t frames_tx; + uint64_t frames_rx; + + IfaceFrameCounters() + : frames_tx(0) + , frames_rx(0) + { } + }; + ICanDriver& driver_; ISystemClock& sysclock_; CanTxQueue tx_queues_[MaxCanIfaces]; - - // Noncopyable - CanIOManager(CanIOManager&); - CanIOManager& operator=(CanIOManager&); + IfaceFrameCounters counters_[MaxCanIfaces]; int sendToIface(int iface_index, const CanFrame& frame, MonotonicTime tx_deadline, CanIOFlags flags); int sendFromTxQueue(int iface_index); @@ -147,7 +169,7 @@ public: int getNumIfaces() const; - uint64_t getNumErrors(int iface_index) const; + CanIfacePerfCounters getIfacePerfCounters(int iface_index) const; /** * Returns: diff --git a/libuavcan/src/transport/can_io.cpp b/libuavcan/src/transport/can_io.cpp index afd01a71bc..36bc6190ea 100644 --- a/libuavcan/src/transport/can_io.cpp +++ b/libuavcan/src/transport/can_io.cpp @@ -227,6 +227,10 @@ int CanIOManager::sendToIface(int iface_index, const CanFrame& frame, MonotonicT UAVCAN_TRACE("CanIOManager", "Send failed: code %i, iface %i, frame %s", res, iface_index, frame.toString().c_str()); } + if (res > 0) + { + counters_[iface_index].frames_tx += res; + } return res; } @@ -266,15 +270,19 @@ int CanIOManager::getNumIfaces() const return std::min(std::max(num, 0), (int)MaxCanIfaces); } -uint64_t CanIOManager::getNumErrors(int iface_index) const +CanIfacePerfCounters CanIOManager::getIfacePerfCounters(int iface_index) const { ICanIface* const iface = driver_.getIface(iface_index); if (iface == NULL || iface_index >= MaxCanIfaces || iface_index < 0) { assert(0); - return std::numeric_limits::max(); + return CanIfacePerfCounters(); } - return iface->getNumErrors() + tx_queues_[iface_index].getNumRejectedFrames(); + CanIfacePerfCounters cnt; + cnt.errors = iface->getErrorCount() + tx_queues_[iface_index].getRejectedFrameCount(); + cnt.frames_rx = counters_[iface_index].frames_rx; + cnt.frames_tx = counters_[iface_index].frames_tx; + return cnt; } int CanIOManager::send(const CanFrame& frame, MonotonicTime tx_deadline, MonotonicTime blocking_deadline, @@ -406,6 +414,10 @@ int CanIOManager::receive(CanRxFrame& out_frame, MonotonicTime blocking_deadline continue; } out_frame.iface_index = i; + if ((res > 0) && !(out_flags & CanIOFlagLoopback)) + { + counters_[i].frames_rx += 1; + } return res; } } diff --git a/libuavcan/test/node/test_node.hpp b/libuavcan/test/node/test_node.hpp index 730ebc0e54..db18cdfd92 100644 --- a/libuavcan/test/node/test_node.hpp +++ b/libuavcan/test/node/test_node.hpp @@ -122,7 +122,7 @@ struct PairableCanDriver : public uavcan::ICanDriver, public uavcan::ICanIface int configureFilters(const uavcan::CanFilterConfig*, int) { return -1; } int getNumFilters() const { return 0; } - uint64_t getNumErrors() const { return 0; } + uint64_t getErrorCount() const { return 0; } }; diff --git a/libuavcan/test/transport/can/can.hpp b/libuavcan/test/transport/can/can.hpp index 41d0d33b25..4bd574a05d 100644 --- a/libuavcan/test/transport/can/can.hpp +++ b/libuavcan/test/transport/can/can.hpp @@ -152,7 +152,7 @@ public: int configureFilters(const uavcan::CanFilterConfig*, int) { return -1; } // cppcheck-suppress unusedFunction int getNumFilters() const { return 0; } - uint64_t getNumErrors() const { return num_errors; } + uint64_t getErrorCount() const { return num_errors; } }; class CanDriverMock : public uavcan::ICanDriver diff --git a/libuavcan/test/transport/can/io.cpp b/libuavcan/test/transport/can/io.cpp index c3cc09396c..da007016f7 100644 --- a/libuavcan/test/transport/can/io.cpp +++ b/libuavcan/test/transport/can/io.cpp @@ -91,7 +91,7 @@ TEST(CanIOManager, Reception) EXPECT_EQ(0, flags); /* - * Errors + * Perf counters */ driver.select_failure = true; EXPECT_EQ(-1, iomgr.receive(frame, uavcan::MonotonicTime(), flags)); @@ -103,8 +103,14 @@ TEST(CanIOManager, Reception) driver.ifaces.at(0).num_errors = 9000; driver.ifaces.at(1).num_errors = 100500; - EXPECT_EQ(9000, iomgr.getNumErrors(0)); - EXPECT_EQ(100500, iomgr.getNumErrors(1)); + EXPECT_EQ(9000, iomgr.getIfacePerfCounters(0).errors); + EXPECT_EQ(100500, iomgr.getIfacePerfCounters(1).errors); + + EXPECT_EQ(3, iomgr.getIfacePerfCounters(0).frames_rx); + EXPECT_EQ(3, iomgr.getIfacePerfCounters(1).frames_rx); + + EXPECT_EQ(0, iomgr.getIfacePerfCounters(0).frames_tx); + EXPECT_EQ(0, iomgr.getIfacePerfCounters(1).frames_tx); } TEST(CanIOManager, Transmission) @@ -149,8 +155,8 @@ TEST(CanIOManager, Transmission) EXPECT_EQ(0, clockmock.utc); EXPECT_TRUE(driver.ifaces.at(0).tx.empty()); EXPECT_TRUE(driver.ifaces.at(1).tx.empty()); - EXPECT_EQ(0, iomgr.getNumErrors(0)); - EXPECT_EQ(0, iomgr.getNumErrors(1)); + EXPECT_EQ(0, iomgr.getIfacePerfCounters(0).errors); + EXPECT_EQ(0, iomgr.getIfacePerfCounters(1).errors); /* * TX Queue basics @@ -204,9 +210,9 @@ TEST(CanIOManager, Transmission) // Final checks EXPECT_TRUE(driver.ifaces.at(0).tx.empty()); EXPECT_TRUE(driver.ifaces.at(1).tx.empty()); - EXPECT_EQ(0, pool.getNumUsedBlocks()); // Make sure the memory was properly released - EXPECT_EQ(1, iomgr.getNumErrors(0)); // This is because of expired frame[0] - EXPECT_EQ(0, iomgr.getNumErrors(1)); + EXPECT_EQ(0, pool.getNumUsedBlocks()); // Make sure the memory was properly released + EXPECT_EQ(1, iomgr.getIfacePerfCounters(0).errors); // This is because of expired frame[0] + EXPECT_EQ(0, iomgr.getIfacePerfCounters(1).errors); /* * TX Queue updates from receive() call @@ -254,8 +260,8 @@ TEST(CanIOManager, Transmission) EXPECT_EQ(1200, clockmock.utc); EXPECT_TRUE(driver.ifaces.at(0).tx.empty()); EXPECT_TRUE(driver.ifaces.at(1).tx.empty()); - EXPECT_EQ(1, iomgr.getNumErrors(0)); - EXPECT_EQ(1, iomgr.getNumErrors(1)); // This is because of rejected frame[1] + EXPECT_EQ(1, iomgr.getIfacePerfCounters(0).errors); + EXPECT_EQ(1, iomgr.getIfacePerfCounters(1).errors); // This is because of rejected frame[1] /* * Error handling @@ -287,6 +293,15 @@ TEST(CanIOManager, Transmission) EXPECT_TRUE(driver.ifaces.at(1).matchAndPopTx(frames[0], 2200)); EXPECT_EQ(0, pool.getNumUsedBlocks()); // All transmitted ASSERT_EQ(0, flags); + + /* + * Perf counters + */ + EXPECT_EQ(1, iomgr.getIfacePerfCounters(0).frames_rx); + EXPECT_EQ(1, iomgr.getIfacePerfCounters(1).frames_rx); + + EXPECT_EQ(6, iomgr.getIfacePerfCounters(0).frames_tx); + EXPECT_EQ(8, iomgr.getIfacePerfCounters(1).frames_tx); } TEST(CanIOManager, Loopback) @@ -335,6 +350,16 @@ TEST(CanIOManager, Loopback) ASSERT_EQ(uavcan::CanIOFlagLoopback, flags); ASSERT_TRUE(rfr1 == fr1); ASSERT_TRUE(rfr2 == fr2); + + /* + * Perf counters + * Loopback frames are not registered as RX + */ + EXPECT_EQ(0, iomgr.getIfacePerfCounters(0).frames_rx); + EXPECT_EQ(0, iomgr.getIfacePerfCounters(1).frames_rx); + + EXPECT_EQ(3, iomgr.getIfacePerfCounters(0).frames_tx); + EXPECT_EQ(0, iomgr.getIfacePerfCounters(1).frames_tx); } TEST(CanIOManager, Size) diff --git a/libuavcan/test/transport/can/tx_queue.cpp b/libuavcan/test/transport/can/tx_queue.cpp index 3655516a1f..44a7ec5a64 100644 --- a/libuavcan/test/transport/can/tx_queue.cpp +++ b/libuavcan/test/transport/can/tx_queue.cpp @@ -112,7 +112,7 @@ TEST(CanTxQueue, TxQueue) // Out of free memory now - EXPECT_EQ(0, queue.getNumRejectedFrames()); + EXPECT_EQ(0, queue.getRejectedFrameCount()); EXPECT_EQ(4, getQueueLength(queue)); EXPECT_TRUE(isInQueue(queue, f0)); EXPECT_TRUE(isInQueue(queue, f1)); @@ -137,7 +137,7 @@ TEST(CanTxQueue, TxQueue) EXPECT_TRUE(isInQueue(queue, f2)); EXPECT_FALSE(isInQueue(queue, f1)); EXPECT_EQ(4, getQueueLength(queue)); - EXPECT_EQ(2, queue.getNumRejectedFrames()); + EXPECT_EQ(2, queue.getRejectedFrameCount()); EXPECT_EQ(f0, queue.peek()->frame); // Check the priority queue.push(f5, tsMono(600), CanTxQueue::Persistent, flags); // Will override f0 (rest are presistent) @@ -159,7 +159,7 @@ TEST(CanTxQueue, TxQueue) EXPECT_TRUE(queue.topPriorityHigherOrEqual(f5a)); EXPECT_EQ(4, getQueueLength(queue)); EXPECT_EQ(4, pool32.getNumUsedBlocks()); - EXPECT_EQ(5, queue.getNumRejectedFrames()); + EXPECT_EQ(5, queue.getRejectedFrameCount()); EXPECT_TRUE(isInQueue(queue, f2)); EXPECT_TRUE(isInQueue(queue, f3)); EXPECT_TRUE(isInQueue(queue, f4)); @@ -173,19 +173,19 @@ TEST(CanTxQueue, TxQueue) queue.push(f0, tsMono(800), CanTxQueue::Volatile, flags); // Will replace f4 which is expired now EXPECT_TRUE(isInQueue(queue, f0)); EXPECT_FALSE(isInQueue(queue, f4)); - EXPECT_EQ(6, queue.getNumRejectedFrames()); + EXPECT_EQ(6, queue.getRejectedFrameCount()); clockmock.monotonic = 1001; queue.push(f5, tsMono(2000), CanTxQueue::Volatile, flags); // Entire queue is expired EXPECT_TRUE(isInQueue(queue, f5)); EXPECT_EQ(1, getQueueLength(queue)); // Just one entry left - f5 EXPECT_EQ(1, pool32.getNumUsedBlocks()); // Make sure there is no leaks - EXPECT_EQ(10, queue.getNumRejectedFrames()); + EXPECT_EQ(10, queue.getRejectedFrameCount()); queue.push(f0, tsMono(1000), CanTxQueue::Persistent, flags); // This entry is already expired EXPECT_EQ(1, getQueueLength(queue)); EXPECT_EQ(1, pool32.getNumUsedBlocks()); - EXPECT_EQ(11, queue.getNumRejectedFrames()); + EXPECT_EQ(11, queue.getRejectedFrameCount()); /* * Removing @@ -212,7 +212,7 @@ TEST(CanTxQueue, TxQueue) EXPECT_EQ(0, getQueueLength(queue)); // Final state checks EXPECT_EQ(0, pool32.getNumUsedBlocks()); - EXPECT_EQ(11, queue.getNumRejectedFrames()); + EXPECT_EQ(11, queue.getRejectedFrameCount()); EXPECT_FALSE(queue.peek()); EXPECT_FALSE(queue.topPriorityHigherOrEqual(f0)); }