From c4b4254e4207b17d3870123b00320209c8b63ff1 Mon Sep 17 00:00:00 2001 From: Alex G Rice Date: Sat, 25 Nov 2023 14:31:44 -0700 Subject: [PATCH] Update readme and polishing. --- .github/workflows/{test.yaml => tests.yaml} | 0 README.md | 24 ++++++++++++-------- docs/benchmark-results.ods | Bin 19453 -> 24665 bytes mojo_impl/tests/test_impls.mojo | 4 ++-- 4 files changed, 16 insertions(+), 12 deletions(-) rename .github/workflows/{test.yaml => tests.yaml} (100%) diff --git a/.github/workflows/test.yaml b/.github/workflows/tests.yaml similarity index 100% rename from .github/workflows/test.yaml rename to .github/workflows/tests.yaml diff --git a/README.md b/README.md index 4a9cc30..61aac64 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,14 @@ # Spatial envelope optimization and benchmarks -A [Mojo](https://github.com/modularml/mojo)🔥 project calculating the spatial envelope, and exploring the -performance of Python, NumPy, and Mojo. - [![Run Tests](https://github.com/guidorice/modcon23-contest/actions/workflows/tests.yaml/badge.svg)](https://github.com/guidorice/modcon23-contest/actions/workflows/tests.yaml) +A [Mojo](https://github.com/modularml/mojo)🔥 project created for the [MonCon23 +contest](https://www.modular.com/mojo). + +Calculates the spatial envelope, and explores the performance of Python, NumPy, +and Mojo. *The Mojo final implementation is 20X to 600X faster than Python, +and 1.3X to 4X faster than [NumPy](https://numpy.org/).* + ## Envelope Calculating an envelope is a fundamental part of spatial analysis. The envelope @@ -26,18 +30,18 @@ Figure attribution: [QGIS documentation](https://docs.qgis.org/3.28/en/docs/user ## Variants also considered -I wanted to benchmark the [Shapely](https://shapely.readthedocs.io/en/stable/) -package which wraps the [GEOS library](https://libgeos.org/), another -well-optimized C/C++ codebase. However Shapely seems to cache the envelope upon -geometry creation, so it was not feasible to benchmark the envelope -calculations separately from geometry constructors. Using NumPy seemed like a -good alternative. +The [Shapely](https://shapely.readthedocs.io/en/stable/) package wraps the +[GEOS library](https://libgeos.org/), another well-optimized C/C++ codebase. +Shapely caches the envelope upon geometry creation, so it was not feasible to +benchmark the envelope calculations separately from geometry constructors. For +that reason, Shapely was not included in the benchmarks. ## All benchmarks Test system: mojo `0.5.0` on Apple M2, 24GB RAM. Data type: `float32`. ![overall benchmarks](./docs/img/benchmarks-1.png) +[raw results spreadsheet](./docs/benchmark-results.ods) ## Chart of optimized variants only @@ -62,7 +66,7 @@ In other words, the same generic code can run, for example, `float16`, dimensions is sometimes referred to as XY, XYZ, or XYZM, where Z is "height", and M is "measure". -## Example output from Mojo's `benchmark` module +## Example output including Mojo's `benchmark` report ```text $ mojo mojo_impl/optimized_a.mojo 100 diff --git a/docs/benchmark-results.ods b/docs/benchmark-results.ods index 24b912bee3ae3ba9d532c3c184a18df466c16edc..beb95db7d85922c16be99febb950d884b151a0f5 100644 GIT binary patch delta 22902 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

QhW9id9)O*0_?LkVit^P$#z#*2?Fi*7|Y-D{h z_zO{EWB^WS>Z_`2VSChqs4XtvRp1aZW%em049>ghu5B4 z`#l+l>a45BB;{+9pcj;4L!i#;V`E|JEYr?XOuM<9$LN)>qn}%Fm5w)Tb&2g9aTmq= zQT~m0j6|`AZfk;MQpBY5xGI{T0qcw6X@V*p?AC@&PlBLR!U^_ z_4T7wsoB&Cra+!Xlsuo0K{~D`eYIYuz%3Y>>3x%D0>Oe$DBI9g!Ou_3R>exvc$^n% zJK2a)1d6o2xIaX-QV#UKs$CKIqD|D#QKDMnh#~?Lly;mC{>d|WhyoOi7x@cY5d^6Y zHJ;TnMLaI9rE8S(V;}@-=qA6~q0!4AQJ}P`3p71O&R!7Yr+%^_e!zKqklmWKE}JKrDERTC_0lYh6y(W++o`Jbx$+(6Q+`T0!I#v%-#+J&g z2X^a;_1fRZR)DGW-eDKto$Bbjf0D4EdKaB+YO5&C87g{J?>5uDz%(uwg{~zTXoL{S z+4!?xa^FHFBrsl~D1x=-A*V^8$mlX5j&JW1<&3H>7Tg|E#2PCPowmLx@La&kNdXLQ zNh}oW4o@pYBy%b@EzZBt1l}=}BMrNRdVyWs*}R<9)k0V2NQoxjqTSZjh?ghs2!wHt*8x2T)j^bHNXFo1ZozqEwU9jqN zbC`}kw*eBCJ;n(}czd4p<~;kgRZ2f(rS0@o7GDpL=dSWf@>-UVn3VWu7P2jv5{}d2 zm8q_Du}VzJAaem7BnD5NYjTSwKR6EeX#H3)ys;YF*Z9oBjJHgb_+Hex2{vOd1UA%n zH{MtG&>H}I`PH1~@&djoGMS-&1%}a^h4RloPJt{MMhU$B9Ecg7Ics~2kNm%yCJ-(5 zyl{LRyI}J)N{v5bgQw!i;;i7kV>+xPWH#BNzebZSuw$9}9Y92Lq4W=z#t1W{XrGWQ zhd4;ecb>7MZjcmh*ycVg`V0vI^g~)XUEROVC#x`Armyjl9htCf1SG8N+BrD%^=#13 zOaO^>+h;eU8}$j@?IRGKI}cE8Ef${f(^g;ms?zL}-iVDAu6E8pCqgFGTdwvign!v$ z(I3uf$U-0GCY_e{LOyHimh^(-C+}u@to*(>gDb)PUjIIOff`Uwz8|V>sKIiPD!nql zjBUa}>P4np-rc6bLXmRFV{Bg0s(rcH*$%vGk18rW$IIRGJsEN1Yf>lH*+U5&yD&cnBZ1BSF>`qDZlcf>>wL{m0${B|4w{)?!0Vu8~zsBZ7J|Er;Jp5L(Eb7 zYHnCU__k<#ZyXR>F0%KI) ziW|InzF-LLU)>ehV@-~)4Ro*QV~rrwDZ7+A>DsnCdt{*a!$0hZP~u*s6(OZA+Wh_o z_xKt&cKPXEwfOm8?{9AdJFnT`!N5?s|EDQdy{n$VXQV-7s%WkAWwL*TC4~GU5mi#CdY}uPR*DM(tQUk8Wbao2-+d&er4((gy$wnP+AI diff --git a/mojo_impl/tests/test_impls.mojo b/mojo_impl/tests/test_impls.mojo index 0131631..2d73bd3 100644 --- a/mojo_impl/tests/test_impls.mojo +++ b/mojo_impl/tests/test_impls.mojo @@ -14,10 +14,10 @@ alias width = 1000 fn main() raises: - test_naive_mojo_impls() + test_mojo_impls() -fn test_naive_mojo_impls(): +fn test_mojo_impls(): let test = MojoTest("mojo implementations are all consistent") # create a tensor, filled with random values