| Replace V with Nim 472eb49 nandithebull 6h ago | 1 | # nimflutter_ffi example |
| Add a Mandelbrot example app, and a V kernel worth demonstrating 81540bb nandithebull 9h ago | 2 | |
| Replace V with Nim 472eb49 nandithebull 6h ago | 3 | A Mandelbrot explorer whose pixels are computed in Nim. Drag to pan, scroll to |
| Add drag-to-pan 0ed90f3 nandithebull 8h ago | 4 | zoom smoothly, tap to zoom in, right-click to zoom out — zoom is anchored at |
| 5 | the cursor, and a drag covers less ground the deeper you are. Sliders |
| Add a Mandelbrot example app, and a V kernel worth demonstrating 81540bb nandithebull 9h ago | 6 | control the iteration cap and how many isolates the frame is split across; |
| 7 | "Reset view" restores the framing without disturbing either. |
| 8 | |
| 9 | It exists to exercise the parts of the bridge the string demo cannot: |
| 10 | |
| 11 | * **Bulk data across the boundary.** Each frame is a full RGBA buffer, not a |
| Replace V with Nim 472eb49 nandithebull 6h ago | 12 | string. Dart allocates it and `nf_mandelbrot` fills it in place, so no Nim |
| 13 | memory crosses the boundary and there is nothing to `nf_free`. |
| Add a Mandelbrot example app, and a V kernel worth demonstrating 81540bb nandithebull 9h ago | 14 | * **Band parallelism.** The image splits into horizontal strips rendered on |
| 15 | separate isolates. Bands are independent by construction, and `-gc none` |
| 16 | means no stop-the-world phase to serialise them. |
| Replace V with Nim 472eb49 nandithebull 6h ago | 17 | * **An honest benchmark.** The same algorithm is written twice — in Nim |
| 18 | (`src/nimflutter.v`) and in Dart (`lib/mandelbrot_dart.dart`) — and the |
| Add a Mandelbrot example app, and a V kernel worth demonstrating 81540bb nandithebull 9h ago | 19 | Benchmark button times both. The tests assert the two agree pixel-for-pixel, |
| 20 | which is what makes the comparison meaningful. |
| 21 | |
| 22 | ## What the numbers actually say |
| 23 | |
| 24 | Measured here (800x600, maxIter 500, release build, 8-core Linux): |
| 25 | |
| 26 | | | time | |
| 27 | |---|---| |
| Replace V with Nim 472eb49 nandithebull 6h ago | 28 | | Nim, one isolate | ~152 ms | |
| 29 | | Nim, 4 isolates | ~65 ms | |
| Add a Mandelbrot example app, and a V kernel worth demonstrating 81540bb nandithebull 9h ago | 30 | | Dart AOT, one isolate | ~165 ms | |
| 31 | |
| Replace V with Nim 472eb49 nandithebull 6h ago | 32 | **Nim is not meaningfully faster than Dart at this.** For a scalar |
| 33 | floating-point loop, Nim-through-C and Dart AOT land within ~10% of each other. |
| Add a Mandelbrot example app, and a V kernel worth demonstrating 81540bb nandithebull 9h ago | 34 | The 2.5x comes from the parallel split, which Dart could do on its own without |
| 35 | any FFI. Treat this app as a demonstration of the *bridge* — bulk buffers, |
| Replace V with Nim 472eb49 nandithebull 6h ago | 36 | caller-owned memory, safe multi-isolate calls — not as a speed claim for Nim. |
| Add a Mandelbrot example app, and a V kernel worth demonstrating 81540bb nandithebull 9h ago | 37 | |
| Replace V with Nim 472eb49 nandithebull 6h ago | 38 | Reach for Nim here because you want to write the logic in Nim, or already have |
| 39 | it in Nim, not because C-via-Nim is expected to outrun Dart AOT on arithmetic. |
| Add a Mandelbrot example app, and a V kernel worth demonstrating 81540bb nandithebull 9h ago | 40 | |
| Raise the isolate ceiling to 32, and add the sweep that justifies it 59a731a nandithebull 9h ago | 41 | ## How many isolates? |
| 42 | |
| 43 | The slider goes to 32, and past the core count is the right place to be. Bands |
| 44 | cost very different amounts — rows crossing the set's interior run the full |
| 45 | iteration cap, rows in open space escape almost immediately — and a frame is |
| 46 | not done until its slowest band is. Over-decomposing lets a free core start the |
| 47 | next small band instead of idling. |
| 48 | |
| 49 | Measured here (800x600 / 500 iterations, 8 logical cores): |
| 50 | |
| 51 | | tiles | best ms | speedup | |
| 52 | |---|---|---| |
| 53 | | serial | 153 | 1.00x | |
| 54 | | 4 | 64 | 2.39x | |
| 55 | | 8 | 43 | 3.56x | |
| 56 | | 16 | 34 | 4.50x | |
| 57 | | 32 | 29 | 5.28x | |
| 58 | | 64 | 27 | 5.67x | |
| 59 | |
| 60 | Even at 32 bands the slowest is still 2.7x the mean, which is the remaining |
| 61 | inefficiency — not isolate overhead. Spawning 24 isolates costs ~0.8 ms and |
| 62 | moving the whole 1.83 MB frame back across them ~1.4 ms, against a ~29 ms |
| 63 | frame. Run `just sweep` to get these numbers for your own machine. |
| 64 | |
| Add a Mandelbrot example app, and a V kernel worth demonstrating 81540bb nandithebull 9h ago | 65 | ## Run it |
| 66 | |
| Add a justfile f7c3825 nandithebull 9h ago | 67 | ```bash |
| 68 | just mandelbrot |
| 69 | ``` |
| 70 | |
| 71 | or, driving Flutter yourself: |
| 72 | |
| Add a Mandelbrot example app, and a V kernel worth demonstrating 81540bb nandithebull 9h ago | 73 | ```bash |
| 74 | cd example |
| 75 | flutter run -d linux |
| 76 | ``` |
| 77 | |
| 78 | Only the Linux runner is generated. For the other platforms, generate their |
| 79 | runner directories once first: |
| 80 | |
| 81 | ```bash |
| 82 | flutter create --platforms=android,ios,macos,windows . |
| 83 | ``` |
| 84 | |
| 85 | `flutter create` leaves `lib/`, `test/` and `pubspec.yaml` alone. The native |
| 86 | library is built by the plugin itself: CMake invokes `v` on Linux, Windows and |
| 87 | Android; iOS and macOS compile the pre-generated C in `ios/Classes/`. |
| 88 | |
| 89 | ## Tests |
| 90 | |
| 91 | `flutter test` runs on the host VM rather than in the app bundle, so it needs |
| 92 | the native library on the loader path: |
| 93 | |
| 94 | ```bash |
| 95 | ./tool/build.sh |
| 96 | cd example && LD_LIBRARY_PATH=../build flutter test |
| 97 | ``` |
| 98 | |
| 99 | The suite covers the zoom maths as a property (the point under the cursor stays |
| 100 | put), the buffer contract, the band split matching a single-shot render, and |
| Replace V with Nim 472eb49 nandithebull 6h ago | 101 | the Nim and Dart kernels agreeing exactly. |
| Add a Mandelbrot example app, and a V kernel worth demonstrating 81540bb nandithebull 9h ago | 102 | |
| 103 | ## Headless scripts |
| 104 | |
| 105 | No Flutter SDK needed — only `dart` and the host library. Run from the |
| 106 | repository root, which resolves without Flutter: |
| 107 | |
| 108 | ```bash |
| 109 | ./tool/build.sh |
| Replace V with Nim 472eb49 nandithebull 6h ago | 110 | LD_LIBRARY_PATH=build dart example/lib/fractal_bench.dart # Nim vs Dart timings |
| Add a Mandelbrot example app, and a V kernel worth demonstrating 81540bb nandithebull 9h ago | 111 | LD_LIBRARY_PATH=build dart example/lib/main_test.dart # string round-trips |
| 112 | LD_LIBRARY_PATH=build dart example/lib/memory_check.dart # RSS regression guard |
| 113 | ``` |
| 114 | |
| 115 | For a like-for-like comparison with a release app, compile the benchmark AOT |
| 116 | first — `dart run` uses the JIT: |
| 117 | |
| 118 | ```bash |
| 119 | dart compile exe example/lib/fractal_bench.dart -o /tmp/bench |
| 120 | LD_LIBRARY_PATH=build /tmp/bench |
| 121 | ``` |