Skip to content

Commit 7bfdaf4

Browse files
committed
better metrics interpolation #10
1 parent c1955f7 commit 7bfdaf4

File tree

5 files changed

+91
-52
lines changed

5 files changed

+91
-52
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
.DS_Store
22
/target
33
/internal
4+
__handlers__/

src/app.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ fn run_inputs_thread(tx: mpsc::Sender<Event>, tick: u64) {
141141
let mut last_tick = Instant::now();
142142

143143
loop {
144-
if event::poll(Duration::from_millis(100)).unwrap() {
144+
if event::poll(Duration::from_millis(tick)).unwrap() {
145145
match event::read().unwrap() {
146146
event::Event::Key(key) => handle_key_event(&key, &tx).unwrap(),
147147
_ => {}
@@ -158,15 +158,15 @@ fn run_inputs_thread(tx: mpsc::Sender<Event>, tick: u64) {
158158

159159
fn run_sampler_thread(tx: mpsc::Sender<Event>, interval: u64) {
160160
let interval = interval.max(100).min(10000);
161-
let sample_duration = 80;
162161

163162
std::thread::spawn(move || {
164163
let mut sampler = Sampler::new().unwrap();
165164

165+
// Send initial metrics
166+
tx.send(Event::Update(sampler.get_metrics(100).unwrap())).unwrap();
167+
166168
loop {
167-
let metrics = sampler.get_metrics(sample_duration).unwrap();
168-
tx.send(Event::Update(metrics)).unwrap();
169-
std::thread::sleep(Duration::from_millis(interval - sample_duration));
169+
tx.send(Event::Update(sampler.get_metrics(interval).unwrap())).unwrap();
170170
}
171171
});
172172
}
@@ -346,7 +346,6 @@ impl App {
346346
self.render_freq_block(f, c2, "GPU", &self.igpu_freq);
347347

348348
// 3rd row
349-
350349
let label_l = format!(
351350
"Power: {:.2}W (avg {:.2}W, max {:.2}W)",
352351
self.all_power.top_value, self.all_power.avg_value, self.all_power.max_value,
@@ -380,7 +379,7 @@ impl App {
380379

381380
pub fn run_loop(&mut self, interval: u64) -> WithError<()> {
382381
let (tx, rx) = mpsc::channel::<Event>();
383-
run_inputs_thread(tx.clone(), 200);
382+
run_inputs_thread(tx.clone(), 250);
384383
run_sampler_thread(tx.clone(), interval);
385384

386385
let mut term = enter_term();

src/main.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,7 @@ fn main() -> Result<(), Box<dyn Error>> {
4040
let mut sampler = Sampler::new()?;
4141

4242
loop {
43-
let metrics = sampler.get_metrics(msec)?;
44-
println!("{:?}", metrics);
43+
println!("{:?}", sampler.get_metrics(msec)?);
4544
}
4645
}
4746
Some(Commands::Debug) => debug::print_debug()?,

src/metrics.rs

Lines changed: 47 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -214,58 +214,63 @@ impl Sampler {
214214
}
215215

216216
pub fn get_metrics(&mut self, duration: u64) -> WithError<Metrics> {
217-
let mut rs = Metrics::default();
218-
219-
let mut ecpu_usages = Vec::new();
220-
let mut pcpu_usages = Vec::new();
221-
222-
for x in self.ior.get_sample(duration) {
223-
// if x.group == "CPU Stats" && x.subgroup == CPU_FREQ_DICE_SUBG {
224-
// match x.channel.as_str() {
225-
// "ECPU" => rs.ecpu_usage = calc_freq(x.item, &self.soc.ecpu_freqs),
226-
// "PCPU" => rs.pcpu_usage = calc_freq(x.item, &self.soc.pcpu_freqs),
227-
// _ => {}
228-
// }
229-
// }
230-
231-
if x.group == "CPU Stats" && x.subgroup == CPU_FREQ_CORE_SUBG {
232-
if x.channel.contains("ECPU") {
233-
ecpu_usages.push(calc_freq(x.item, &self.soc.ecpu_freqs));
234-
continue;
217+
let measures: usize = 4;
218+
let mut results: Vec<Metrics> = Vec::with_capacity(measures);
219+
220+
// do several samples to smooth metrics
221+
// see: https://github.com/vladkens/macmon/issues/10
222+
for (sample, sample_dt) in self.ior.get_samples(duration, measures) {
223+
let mut ecpu_usages = Vec::new();
224+
let mut pcpu_usages = Vec::new();
225+
let mut rs = Metrics::default();
226+
227+
for x in sample {
228+
if x.group == "CPU Stats" && x.subgroup == CPU_FREQ_CORE_SUBG {
229+
if x.channel.contains("ECPU") {
230+
ecpu_usages.push(calc_freq(x.item, &self.soc.ecpu_freqs));
231+
continue;
232+
}
233+
234+
if x.channel.contains("PCPU") {
235+
pcpu_usages.push(calc_freq(x.item, &self.soc.pcpu_freqs));
236+
continue;
237+
}
235238
}
236239

237-
if x.channel.contains("PCPU") {
238-
pcpu_usages.push(calc_freq(x.item, &self.soc.pcpu_freqs));
239-
continue;
240+
if x.group == "GPU Stats" && x.subgroup == GPU_FREQ_DICE_SUBG {
241+
match x.channel.as_str() {
242+
"GPUPH" => rs.gpu_usage = calc_freq(x.item, &self.soc.gpu_freqs[1..].to_vec()),
243+
_ => {}
244+
}
240245
}
241-
}
242246

243-
if x.group == "GPU Stats" && x.subgroup == GPU_FREQ_DICE_SUBG {
244-
match x.channel.as_str() {
245-
"GPUPH" => rs.gpu_usage = calc_freq(x.item, &self.soc.gpu_freqs[1..].to_vec()),
246-
_ => {}
247+
if x.group == "Energy Model" {
248+
match x.channel.as_str() {
249+
"CPU Energy" => rs.cpu_power += cfio_watts(x.item, &x.unit, sample_dt)?,
250+
"GPU Energy" => rs.gpu_power += cfio_watts(x.item, &x.unit, sample_dt)?,
251+
c if c.starts_with("ANE") => rs.ane_power += cfio_watts(x.item, &x.unit, sample_dt)?,
252+
_ => {}
253+
}
247254
}
248255
}
249256

250-
if x.group == "Energy Model" {
251-
match x.channel.as_str() {
252-
"CPU Energy" => rs.cpu_power += cfio_watts(x.item, &x.unit, duration)?,
253-
"GPU Energy" => rs.gpu_power += cfio_watts(x.item, &x.unit, duration)?,
254-
c if c.starts_with("ANE") => rs.ane_power += cfio_watts(x.item, &x.unit, duration)?,
255-
_ => {}
256-
}
257-
}
257+
rs.ecpu_usage = calc_freq_final(&ecpu_usages, &self.soc.ecpu_freqs);
258+
rs.pcpu_usage = calc_freq_final(&pcpu_usages, &self.soc.pcpu_freqs);
259+
results.push(rs);
258260
}
259261

260-
// println!("----------");
261-
// println!("{:?}", ecpu_usages);
262-
// println!("{:?}", pcpu_usages);
263-
// println!("1 {:?} {:?}", rs.ecpu_usage, rs.pcpu_usage);
264-
rs.ecpu_usage = calc_freq_final(&ecpu_usages, &self.soc.ecpu_freqs);
265-
rs.pcpu_usage = calc_freq_final(&pcpu_usages, &self.soc.pcpu_freqs);
266-
// println!("2 {:?} {:?}", rs.ecpu_usage, rs.pcpu_usage);
267-
262+
let mut rs = Metrics::default();
263+
rs.ecpu_usage.0 = zero_div(results.iter().map(|x| x.ecpu_usage.0).sum(), measures as _);
264+
rs.ecpu_usage.1 = zero_div(results.iter().map(|x| x.ecpu_usage.1).sum(), measures as _);
265+
rs.pcpu_usage.0 = zero_div(results.iter().map(|x| x.pcpu_usage.0).sum(), measures as _);
266+
rs.pcpu_usage.1 = zero_div(results.iter().map(|x| x.pcpu_usage.1).sum(), measures as _);
267+
rs.gpu_usage.0 = zero_div(results.iter().map(|x| x.gpu_usage.0).sum(), measures as _);
268+
rs.gpu_usage.1 = zero_div(results.iter().map(|x| x.gpu_usage.1).sum(), measures as _);
269+
rs.cpu_power = zero_div(results.iter().map(|x| x.cpu_power).sum(), measures as _);
270+
rs.gpu_power = zero_div(results.iter().map(|x| x.gpu_power).sum(), measures as _);
271+
rs.ane_power = zero_div(results.iter().map(|x| x.ane_power).sum(), measures as _);
268272
rs.all_power = rs.cpu_power + rs.gpu_power + rs.ane_power;
273+
269274
rs.memory = self.get_mem()?;
270275
rs.temp = self.get_temp()?;
271276

src/sources.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,14 +532,15 @@ unsafe fn cfio_get_subs(chan: CFMutableDictionaryRef) -> WithError<IOReportSubsc
532532
pub struct IOReport {
533533
subs: IOReportSubscriptionRef,
534534
chan: CFMutableDictionaryRef,
535+
prev: Option<(CFDictionaryRef, std::time::Instant)>,
535536
}
536537

537538
impl IOReport {
538539
pub fn new(channels: Vec<(&str, Option<&str>)>) -> WithError<Self> {
539540
let chan = unsafe { cfio_get_chan(channels)? };
540541
let subs = unsafe { cfio_get_subs(chan)? };
541542

542-
Ok(Self { subs, chan })
543+
Ok(Self { subs, chan, prev: None })
543544
}
544545

545546
pub fn get_sample(&self, duration: u64) -> IOReportIterator {
@@ -554,13 +555,47 @@ impl IOReport {
554555
IOReportIterator::new(sample3)
555556
}
556557
}
558+
559+
fn raw_sample(&self) -> (CFDictionaryRef, std::time::Instant) {
560+
(unsafe { IOReportCreateSamples(self.subs, self.chan, null()) }, std::time::Instant::now())
561+
}
562+
563+
pub fn get_samples(&mut self, duration: u64, count: usize) -> Vec<(IOReportIterator, u64)> {
564+
let count = count.max(1).min(32);
565+
let mut samples: Vec<(IOReportIterator, u64)> = Vec::with_capacity(count);
566+
let step_msec = duration / count as u64;
567+
568+
let mut prev = match self.prev {
569+
Some(x) => x,
570+
None => self.raw_sample(),
571+
};
572+
573+
for _ in 0..count {
574+
std::thread::sleep(std::time::Duration::from_millis(step_msec));
575+
576+
let next = self.raw_sample();
577+
let diff = unsafe { IOReportCreateSamplesDelta(prev.0, next.0, null()) };
578+
unsafe { CFRelease(prev.0 as _) };
579+
580+
let elapsed = next.1.duration_since(prev.1).as_millis() as u64;
581+
prev = next;
582+
583+
samples.push((IOReportIterator::new(diff), elapsed.max(1)));
584+
}
585+
586+
self.prev = Some(prev);
587+
samples
588+
}
557589
}
558590

559591
impl Drop for IOReport {
560592
fn drop(&mut self) {
561593
unsafe {
562594
CFRelease(self.chan as _);
563595
CFRelease(self.subs as _);
596+
if self.prev.is_some() {
597+
CFRelease(self.prev.unwrap().0 as _);
598+
}
564599
}
565600
}
566601
}

0 commit comments

Comments
 (0)