Skip to content

Commit 70fe87c

Browse files
committed
samples: bench: Make Semaphores static
Although there is still a lot of allocation left (the crossbeam API for channels is kind of built around it), convert the Semaphores in the benchmark to be static. This reduces overhead a little bit, because the reference counts of Arc don't need to be maintained, and also demonstrates how StaticCell can be used to allocate things like arrays of objects statically. Signed-off-by: David Brown <[email protected]>
1 parent 2bca101 commit 70fe87c

File tree

2 files changed

+41
-32
lines changed

2 files changed

+41
-32
lines changed

samples/bench/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ crate-type = ["staticlib"]
1515
[dependencies]
1616
zephyr = "0.1.0"
1717
critical-section = "1.1.2"
18+
heapless = "0.8"
19+
static_cell = "2.1"
1820

1921
# Dependencies that are used by build.rs.
2022
[build-dependencies]

samples/bench/src/lib.rs

Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use core::pin::Pin;
1515
use alloc::collections::vec_deque::VecDeque;
1616
use alloc::vec;
1717
use alloc::vec::Vec;
18+
use static_cell::StaticCell;
1819
use zephyr::sync::SpinMutex;
1920
use zephyr::time::NoWait;
2021
use zephyr::work::futures::work_size;
@@ -47,6 +48,9 @@ const WORK_STACK_SIZE: usize = 2048;
4748
const TOTAL_ITERS: usize = 1_000;
4849
// const TOTAL_ITERS: usize = 10_000;
4950

51+
/// A heapless::Vec, with a maximum size of the number of threads chosen above.
52+
type HeaplessVec<T> = heapless::Vec<T, NUM_THREADS>;
53+
5054
#[no_mangle]
5155
extern "C" fn rust_main() {
5256
let tester = ThreadTests::new(NUM_THREADS);
@@ -101,17 +105,17 @@ extern "C" fn rust_main() {
101105
/// low priority task is providing the data.
102106
struct ThreadTests {
103107
/// Each test thread gets a semaphore, to use as appropriate for that test.
104-
sems: Vec<Arc<Semaphore>>,
108+
sems: HeaplessVec<&'static Semaphore>,
105109

106110
/// This semaphore is used to ping-ping back to another thread.
107-
back_sems: Vec<Arc<Semaphore>>,
111+
back_sems: HeaplessVec<&'static Semaphore>,
108112

109113
/// Each test also has a message queue, for testing, that it has sender and receiver for.
110-
chans: Vec<ChanPair<u32>>,
114+
chans: HeaplessVec<ChanPair<u32>>,
111115

112116
/// In addition, each test has a channel it owns the receiver for that listens for commands
113117
/// about what test to run.
114-
commands: Vec<Sender<Command>>,
118+
commands: HeaplessVec<Sender<Command>>,
115119

116120
/// Low and high also take commands.
117121
low_command: Sender<Command>,
@@ -145,10 +149,10 @@ impl ThreadTests {
145149
let _ = Arc::into_raw(workq.clone());
146150

147151
let mut result = Self {
148-
sems: Vec::new(),
149-
back_sems: Vec::new(),
150-
chans: Vec::new(),
151-
commands: Vec::new(),
152+
sems: HeaplessVec::new(),
153+
back_sems: HeaplessVec::new(),
154+
chans: HeaplessVec::new(),
155+
commands: HeaplessVec::new(),
152156
results: ChanPair::new_unbounded(),
153157
low_command: low_send,
154158
high_command: high_send,
@@ -157,18 +161,21 @@ impl ThreadTests {
157161

158162
let mut thread_commands = Vec::new();
159163

160-
for _ in 0..count {
161-
let sem = Arc::new(Semaphore::new(0, u32::MAX));
162-
result.sems.push(sem.clone());
164+
static SEMS: [StaticCell<Semaphore>; NUM_THREADS] = [const { StaticCell::new() }; NUM_THREADS];
165+
static BACK_SEMS: [StaticCell<Semaphore>; NUM_THREADS] = [const { StaticCell::new() }; NUM_THREADS];
163166

164-
let sem = Arc::new(Semaphore::new(0, u32::MAX));
165-
result.back_sems.push(sem);
167+
for i in 0..count {
168+
let sem = SEMS[i].init(Semaphore::new(0, u32::MAX));
169+
result.sems.push(sem).unwrap();
170+
171+
let sem = BACK_SEMS[i].init(Semaphore::new(0, u32::MAX));
172+
result.back_sems.push(sem).unwrap();
166173

167174
let chans = ChanPair::new_bounded(1);
168-
result.chans.push(chans.clone());
175+
result.chans.push(chans.clone()).unwrap();
169176

170177
let (csend, crecv) = bounded(1);
171-
result.commands.push(csend);
178+
result.commands.push(csend).unwrap();
172179
thread_commands.push(crecv);
173180
}
174181

@@ -213,8 +220,8 @@ impl ThreadTests {
213220
work_size(Self::ping_pong_worker_async(
214221
result.clone(),
215222
0,
216-
result.sems[0].clone(),
217-
result.back_sems[0].clone(),
223+
result.sems[0],
224+
result.back_sems[0],
218225
6
219226
))
220227
);
@@ -348,7 +355,7 @@ impl ThreadTests {
348355
// ourselves.
349356
Command::SimpleSemAsync(count) => {
350357
spawn(
351-
Self::simple_sem_async(this.clone(), id, this.sems[id].clone(), count),
358+
Self::simple_sem_async(this.clone(), id, this.sems[id], count),
352359
&this.workq,
353360
c"worker",
354361
);
@@ -360,7 +367,7 @@ impl ThreadTests {
360367
Self::simple_sem_yield_async(
361368
this.clone(),
362369
id,
363-
this.sems[id].clone(),
370+
this.sems[id],
364371
count,
365372
),
366373
&this.workq,
@@ -371,7 +378,7 @@ impl ThreadTests {
371378

372379
Command::SemWaitAsync(count) => {
373380
spawn(
374-
Self::sem_take_async(this.clone(), id, this.sems[id].clone(), count),
381+
Self::sem_take_async(this.clone(), id, this.sems[id], count),
375382
&this.workq,
376383
c"worker",
377384
);
@@ -380,7 +387,7 @@ impl ThreadTests {
380387

381388
Command::SemWaitSameAsync(count) => {
382389
spawn(
383-
Self::sem_take_async(this.clone(), id, this.sems[id].clone(), count),
390+
Self::sem_take_async(this.clone(), id, this.sems[id], count),
384391
&this.workq,
385392
c"worker",
386393
);
@@ -399,8 +406,8 @@ impl ThreadTests {
399406
Self::ping_pong_worker_async(
400407
this.clone(),
401408
id,
402-
this.sems[id].clone(),
403-
this.back_sems[id].clone(),
409+
this.sems[id],
410+
this.back_sems[id],
404411
count,
405412
),
406413
&this.workq,
@@ -424,8 +431,8 @@ impl ThreadTests {
424431
Self::ping_pong_worker_async(
425432
this.clone(),
426433
th,
427-
this.sems[0].clone(),
428-
this.back_sems[0].clone(),
434+
this.sems[0],
435+
this.back_sems[0],
429436
count,
430437
),
431438
&this.workq,
@@ -464,7 +471,7 @@ impl ThreadTests {
464471
}
465472
}
466473

467-
async fn simple_sem_async(this: Arc<Self>, id: usize, sem: Arc<Semaphore>, count: usize) {
474+
async fn simple_sem_async(this: Arc<Self>, id: usize, sem: &'static Semaphore, count: usize) {
468475
for _ in 0..count {
469476
sem.give();
470477
sem.take_async(NoWait).await.unwrap();
@@ -477,7 +484,7 @@ impl ThreadTests {
477484
.unwrap();
478485
}
479486

480-
async fn simple_sem_yield_async(this: Arc<Self>, id: usize, sem: Arc<Semaphore>, count: usize) {
487+
async fn simple_sem_yield_async(this: Arc<Self>, id: usize, sem: &'static Semaphore, count: usize) {
481488
for _ in 0..count {
482489
sem.give();
483490
sem.take_async(NoWait).await.unwrap();
@@ -509,7 +516,7 @@ impl ThreadTests {
509516
}
510517
}
511518

512-
async fn sem_take_async(this: Arc<Self>, id: usize, sem: Arc<Semaphore>, count: usize) {
519+
async fn sem_take_async(this: Arc<Self>, id: usize, sem: &'static Semaphore, count: usize) {
513520
for _ in 0..count {
514521
// Enable this to verify that we are actually blocking.
515522
if false {
@@ -551,8 +558,8 @@ impl ThreadTests {
551558
async fn ping_pong_worker_async(
552559
this: Arc<Self>,
553560
id: usize,
554-
sem: Arc<Semaphore>,
555-
back_sem: Arc<Semaphore>,
561+
sem: &'static Semaphore,
562+
back_sem: &'static Semaphore,
556563
count: usize,
557564
) {
558565
for i in 0..count {
@@ -615,7 +622,7 @@ impl ThreadTests {
615622
// No reply.
616623
}
617624

618-
async fn sem_giver_async(this: Arc<Self>, sems: Vec<Arc<Semaphore>>, count: usize) {
625+
async fn sem_giver_async(this: Arc<Self>, sems: HeaplessVec<&'static Semaphore>, count: usize) {
619626
for _ in 0..count {
620627
for sem in &sems {
621628
sem.give();
@@ -699,7 +706,7 @@ impl ThreadTests {
699706
}
700707
}
701708

702-
#[derive(Clone)]
709+
#[derive(Clone, Debug)]
703710
struct ChanPair<T> {
704711
sender: Sender<T>,
705712
receiver: Receiver<T>,

0 commit comments

Comments
 (0)