()
| 646 | let opaque_black = px |
| 647 | .chunks_exact(4) |
| 648 | .filter(|p| p[0] == 0 && p[1] == 0 && p[2] == 0 && p[3] == 255) |
| 649 | .count(); |
| 650 | assert!( |
| 651 | opaque_black > 10_000, |
| 652 | "expected the clear to fill the framebuffer, got {opaque_black} black pixels" |
| 653 | ); |
| 654 | assert!( |
| 655 | vm.framebuffer_fill_count() >= 1, |
| 656 | "life did not clear the framebuffer via the FILL register" |
| 657 | ); |
| 658 | // ... and at least one live cell drawn (a green, non-black pixel). |
| 659 | let live = px.chunks_exact(4).any(|p| p[1] > 0 && p[3] == 255); |
| 660 | assert!(live, "life rendered no live cells onto the framebuffer"); |
| 661 | } |
| 662 | |
| 663 | // Headless framebuffer throughput bench: a measurement, not a pass/fail, so it |
| 664 | // carries no assertion and stays #[ignore]d for manual release runs. |
| 665 | #[test] |
| 666 | #[ignore = "manual framebuffer throughput benchmark"] |
| 667 | fn cube_framebuffer_bench() { |
| 668 | let user = compile_hosted(user::CUBE); |
| 669 | let steps: u64 = 40_000_000; |
| 670 | |
| 671 | let start = std::time::Instant::now(); |
| 672 | let (vm, _outcome, _uart) = boot_kernel(cached_kernel(), Some(&user), None, "", steps); |
| 673 | let elapsed = start.elapsed().as_secs_f64(); |
| 674 | |
| 675 | let frames = vm.framebuffer_fill_count(); |
| 676 | let cps = steps as f64 / elapsed; |
| 677 | let fps = frames as f64 / elapsed; |
| 678 | let cycles_per_frame = if frames > 0 { |
| 679 | steps as f64 / frames as f64 |
| 680 | } else { |
| 681 | f64::NAN |
| 682 | }; |
| 683 | println!( |
| 684 | "cube bench: {steps} steps in {elapsed:.3}s => {cps:.0} cycles/s; \ |
| 685 | {frames} frames; {cycles_per_frame:.0} cycles/frame; {fps:.1} cube fps" |
| 686 | ); |
| 687 | } |
| 688 | |
| 689 | // --- Interactive shell (merged from kernel_shell.rs) --- |
| 690 |
nothing calls this directly
no test coverage detected