Skip to content

Commit 0a443c8

Browse files
committed
samples: philosophers: Add statistics
Using the newly provided `sync::Mutex`, implement support for printing statistics about the philosophers habits. Remove the verbose message showing each meal, and replace with a period print of the statics. Change the sample.yml file with a regexp to make sure that all of the philosphers are able to eat at least a bit. Signed-off-by: David Brown <[email protected]>
1 parent 75a34de commit 0a443c8

File tree

2 files changed

+57
-10
lines changed

2 files changed

+57
-10
lines changed

samples/philosophers/sample.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ common:
66
harness_config:
77
type: one_line
88
regex:
9-
- "Child 5 thinking"
9+
# Match the statistics, and make sure that each philosopher has at least 10 (two digits)
10+
# meals.
11+
- "^\\[\\d{2,}, \\d{2,}, \\d{2,}, \\d{2,}, \\d{2,}, \\d{2,}\\]"
1012
tags: rust
1113
filter: CONFIG_RUST_SUPPORTED
1214
tests:

samples/philosophers/src/lib.rs

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@ extern crate alloc;
77

88
use alloc::boxed::Box;
99
use alloc::vec::Vec;
10+
use zephyr::object::KobjInit;
1011
use zephyr::time::{Duration, sleep, Tick};
1112
use zephyr::{
1213
printkln,
1314
kobj_define,
1415
sys::uptime_get,
15-
sync::Arc,
16+
sync::{Arc, Mutex},
1617
};
1718

1819
use crate::sysmutex::SysMutexSync;
@@ -51,6 +52,9 @@ extern "C" fn rust_main() {
5152
zephyr::kconfig::CONFIG_BOARD);
5253
printkln!("Time tick: {}", zephyr::time::SYS_FREQUENCY);
5354

55+
STAT_MUTEX.init();
56+
let stats = Arc::new(Mutex::new_from(Stats::default(), STAT_MUTEX.get()));
57+
5458
let syncers = get_syncer();
5559

5660
printkln!("Pre fork");
@@ -65,9 +69,9 @@ extern "C" fn rust_main() {
6569
let child_syncer = ChannelSync::new(cq_send.clone(), reply_queues[i].clone());
6670
let child_syncer = Arc::new(child_syncer);
6771
*/
68-
// let child_stat = stats.clone();
72+
let child_stat = stats.clone();
6973
let thread = PHIL_THREAD[i].spawn(PHIL_STACK[i].token(), move || {
70-
phil_thread(i, syncer /*, child_stat*/);
74+
phil_thread(i, syncer, child_stat);
7175
});
7276
thread.start();
7377
}
@@ -76,7 +80,7 @@ extern "C" fn rust_main() {
7680
loop {
7781
// Periodically, printout the stats.
7882
zephyr::time::sleep(delay);
79-
// stats.lock().unwrap().show();
83+
stats.lock().unwrap().show();
8084
}
8185
}
8286

@@ -92,7 +96,7 @@ fn get_syncer() -> Vec<Arc<dyn ForkSync>> {
9296
result
9397
}
9498

95-
fn phil_thread(n: usize, syncer: Arc<dyn ForkSync> /*, stats: Arc<Mutex<Stats>>*/) {
99+
fn phil_thread(n: usize, syncer: Arc<dyn ForkSync>, stats: Arc<Mutex<Stats>>) {
96100
printkln!("Child {} started: {:?}", n, syncer);
97101

98102
// Determine our two forks.
@@ -112,20 +116,58 @@ fn phil_thread(n: usize, syncer: Arc<dyn ForkSync> /*, stats: Arc<Mutex<Stats>>*
112116
syncer.take(forks.1);
113117

114118
let delay = get_random_delay(n, 25);
115-
printkln!("Child {} eating ({} ms)", n, delay);
119+
// printkln!("Child {} eating ({} ms)", n, delay);
116120
sleep(delay);
117-
// stats.lock().unwrap().record_eat(n, delay);
121+
stats.lock().unwrap().record_eat(n, delay);
118122

119123
// Release the forks.
120124
// printkln!("Child {} giving up forks", n);
121125
syncer.release(forks.1);
122126
syncer.release(forks.0);
123127

124128
let delay = get_random_delay(n, 25);
125-
printkln!("Child {} thinking ({} ms)", n, delay);
129+
// printkln!("Child {} thinking ({} ms)", n, delay);
126130
sleep(delay);
127-
// stats.lock().unwrap().record_think(n, delay);
131+
stats.lock().unwrap().record_think(n, delay);
132+
}
133+
}
134+
}
135+
136+
/// Instead of just printing out so much information that the data just scrolls by, gather statistics.
137+
#[derive(Default)]
138+
struct Stats {
139+
/// How many times each philospher has gone through the loop.
140+
count: [u64; NUM_PHIL],
141+
/// How much time each philosopher has spent eating.
142+
eating: [u64; NUM_PHIL],
143+
/// How much time each pilosopher has spent thinking.
144+
thinking: [u64; NUM_PHIL],
145+
}
146+
147+
impl Stats {
148+
fn record_eat(&mut self, index: usize, time: Duration) {
149+
self.eating[index] += time.to_millis();
150+
}
151+
152+
fn record_think(&mut self, index: usize, time: Duration) {
153+
self.thinking[index] += time.to_millis();
154+
self.count[index] += 1;
155+
}
156+
157+
fn show(&self) {
158+
printkln!("{:?}, e:{:?}, t:{:?}", self.count, self.eating, self.thinking);
159+
160+
/*
161+
// Invoke the thread analyzer report.
162+
{
163+
extern "C" {
164+
fn thread_analyzer_print(cpu: usize);
165+
}
166+
unsafe {
167+
thread_analyzer_print(0);
168+
}
128169
}
170+
*/
129171
}
130172
}
131173

@@ -141,4 +183,7 @@ fn get_random_delay(id: usize, period: usize) -> Duration {
141183
kobj_define! {
142184
static PHIL_THREAD: [StaticThread; NUM_PHIL];
143185
static PHIL_STACK: [ThreadStack<PHIL_STACK_SIZE>; NUM_PHIL];
186+
187+
// A mutex to hold statistics data.
188+
static STAT_MUTEX: StaticMutex;
144189
}

0 commit comments

Comments
 (0)