Skip to content

Commit 816d3a3

Browse files
Add Benchmark app
1 parent 10901f0 commit 816d3a3

File tree

4 files changed

+320
-0
lines changed

4 files changed

+320
-0
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"name": "Benchmark",
3+
"publisher": "MicroPythonOS",
4+
"short_description": "Benchmark MicroPythonOS",
5+
"long_description": "Different benchmarks to measure the speed of MicroPythonOS.",
6+
"icon_url": "https://apps.micropythonos.com/apps/com.micropythonos.benchmark/icons/com.micropythonos.benchmark_0.0.1_64x64.png",
7+
"download_url": "https://apps.micropythonos.com/apps/com.micropythonos.benchmark/mpks/com.micropythonos.benchmark_0.0.1.mpk",
8+
"fullname": "com.micropythonos.benchmark",
9+
"version": "0.0.1",
10+
"category": "benchmark",
11+
"activities": [
12+
{
13+
"entrypoint": "assets/benchmark.py",
14+
"classname": "Benchmark",
15+
"intent_filters": [
16+
{
17+
"action": "main",
18+
"category": "launcher"
19+
}
20+
]
21+
}
22+
]
23+
}
24+
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
import time
2+
import _thread
3+
4+
from mpos.apps import Activity
5+
import mpos.ui
6+
7+
indev_error_x = 160
8+
indev_error_y = 120
9+
10+
DARKPINK = lv.color_hex(0xEC048C)
11+
12+
class Benchmark(Activity):
13+
14+
hor_res = 0
15+
ver_res = 0
16+
layer = None
17+
fps_buffer = [0] # Buffer to store FPS
18+
bird_x = 100
19+
bird_y = 0
20+
image_w = 296
21+
image_h = 240
22+
image_target_w = 160
23+
image_target_h = 120
24+
image_x = image_w
25+
image_y = 0
26+
27+
#lvgl_w = 160
28+
#lvgl_h = 120
29+
30+
# Widgets:
31+
canvas = None
32+
image = None
33+
34+
def onCreate(self):
35+
screen = lv.obj()
36+
# Make the screen focusable so it can be scrolled with the arrow keys
37+
focusgroup = lv.group_get_default()
38+
if focusgroup:
39+
focusgroup.add_obj(screen)
40+
screen.add_event_cb(self.key_cb, lv.EVENT.KEY, None)
41+
self.image = lv.image(screen)
42+
#self.load_image("data/images/screenshots/snapshot_640x480_RGB565.raw")
43+
self.load_image("data/images/screenshots/snapshot_296x240_RGB565.raw")
44+
#self.image.set_size(self.lvgl_w, self.lvgl_h)
45+
#self.gif.set_size(lvgl_w, lvgl_h) doesn't seem to do anything. get_style_transform_scale_x/y works but then it needs get_style_translate_x/y
46+
#self.image.set_scale(max(scale_factor_w,scale_factor_h)) # fills the entire screen but cuts off borders
47+
scale_factor_w = round(self.image_target_w * 256 / self.image_w)
48+
self.image.set_scale(scale_factor_w)
49+
#self.image.set_scale(128)
50+
#self.image.set_size(640, 480)
51+
self.spinner = lv.spinner(screen)
52+
self.spinner.set_size(16, 16)
53+
self.setContentView(screen)
54+
55+
def onResume(self, screen):
56+
super().onResume(screen)
57+
lv.log_register_print_cb(self.log_callback)
58+
try:
59+
_thread.stack_size(mpos.apps.good_stack_size())
60+
_thread.start_new_thread(self.game, ())
61+
except Exception as e:
62+
print("Could not start thread: ", e)
63+
64+
def onStop(self, screen):
65+
super().onStop(screen)
66+
lv.log_register_print_cb(None)
67+
68+
69+
def extract_dimensions_and_format(self, filename):
70+
# Split the filename by '_'
71+
parts = filename.split('_')
72+
# Get the color format (last part before '.raw')
73+
color_format = parts[-1].split('.')[0] # e.g., "RGB565"
74+
# Get the resolution (second-to-last part)
75+
resolution = parts[-2] # e.g., "240x240"
76+
# Split resolution by 'x' to get width and height
77+
width, height = map(int, resolution.split('x'))
78+
return width, height, color_format.upper()
79+
80+
def load_image(self, name):
81+
if not name.lower().endswith(".raw"):
82+
self.image.remove_flag(lv.obj.FLAG.HIDDEN)
83+
self.image.set_src(f"M:{name}")
84+
else:
85+
f = open(name, 'rb')
86+
image_data = f.read()
87+
print(f"loaded {len(image_data)} bytes from .raw file")
88+
f.close()
89+
try:
90+
width, height, color_format = self.extract_dimensions_and_format(name)
91+
except ValueError as e:
92+
print(f"Warning: could not extract dimensions and format from raw image: {e}")
93+
return
94+
print(f"Raw image has width: {width}, Height: {height}, Color Format: {color_format}")
95+
stride = width * 2
96+
cf = lv.COLOR_FORMAT.RGB565
97+
if color_format != "RGB565":
98+
print(f"WARNING: unknown color format {color_format}, assuming RGB565...")
99+
self.current_image_dsc = lv.image_dsc_t({
100+
"header": {
101+
"magic": lv.IMAGE_HEADER_MAGIC,
102+
"w": width,
103+
"h": height,
104+
"stride": stride,
105+
"cf": cf
106+
},
107+
'data_size': len(image_data),
108+
'data': image_data
109+
})
110+
self.image.set_src(self.current_image_dsc)
111+
112+
def touch_cb(self, event):
113+
event_code=event.get_code()
114+
#print(f"lv_event_t: code={event_code}")
115+
if event_code == lv.EVENT.PRESSING:
116+
self.runall()
117+
118+
# Custom log callback to capture FPS
119+
def log_callback(self,level, log_str):
120+
# Convert log_str to string if it's a bytes object
121+
log_str = log_str.decode() if isinstance(log_str, bytes) else log_str
122+
# Optional: Print for debugging
123+
#print(f"Level: {level}, Log: {log_str}")
124+
# Log message format: "sysmon: 25 FPS (refr_cnt: 8 | redraw_cnt: 1), ..."
125+
if "sysmon:" in log_str and "FPS" in log_str:
126+
try:
127+
# Extract FPS value (e.g., "25" from "sysmon: 25 FPS ...")
128+
fps_part = log_str.split("FPS")[0].split("sysmon:")[1].strip()
129+
fps = int(fps_part)
130+
print("Current FPS:", fps)
131+
self.fps_buffer[0] = fps
132+
except (IndexError, ValueError):
133+
pass
134+
135+
def key_cb(self, event):
136+
key = event.get_key()
137+
#print(f"got key {key}")
138+
139+
if key == lv.KEY.UP:
140+
self.image_target_w += 20
141+
scale_factor_w = round(self.image_target_w * 256 / self.image_w)
142+
self.image.set_scale(scale_factor_w)
143+
#self.bird_y -= 10
144+
elif key == lv.KEY.DOWN:
145+
self.image_target_w -= 20
146+
scale_factor_w = round(self.image_target_w * 256 / self.image_w)
147+
self.image.set_scale(scale_factor_w)
148+
#self.bird_y += 10
149+
elif key == lv.KEY.LEFT:
150+
self.bird_x -= 10
151+
elif key == lv.KEY.RIGHT:
152+
self.bird_x += 10
153+
elif key == lv.KEY.ENTER:
154+
self.bird_y -= 25
155+
156+
def game(self):
157+
# print("Waiting a bit before starting...") ; time.sleep(1) # wait for top bar to go away
158+
while self.has_foreground():
159+
self.update_ui_threadsafe_if_foreground(self.spinner.set_pos, self.bird_x, self.bird_y)
160+
self.update_ui_threadsafe_if_foreground(self.image.set_x, self.image_x)
161+
time.sleep_ms(10)
162+
self.image_x -= 1
163+
if self.image_x < (-self.image_target_w*2):
164+
self.image_x = self.image_w
165+
self.bird_y += 1
166+
if self.bird_y > self.image_h:
167+
self.bird_y = 0
168+
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import time
2+
import _thread
3+
4+
from mpos.apps import Activity
5+
import mpos.ui
6+
7+
indev_error_x = 160
8+
indev_error_y = 120
9+
10+
DARKPINK = lv.color_hex(0xEC048C)
11+
12+
class Benchmark(Activity):
13+
14+
hor_res = 0
15+
ver_res = 0
16+
layer = None
17+
fps_buffer = [0] # Buffer to store FPS
18+
19+
# Widgets:
20+
canvas = None
21+
22+
def onCreate(self):
23+
screen = lv.obj()
24+
self.canvas = lv.canvas(screen)
25+
disp = lv.display_get_default()
26+
self.hor_res = disp.get_horizontal_resolution()
27+
self.ver_res = disp.get_vertical_resolution()
28+
self.canvas.set_size(self.hor_res, self.ver_res)
29+
self.canvas.set_style_bg_color(lv.color_white(), 0)
30+
buffer = bytearray(self.hor_res * self.ver_res * 4)
31+
self.canvas.set_buffer(buffer, self.hor_res, self.ver_res, lv.COLOR_FORMAT.NATIVE)
32+
self.canvas.fill_bg(lv.color_white(), lv.OPA.COVER)
33+
self.layer = lv.layer_t()
34+
self.canvas.init_layer(self.layer)
35+
self.canvas.add_flag(lv.obj.FLAG.CLICKABLE)
36+
self.canvas.add_event_cb(self.touch_cb, lv.EVENT.ALL, None)
37+
self.setContentView(screen)
38+
39+
def onResume(self, screen):
40+
#lv.perf_monitor_create(10, NULL, NULL)
41+
lv.log_register_print_cb(self.log_callback)
42+
#try:
43+
# _thread.stack_size(mpos.apps.good_stack_size())
44+
# _thread.start_new_thread(self.runall, ())
45+
#except Exception as e:
46+
# print("Could not start thread: ", e)
47+
48+
def onStop(self, screen):
49+
super().onStop(screen)
50+
lv.log_register_print_cb(None)
51+
52+
def touch_cb(self, event):
53+
event_code=event.get_code()
54+
#print(f"lv_event_t: code={event_code}")
55+
if event_code == lv.EVENT.PRESSING:
56+
self.runall()
57+
58+
# Custom log callback to capture FPS
59+
def log_callback(self,level, log_str):
60+
# Convert log_str to string if it's a bytes object
61+
log_str = log_str.decode() if isinstance(log_str, bytes) else log_str
62+
# Optional: Print for debugging
63+
#print(f"Level: {level}, Log: {log_str}")
64+
# Log message format: "sysmon: 25 FPS (refr_cnt: 8 | redraw_cnt: 1), ..."
65+
if "sysmon:" in log_str and "FPS" in log_str:
66+
try:
67+
# Extract FPS value (e.g., "25" from "sysmon: 25 FPS ...")
68+
fps_part = log_str.split("FPS")[0].split("sysmon:")[1].strip()
69+
fps = int(fps_part)
70+
print("Current FPS:", fps)
71+
self.fps_buffer[0] = fps
72+
except (IndexError, ValueError):
73+
pass
74+
75+
def runall(self):
76+
print("Waiting a bit before starting...")
77+
time.sleep(1) # wait for top bar to go away
78+
for _ in range(5):
79+
self.draw_n_squares(10000)
80+
81+
def draw_n_squares(self, n):
82+
start = time.ticks_ms()
83+
for _ in range(n):
84+
self.draw_rect(100, 100)
85+
end = time.ticks_ms()
86+
diff = end - start
87+
print(f"draw_rect x {n} took {diff}ms")
88+
start = time.ticks_ms()
89+
for _ in range(n):
90+
self.draw_rect_viper(100, 100)
91+
end = time.ticks_ms()
92+
diff = end - start
93+
print(f"draw_rect_viper x {n} took {diff}ms")
94+
95+
def draw_rect(self, x: int, y: int):
96+
draw_dsc = lv.draw_rect_dsc_t()
97+
lv.draw_rect_dsc_t.init(draw_dsc)
98+
draw_dsc.bg_color = lv.color_hex(0xffaaaa)
99+
draw_dsc.border_color = lv.color_hex(0xff5555)
100+
draw_dsc.border_width = 2
101+
draw_dsc.outline_color = lv.color_hex(0xff0000)
102+
draw_dsc.outline_pad = 3
103+
draw_dsc.outline_width = 2
104+
a = lv.area_t()
105+
a.x1 = x-10
106+
a.y1 = y-10
107+
a.x2 = x+10
108+
a.y2 = y+10
109+
lv.draw_rect(self.layer, draw_dsc, a)
110+
self.canvas.finish_layer(self.layer)
111+
112+
@micropython.viper # make it with native compilation
113+
def draw_rect_viper(self, x: int, y: int):
114+
draw_dsc = lv.draw_rect_dsc_t()
115+
lv.draw_rect_dsc_t.init(draw_dsc)
116+
draw_dsc.bg_color = lv.color_hex(0xffaaaa)
117+
draw_dsc.border_color = lv.color_hex(0xff5555)
118+
draw_dsc.border_width = 2
119+
draw_dsc.outline_color = lv.color_hex(0xff0000)
120+
draw_dsc.outline_pad = 3
121+
draw_dsc.outline_width = 2
122+
a = lv.area_t()
123+
a.x1 = x-10
124+
a.y1 = y-10
125+
a.x2 = x+10
126+
a.y2 = y+10
127+
lv.draw_rect(self.layer, draw_dsc, a)
128+
self.canvas.finish_layer(self.layer)
6.04 KB
Loading

0 commit comments

Comments
 (0)