diff --git a/internal_filesystem/apps/com.micropythonos.benchmark/META-INF/MANIFEST.JSON b/internal_filesystem/apps/com.micropythonos.benchmark/META-INF/MANIFEST.JSON new file mode 100644 index 00000000..c3928488 --- /dev/null +++ b/internal_filesystem/apps/com.micropythonos.benchmark/META-INF/MANIFEST.JSON @@ -0,0 +1,24 @@ +{ +"name": "Benchmark", +"publisher": "MicroPythonOS", +"short_description": "Benchmark MicroPythonOS", +"long_description": "Different benchmarks to measure the speed of MicroPythonOS.", +"icon_url": "https://apps.micropythonos.com/apps/com.micropythonos.benchmark/icons/com.micropythonos.benchmark_0.0.1_64x64.png", +"download_url": "https://apps.micropythonos.com/apps/com.micropythonos.benchmark/mpks/com.micropythonos.benchmark_0.0.1.mpk", +"fullname": "com.micropythonos.benchmark", +"version": "0.0.1", +"category": "benchmark", +"activities": [ + { + "entrypoint": "assets/benchmark.py", + "classname": "Benchmark", + "intent_filters": [ + { + "action": "main", + "category": "launcher" + } + ] + } + ] +} + diff --git a/internal_filesystem/apps/com.micropythonos.benchmark/assets/benchmark.py b/internal_filesystem/apps/com.micropythonos.benchmark/assets/benchmark.py new file mode 100644 index 00000000..4fc48922 --- /dev/null +++ b/internal_filesystem/apps/com.micropythonos.benchmark/assets/benchmark.py @@ -0,0 +1,168 @@ +import time +import _thread + +from mpos.apps import Activity +import mpos.ui + +indev_error_x = 160 +indev_error_y = 120 + +DARKPINK = lv.color_hex(0xEC048C) + +class Benchmark(Activity): + + hor_res = 0 + ver_res = 0 + layer = None + fps_buffer = [0] # Buffer to store FPS + bird_x = 100 + bird_y = 0 + image_w = 296 + image_h = 240 + image_target_w = 160 + image_target_h = 120 + image_x = image_w + image_y = 0 + + #lvgl_w = 160 + #lvgl_h = 120 + + # Widgets: + canvas = None + image = None + + def onCreate(self): + screen = lv.obj() + # Make the screen focusable so it can be scrolled with the arrow keys + focusgroup = lv.group_get_default() + if focusgroup: + focusgroup.add_obj(screen) + screen.add_event_cb(self.key_cb, lv.EVENT.KEY, None) + self.image = lv.image(screen) + #self.load_image("data/images/screenshots/snapshot_640x480_RGB565.raw") + self.load_image("data/images/screenshots/snapshot_296x240_RGB565.raw") + #self.image.set_size(self.lvgl_w, self.lvgl_h) + #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 + #self.image.set_scale(max(scale_factor_w,scale_factor_h)) # fills the entire screen but cuts off borders + scale_factor_w = round(self.image_target_w * 256 / self.image_w) + self.image.set_scale(scale_factor_w) + #self.image.set_scale(128) + #self.image.set_size(640, 480) + self.spinner = lv.spinner(screen) + self.spinner.set_size(16, 16) + self.setContentView(screen) + + def onResume(self, screen): + super().onResume(screen) + lv.log_register_print_cb(self.log_callback) + try: + _thread.stack_size(mpos.apps.good_stack_size()) + _thread.start_new_thread(self.game, ()) + except Exception as e: + print("Could not start thread: ", e) + + def onStop(self, screen): + super().onStop(screen) + lv.log_register_print_cb(None) + + + def extract_dimensions_and_format(self, filename): + # Split the filename by '_' + parts = filename.split('_') + # Get the color format (last part before '.raw') + color_format = parts[-1].split('.')[0] # e.g., "RGB565" + # Get the resolution (second-to-last part) + resolution = parts[-2] # e.g., "240x240" + # Split resolution by 'x' to get width and height + width, height = map(int, resolution.split('x')) + return width, height, color_format.upper() + + def load_image(self, name): + if not name.lower().endswith(".raw"): + self.image.remove_flag(lv.obj.FLAG.HIDDEN) + self.image.set_src(f"M:{name}") + else: + f = open(name, 'rb') + image_data = f.read() + print(f"loaded {len(image_data)} bytes from .raw file") + f.close() + try: + width, height, color_format = self.extract_dimensions_and_format(name) + except ValueError as e: + print(f"Warning: could not extract dimensions and format from raw image: {e}") + return + print(f"Raw image has width: {width}, Height: {height}, Color Format: {color_format}") + stride = width * 2 + cf = lv.COLOR_FORMAT.RGB565 + if color_format != "RGB565": + print(f"WARNING: unknown color format {color_format}, assuming RGB565...") + self.current_image_dsc = lv.image_dsc_t({ + "header": { + "magic": lv.IMAGE_HEADER_MAGIC, + "w": width, + "h": height, + "stride": stride, + "cf": cf + }, + 'data_size': len(image_data), + 'data': image_data + }) + self.image.set_src(self.current_image_dsc) + + def touch_cb(self, event): + event_code=event.get_code() + #print(f"lv_event_t: code={event_code}") + if event_code == lv.EVENT.PRESSING: + self.runall() + + # Custom log callback to capture FPS + def log_callback(self,level, log_str): + # Convert log_str to string if it's a bytes object + log_str = log_str.decode() if isinstance(log_str, bytes) else log_str + # Optional: Print for debugging + #print(f"Level: {level}, Log: {log_str}") + # Log message format: "sysmon: 25 FPS (refr_cnt: 8 | redraw_cnt: 1), ..." + if "sysmon:" in log_str and "FPS" in log_str: + try: + # Extract FPS value (e.g., "25" from "sysmon: 25 FPS ...") + fps_part = log_str.split("FPS")[0].split("sysmon:")[1].strip() + fps = int(fps_part) + print("Current FPS:", fps) + self.fps_buffer[0] = fps + except (IndexError, ValueError): + pass + + def key_cb(self, event): + key = event.get_key() + #print(f"got key {key}") + + if key == lv.KEY.UP: + self.image_target_w += 20 + scale_factor_w = round(self.image_target_w * 256 / self.image_w) + self.image.set_scale(scale_factor_w) + #self.bird_y -= 10 + elif key == lv.KEY.DOWN: + self.image_target_w -= 20 + scale_factor_w = round(self.image_target_w * 256 / self.image_w) + self.image.set_scale(scale_factor_w) + #self.bird_y += 10 + elif key == lv.KEY.LEFT: + self.bird_x -= 10 + elif key == lv.KEY.RIGHT: + self.bird_x += 10 + elif key == lv.KEY.ENTER: + self.bird_y -= 25 + + def game(self): + # print("Waiting a bit before starting...") ; time.sleep(1) # wait for top bar to go away + while self.has_foreground(): + self.update_ui_threadsafe_if_foreground(self.spinner.set_pos, self.bird_x, self.bird_y) + self.update_ui_threadsafe_if_foreground(self.image.set_x, self.image_x) + time.sleep_ms(10) + self.image_x -= 1 + if self.image_x < (-self.image_target_w*2): + self.image_x = self.image_w + self.bird_y += 1 + if self.bird_y > self.image_h: + self.bird_y = 0 + diff --git a/internal_filesystem/apps/com.micropythonos.benchmark/assets/benchmark_v1.py b/internal_filesystem/apps/com.micropythonos.benchmark/assets/benchmark_v1.py new file mode 100644 index 00000000..46c2dfe0 --- /dev/null +++ b/internal_filesystem/apps/com.micropythonos.benchmark/assets/benchmark_v1.py @@ -0,0 +1,128 @@ +import time +import _thread + +from mpos.apps import Activity +import mpos.ui + +indev_error_x = 160 +indev_error_y = 120 + +DARKPINK = lv.color_hex(0xEC048C) + +class Benchmark(Activity): + + hor_res = 0 + ver_res = 0 + layer = None + fps_buffer = [0] # Buffer to store FPS + + # Widgets: + canvas = None + + def onCreate(self): + screen = lv.obj() + self.canvas = lv.canvas(screen) + disp = lv.display_get_default() + self.hor_res = disp.get_horizontal_resolution() + self.ver_res = disp.get_vertical_resolution() + self.canvas.set_size(self.hor_res, self.ver_res) + self.canvas.set_style_bg_color(lv.color_white(), 0) + buffer = bytearray(self.hor_res * self.ver_res * 4) + self.canvas.set_buffer(buffer, self.hor_res, self.ver_res, lv.COLOR_FORMAT.NATIVE) + self.canvas.fill_bg(lv.color_white(), lv.OPA.COVER) + self.layer = lv.layer_t() + self.canvas.init_layer(self.layer) + self.canvas.add_flag(lv.obj.FLAG.CLICKABLE) + self.canvas.add_event_cb(self.touch_cb, lv.EVENT.ALL, None) + self.setContentView(screen) + + def onResume(self, screen): + #lv.perf_monitor_create(10, NULL, NULL) + lv.log_register_print_cb(self.log_callback) + #try: + # _thread.stack_size(mpos.apps.good_stack_size()) + # _thread.start_new_thread(self.runall, ()) + #except Exception as e: + # print("Could not start thread: ", e) + + def onStop(self, screen): + super().onStop(screen) + lv.log_register_print_cb(None) + + def touch_cb(self, event): + event_code=event.get_code() + #print(f"lv_event_t: code={event_code}") + if event_code == lv.EVENT.PRESSING: + self.runall() + + # Custom log callback to capture FPS + def log_callback(self,level, log_str): + # Convert log_str to string if it's a bytes object + log_str = log_str.decode() if isinstance(log_str, bytes) else log_str + # Optional: Print for debugging + #print(f"Level: {level}, Log: {log_str}") + # Log message format: "sysmon: 25 FPS (refr_cnt: 8 | redraw_cnt: 1), ..." + if "sysmon:" in log_str and "FPS" in log_str: + try: + # Extract FPS value (e.g., "25" from "sysmon: 25 FPS ...") + fps_part = log_str.split("FPS")[0].split("sysmon:")[1].strip() + fps = int(fps_part) + print("Current FPS:", fps) + self.fps_buffer[0] = fps + except (IndexError, ValueError): + pass + + def runall(self): + print("Waiting a bit before starting...") + time.sleep(1) # wait for top bar to go away + for _ in range(5): + self.draw_n_squares(10000) + + def draw_n_squares(self, n): + start = time.ticks_ms() + for _ in range(n): + self.draw_rect(100, 100) + end = time.ticks_ms() + diff = end - start + print(f"draw_rect x {n} took {diff}ms") + start = time.ticks_ms() + for _ in range(n): + self.draw_rect_viper(100, 100) + end = time.ticks_ms() + diff = end - start + print(f"draw_rect_viper x {n} took {diff}ms") + + def draw_rect(self, x: int, y: int): + draw_dsc = lv.draw_rect_dsc_t() + lv.draw_rect_dsc_t.init(draw_dsc) + draw_dsc.bg_color = lv.color_hex(0xffaaaa) + draw_dsc.border_color = lv.color_hex(0xff5555) + draw_dsc.border_width = 2 + draw_dsc.outline_color = lv.color_hex(0xff0000) + draw_dsc.outline_pad = 3 + draw_dsc.outline_width = 2 + a = lv.area_t() + a.x1 = x-10 + a.y1 = y-10 + a.x2 = x+10 + a.y2 = y+10 + lv.draw_rect(self.layer, draw_dsc, a) + self.canvas.finish_layer(self.layer) + + @micropython.viper # make it with native compilation + def draw_rect_viper(self, x: int, y: int): + draw_dsc = lv.draw_rect_dsc_t() + lv.draw_rect_dsc_t.init(draw_dsc) + draw_dsc.bg_color = lv.color_hex(0xffaaaa) + draw_dsc.border_color = lv.color_hex(0xff5555) + draw_dsc.border_width = 2 + draw_dsc.outline_color = lv.color_hex(0xff0000) + draw_dsc.outline_pad = 3 + draw_dsc.outline_width = 2 + a = lv.area_t() + a.x1 = x-10 + a.y1 = y-10 + a.x2 = x+10 + a.y2 = y+10 + lv.draw_rect(self.layer, draw_dsc, a) + self.canvas.finish_layer(self.layer) diff --git a/internal_filesystem/apps/com.micropythonos.benchmark/res/mipmap-mdpi/icon_64x64.png b/internal_filesystem/apps/com.micropythonos.benchmark/res/mipmap-mdpi/icon_64x64.png new file mode 100644 index 00000000..ac0877f0 Binary files /dev/null and b/internal_filesystem/apps/com.micropythonos.benchmark/res/mipmap-mdpi/icon_64x64.png differ