Skip to content

Commit 722b1a4

Browse files
nits
1 parent 215d81c commit 722b1a4

3 files changed

Lines changed: 34 additions & 2 deletions

File tree

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ cmake_minimum_required(VERSION 3.20)
1010

1111
project(canard)
1212
enable_testing()
13-
13+
set(CMAKE_CTEST_ARGUMENTS "-V") # Enable test outputs when running `make test`
1414
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
1515

1616
# Shared Clang-Format target for all subprojects.

libcanard/canard.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,30 @@ static byte_t popcount(const uint64_t x)
133133
#endif
134134
}
135135

136+
/// See ctz().
137+
static byte_t ctz_emulated(uint32_t x)
138+
{
139+
CANARD_ASSERT(x != 0U);
140+
byte_t v = 0;
141+
while ((x & 1U) == 0U) {
142+
x >>= 1U;
143+
++v;
144+
}
145+
return v;
146+
}
147+
148+
/// Count trailing zeros (ctz), aka find first set (ffs), aka the index of the least-significant set bit.
149+
/// Undefined for zero argument.
150+
static byte_t ctz(const uint32_t x)
151+
{
152+
#if defined(__GNUC__) || defined(__clang__) || defined(__CC_ARM)
153+
CANARD_ASSERT(x != 0U);
154+
return (byte_t)__builtin_ctzl(x);
155+
#else
156+
return ctz_emulated(x);
157+
#endif
158+
}
159+
136160
static void* mem_alloc(const canard_mem_t memory, const size_t size) { return memory.vtable->alloc(memory, size); }
137161
static void* mem_alloc_zero(const canard_mem_t memory, const size_t size)
138162
{

libcanard/canard.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,15 @@ struct canard_t
389389
/// due to the limited bus capacity; at the same time, CAN is likely to be used with small memory-limited
390390
/// devices. Hence we introduce a design tradeoff favoring smaller memory footprint over insertion efficiency,
391391
/// which is reasonable on the assumption that the number of simultaneously enqueued transfers (sic! not frames)
392-
/// is typically small, on the order of a couple dozen at most.
392+
/// is typically small, on the order of a couple dozen at most. At small N, linked lists are even expected to
393+
/// outperform BST lookup; given r=2 is the approximate complexity premium of BST lookup over list scan,
394+
/// assuming that an average list lookup ends halfway, then the complexity crossover point is about:
395+
///
396+
/// N/2 > r log2(N)
397+
///
398+
/// So for r=2, we expect linked lists to outperform BSTs for less than about 15 pending transfers per shard
399+
/// (per default, RPC-service and message transfers use different shards, also each priority level is separate).
400+
/// The number of frames per transfer is irrelevant here as it doesn't affect the asymptotic complexity.
393401
///
394402
/// The structures are optimized to minimize the poll complexity, since it is on the hot path, at the expense
395403
/// of insertion and cancellation paths. Each pending queue is a simple FIFO; the priority ordering is done

0 commit comments

Comments
 (0)