lib/framecounter: Use std::chrono
Bug: b/304282368
Change-Id: I640e9721fd84427c4be92ffb87d8059e6a71b2bf
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/kudzu/+/193351
Presubmit-Verified: CQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Armando Montanez <amontanez@google.com>
Commit-Queue: Anthony DiGirolamo <tonymd@google.com>
diff --git a/applications/32blit_demo/main.cc b/applications/32blit_demo/main.cc
index 2243f5b..3502489 100644
--- a/applications/32blit_demo/main.cc
+++ b/applications/32blit_demo/main.cc
@@ -11,6 +11,7 @@
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
+#include <chrono>
#include <cstdint>
#define PW_LOG_LEVEL PW_LOG_LEVEL_DEBUG
@@ -56,27 +57,27 @@
p.generated = true;
};
-void rain(blit::Surface screen, uint32_t time_ms, blit::Rect floor_position) {
+void rain(blit::Surface screen,
+ pw::chrono::SystemClock::duration elapsed_time,
+ blit::Rect floor_position) {
static test_particle s[300];
static int generate_index = 0;
- static uint32_t last_time_ms = time_ms;
- int elapsed_ms = time_ms - last_time_ms;
- float td = (elapsed_ms) / 1000.0f;
+ // Convert to fractional elapsed seconds.
+ auto const elapsed_seconds =
+ std::chrono::duration_cast<std::chrono::duration<float>>(elapsed_time);
rain_generate(s[generate_index++], screen);
if (generate_index >= 300)
generate_index = 0;
- float w = sinf(time_ms / 1000.0f) * 0.05f;
-
blit::Vec2 gvec = blit::Vec2(0, 9.8 * 5);
- blit::Vec2 gravity = gvec * td;
+ blit::Vec2 gravity = gvec * elapsed_seconds.count();
for (auto& p : s) {
if (p.generated) {
p.vel += gravity;
- p.pos += p.vel * td;
+ p.pos += p.vel * elapsed_seconds.count();
int floor = -3;
if (p.pos.x > floor_position.x &&
@@ -106,8 +107,6 @@
screen.pixel(p.pos + blit::Point(0, screen.bounds.h + 2));
}
}
-
- last_time_ms = time_ms;
};
void MainTask(void*) {
@@ -130,8 +129,6 @@
display.ReleaseFramebuffer(std::move(framebuffer));
- uint32_t delta_screen_draw = 0;
-
// The display loop.
while (1) {
frame_counter.StartFrame();
@@ -152,11 +149,11 @@
blit::Point((screen.bounds.w / 2) - (text_size.w / 2),
(screen.bounds.h * .75) - (text_size.h / 2)),
text_size);
- rain(screen, frame_counter.start - delta_screen_draw, text_rect);
+
+ rain(screen, frame_counter.LastFrameDuration(), text_rect);
screen.pen = blit::Pen(0xFF, 0xFF, 0xFF);
screen.text(
text, blit::minimal_font, text_rect, true, blit::TextAlign::top_left);
- delta_screen_draw = pw::spin_delay::Millis() - frame_counter.start;
// Update timers
frame_counter.EndDraw();
@@ -165,7 +162,7 @@
frame_counter.EndFlush();
// Every second make a log message.
- frame_counter.EndFrame();
+ frame_counter.LogTiming();
}
}
diff --git a/applications/badge/main.cc b/applications/badge/main.cc
index ed48f08..b94bfc1 100644
--- a/applications/badge/main.cc
+++ b/applications/badge/main.cc
@@ -363,7 +363,7 @@
frame_counter.EndFlush();
// Every second make a log message.
- frame_counter.EndFrame();
+ frame_counter.LogTiming();
if (pw::spin_delay::Millis() > frame_start_millis + 10000) {
Common::EndOfFrameCallback();
diff --git a/applications/snake/main.cc b/applications/snake/main.cc
index 47197f6..909fe32 100644
--- a/applications/snake/main.cc
+++ b/applications/snake/main.cc
@@ -111,7 +111,7 @@
display.ReleaseFramebuffer(std::move(framebuffer));
frame_counter.EndFlush();
- frame_counter.EndFrame();
+ frame_counter.LogTiming();
pw::spin_delay::WaitMillis(kWaitMillis);
diff --git a/applications/terminal_display/main.cc b/applications/terminal_display/main.cc
index d5e3c8c..bda7cb2 100644
--- a/applications/terminal_display/main.cc
+++ b/applications/terminal_display/main.cc
@@ -424,7 +424,7 @@
frame_counter.EndFlush();
// Every second make a log message.
- frame_counter.EndFrame();
+ frame_counter.LogTiming();
}
}
diff --git a/lib/framecounter/BUILD.gn b/lib/framecounter/BUILD.gn
index cc952fc..e10083b 100644
--- a/lib/framecounter/BUILD.gn
+++ b/lib/framecounter/BUILD.gn
@@ -25,8 +25,8 @@
public = [ "public/libkudzu/framecounter.h" ]
public_deps = [ "$dir_pw_ring_buffer" ]
deps = [
+ "$dir_pw_chrono:system_clock",
"$dir_pw_log",
- "$dir_pw_spin_delay",
]
sources = [ "framecounter.cc" ]
}
diff --git a/lib/framecounter/framecounter.cc b/lib/framecounter/framecounter.cc
index 21667f8..2c2f2b9 100644
--- a/lib/framecounter/framecounter.cc
+++ b/lib/framecounter/framecounter.cc
@@ -1,50 +1,77 @@
+// Copyright 2024 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
#include "libkudzu/framecounter.h"
+#include <chrono>
+
#define PW_LOG_LEVEL PW_LOG_LEVEL_DEBUG
#define PW_LOG_MODULE_NAME "FrameCounter"
#include <cstdint>
#include <cstring>
+#include "pw_chrono/system_clock.h"
#include "pw_log/log.h"
#include "pw_ring_buffer/prefixed_entry_ring_buffer.h"
-#include "pw_spin_delay/delay.h"
+
+using namespace std::chrono_literals;
namespace kudzu {
FrameCounter::FrameCounter() {
- frame_start_millis = pw::spin_delay::Millis();
- frames = 0;
+ second_counter_start = pw::chrono::SystemClock::now();
+ frame_count = 0;
frames_per_second = 0;
draw_times.SetBuffer(draw_buffer);
flush_times.SetBuffer(flush_buffer);
}
-// TODO(b/304282368): Switch to pw_chrono and delete pw_spin_delay
-void FrameCounter::StartFrame() { start = pw::spin_delay::Millis(); }
+void FrameCounter::StartFrame() {
+ frame_start = pw::chrono::SystemClock::now();
+}
void FrameCounter::EndDraw() {
- uint32_t end = pw::spin_delay::Millis();
- uint32_t time = end - start;
- draw_times.PushBack(pw::as_bytes(pw::span{std::addressof(time), 1}));
- start = end;
+ draw_end = pw::chrono::SystemClock::now();
+ auto draw_duration = draw_end - frame_start;
+ uint32_t elapsed_millis =
+ std::chrono::round<std::chrono::microseconds>(draw_duration).count();
+ draw_times.PushBack(
+ pw::as_bytes(pw::span{std::addressof(elapsed_millis), 1}));
}
void FrameCounter::EndFlush() {
- uint32_t time = pw::spin_delay::Millis() - start;
- flush_times.PushBack(pw::as_bytes(pw::span{std::addressof(time), 1}));
+ frame_end = pw::chrono::SystemClock::now();
+ last_frame_duration = frame_end - frame_start;
+ auto flush_duration = frame_end - draw_end;
+ frame_count++;
+ uint32_t elapsed_millis =
+ std::chrono::round<std::chrono::microseconds>(flush_duration).count();
+ flush_times.PushBack(
+ pw::as_bytes(pw::span{std::addressof(elapsed_millis), 1}));
}
-void FrameCounter::EndFrame() {
- frames++;
- if (pw::spin_delay::Millis() > frame_start_millis + 1000) {
- frames_per_second = frames;
- frames = 0;
- PW_LOG_INFO("FPS:%d, Draw:%dms, Flush:%dms",
+void FrameCounter::LogTiming() {
+ if (frame_end - second_counter_start >
+ pw::chrono::SystemClock::for_at_least(1000ms)) {
+ frames_per_second = frame_count;
+ frame_count = 0;
+ PW_LOG_INFO("FPS:%d, Draw:%dus, Flush:%dus",
frames_per_second,
(int)CalcAverageUint32Value(draw_times),
(int)CalcAverageUint32Value(flush_times));
- frame_start_millis = pw::spin_delay::Millis();
+ second_counter_start = pw::chrono::SystemClock::now();
}
}
diff --git a/lib/framecounter/public/libkudzu/framecounter.h b/lib/framecounter/public/libkudzu/framecounter.h
index 9736607..eed40a4 100644
--- a/lib/framecounter/public/libkudzu/framecounter.h
+++ b/lib/framecounter/public/libkudzu/framecounter.h
@@ -1,7 +1,22 @@
+// Copyright 2024 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
#pragma once
#include <stdint.h>
+#include "pw_chrono/system_clock.h"
#include "pw_ring_buffer/prefixed_entry_ring_buffer.h"
namespace kudzu {
@@ -13,12 +28,25 @@
void StartFrame();
void EndDraw();
void EndFlush();
- void EndFrame();
+ void LogTiming();
+ inline pw::chrono::SystemClock::duration LastFrameDuration() {
+ return last_frame_duration;
+ }
+ inline std::chrono::milliseconds LastFrameMilliseconds() {
+ return std::chrono::round<std::chrono::milliseconds>(last_frame_duration);
+ }
- uint32_t frame_start_millis;
- uint32_t frames;
- uint32_t start;
- float delta_time;
+ private:
+ pw::chrono::SystemClock::time_point second_counter_start;
+ // Start of a single frame / start of the draw phase.
+ pw::chrono::SystemClock::time_point frame_start;
+ // End of the draw phase / start of the flush phase.
+ pw::chrono::SystemClock::time_point draw_end;
+ // End of the flush phase and end of the frame.
+ pw::chrono::SystemClock::time_point frame_end;
+ // Duration of frame_start to frame_end.
+ pw::chrono::SystemClock::duration last_frame_duration;
+ uint32_t frame_count;
int frames_per_second;
std::byte draw_buffer[30 * sizeof(uint32_t)];
std::byte flush_buffer[30 * sizeof(uint32_t)];