diff --git a/Cargo.lock b/Cargo.lock index e5d0114..1a50439 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,9 +10,9 @@ checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" [[package]] name = "addr2line" -version = "0.20.0" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] @@ -25,9 +25,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a" dependencies = [ "memchr", ] @@ -64,24 +64,23 @@ dependencies = [ [[package]] name = "anstream" -version = "0.3.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", - "is-terminal", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" +checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea" [[package]] name = "anstyle-parse" @@ -103,9 +102,9 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "1.0.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" dependencies = [ "anstyle", "windows-sys", @@ -136,9 +135,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" -version = "0.3.68" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", @@ -186,16 +185,16 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] name = "breakwater" version = "0.1.0" dependencies = [ "chrono", - "clap 4.3.19", + "clap 4.4.0", "const_format", "criterion", "env_logger 0.10.0", @@ -253,9 +252,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.81" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c6b2562119bf28c3439f7f02db99faf0aa1a8cdfe5772a2ee155d32227239f0" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ "libc", ] @@ -366,9 +365,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.3.19" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd304a20bff958a57f04c4e96a2e7594cc4490a0e809cbd48bb6437edaa452d" +checksum = "1d5f1946157a96594eb2d2c10eb7ad9a2b27518cb3000209dec700c35df9197d" dependencies = [ "clap_builder", "clap_derive", @@ -377,21 +376,21 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.3.19" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1" +checksum = "78116e32a042dd73c2901f0dc30790d20ff3447f3e3472fad359e8c3d282bcd6" dependencies = [ "anstream", "anstyle", - "clap_lex 0.5.0", + "clap_lex 0.5.1", "strsim 0.10.0", ] [[package]] name = "clap_derive" -version = "4.3.12" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" +checksum = "c9fd1a5729c4548118d7d70ff234a44868d00489a4b6597b0b020918a0e91a1a" dependencies = [ "heck", "proc-macro2", @@ -410,9 +409,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" +checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" [[package]] name = "color_quant" @@ -470,7 +469,7 @@ dependencies = [ "anes", "cast", "ciborium", - "clap 4.3.19", + "clap 4.4.0", "criterion-plot", "futures", "is-terminal", @@ -550,9 +549,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "deranged" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7684a49fb1af197853ef7b2ee694bc1f5b4179556f1e5710e1760c5db6f5e929" +checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" [[package]] name = "either" @@ -634,9 +633,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010" dependencies = [ "crc32fast", "miniz_oxide", @@ -790,9 +789,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.3" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" [[package]] name = "glob" @@ -883,9 +882,9 @@ dependencies = [ [[package]] name = "image" -version = "0.24.6" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527909aa81e20ac3a44803521443a765550f09b5130c2c2fa1ea59c2f8f50a3a" +checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711" dependencies = [ "bytemuck", "byteorder", @@ -1006,9 +1005,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" @@ -1113,9 +1112,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.31.1" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe" dependencies = [ "memchr", ] @@ -1204,9 +1203,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.11" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c516611246607d0c04186886dbb3a754368ef82c79e9827a802c6d836dd111c" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -1262,9 +1261,9 @@ dependencies = [ [[package]] name = "png" -version = "0.17.9" +version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59871cc5b6cce7eaccca5a802b4173377a1c2ba90654246789a8fa2334426d11" +checksum = "dd75bf2d8dd3702b9707cdbc56a5b9ef42cec752eb8b3bafc01234558442aa64" dependencies = [ "bitflags 1.3.2", "crc32fast", @@ -1327,9 +1326,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -1397,9 +1396,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.3" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" +checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" dependencies = [ "aho-corasick", "memchr", @@ -1409,9 +1408,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" +checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" dependencies = [ "aho-corasick", "memchr", @@ -1420,21 +1419,21 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "relative-path" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bf2521270932c3c7bed1a59151222bd7643c79310f2916f01925e1e16255698" +checksum = "c707298afce11da2efef2f600116fa93ffa7a032b5d7b628aa17711ec81383ca" [[package]] name = "rstest" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b96577ca10cb3eade7b337eb46520108a67ca2818a24d0b63f41fd62bc9651c" +checksum = "97eeab2f3c0a199bc4be135c36c924b6590b88c377d416494288c14f2db30199" dependencies = [ "futures", "futures-timer", @@ -1444,9 +1443,9 @@ dependencies = [ [[package]] name = "rstest_macros" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225e674cf31712b8bb15fdbca3ec0c1b9d825c5a24407ff2b7e005fb6a29ba03" +checksum = "d428f8247852f894ee1be110b375111b586d4fa431f6c46e64ba5a0dcccbe605" dependencies = [ "cfg-if", "glob", @@ -1482,11 +1481,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.7" +version = "0.38.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "172891ebdceb05aa0005f533a6cbfca599ddd7d966f6f5d4d9b2e70478e70399" +checksum = "9bfe0f2582b4931a45d1fa608f8a8722e8b3c7ac54dd6d5f3b3212791fedef49" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.0", "errno", "libc", "linux-raw-sys", @@ -1538,18 +1537,18 @@ checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" [[package]] name = "serde" -version = "1.0.182" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb30a74471f5b7a1fa299f40b4bf1be93af61116df95465b2b5fc419331e430" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.182" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f4c2c6ea4bc09b5c419012eafcdb0fcef1d9119d626c8f3a0708a5b92d38a70" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", @@ -1558,9 +1557,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.104" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" +checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" dependencies = [ "itoa", "ryu", @@ -1588,6 +1587,16 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[package]] +name = "simd_test" +version = "0.1.0" +dependencies = [ + "breakwater", + "criterion", + "pixelbomber", + "tokio", +] + [[package]] name = "simple_moving_average" version = "0.1.2" @@ -1599,9 +1608,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] @@ -1614,12 +1623,12 @@ checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" [[package]] name = "socket2" -version = "0.4.9" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" dependencies = [ "libc", - "winapi", + "windows-sys", ] [[package]] @@ -1645,9 +1654,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "2.0.28" +version = "2.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" dependencies = [ "proc-macro2", "quote", @@ -1680,18 +1689,18 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.44" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" +checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.44" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" +checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" dependencies = [ "proc-macro2", "quote", @@ -1714,9 +1723,9 @@ dependencies = [ [[package]] name = "tiff" -version = "0.8.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7449334f9ff2baf290d55d73983a7d6fa15e01198faef72af07e2a8db851e471" +checksum = "6d172b0f4d3fba17ba89811858b9d3d97f928aece846475bbda076ca46736211" dependencies = [ "flate2", "jpeg-decoder", @@ -1736,9 +1745,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fdd63d58b18d663fbdf70e049f00a22c8e42be082203be7f26589213cd75ea" +checksum = "17f6bb557fd245c28e6411aa56b6403c689ad95061f50e4be16c274e70a17e48" dependencies = [ "deranged", "itoa", @@ -1755,9 +1764,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.11" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd" +checksum = "1a942f44339478ef67935ab2bbaec2fb0322496cf3cbe84b261e06ac3814c572" dependencies = [ "time-core", ] @@ -1771,7 +1780,7 @@ dependencies = [ "ascii", "chunked_transfer", "log", - "time 0.3.25", + "time 0.3.28", "url", ] @@ -1802,11 +1811,10 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.29.1" +version = "1.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" +checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" dependencies = [ - "autocfg", "backtrace", "bytes", "libc", @@ -2061,9 +2069,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -2076,45 +2084,45 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "zune-inflate" diff --git a/Cargo.toml b/Cargo.toml index 25c690b..53332ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,6 @@ +[workspace] +members = ["simd_test"] + [package] name = "breakwater" version = "0.1.0" @@ -5,14 +8,14 @@ edition = "2021" [dependencies] chrono = "0.4" -const_format = "0.2" clap = { version = "4.3", features = ["derive"] } -rusttype = "0.9" -number_prefix = "0.4" +const_format = "0.2" env_logger = "0.10" lazy_static = "1.4" log = "0.4" +number_prefix = "0.4" prometheus_exporter = "0.8" +rusttype = "0.9" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" simple_moving_average = "0.1" @@ -48,6 +51,6 @@ opt-level = 3 [profile.release] opt-level = 3 -lto = "fat" -codegen-units = 1 +# lto = "fat" +# codegen-units = 1 # panic = "abort" # You can enable this, but I prefer to get actual stack traces diff --git a/simd_test/Cargo.toml b/simd_test/Cargo.toml new file mode 100644 index 0000000..ddb61ae --- /dev/null +++ b/simd_test/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "simd_test" +version = "0.1.0" +edition = "2021" + +[dependencies] +breakwater = { path = "../" } + +# chrono = "0.4" +# clap = { version = "4.3", features = ["derive"] } +# const_format = "0.2" +# env_logger = "0.10" +# lazy_static = "1.4" +# log = "0.4" +# number_prefix = "0.4" +# prometheus_exporter = "0.8" +# rusttype = "0.9" +# serde = { version = "1.0", features = ["derive"] } +# serde_json = "1.0" +# simple_moving_average = "0.1" +# thread-priority = "0.13" +tokio = { version = "1.29", features = ["fs", "rt-multi-thread", "net", "io-util", "macros", "process", "signal", "sync", "time"] } +# vncserver = { version ="0.2", optional = true} + +[dev-dependencies] +criterion = {version = "0.5", features = ["async_tokio"]} +pixelbomber = "0.4.1" +# rstest = "0.18" +# rand = "0.8" + +[lib] +name = "simd_test" +path = "src/lib.rs" + +[[bench]] +name = "benchmarks" +harness = false diff --git a/simd_test/benches/benchmarks.rs b/simd_test/benches/benchmarks.rs new file mode 100644 index 0000000..75904f8 --- /dev/null +++ b/simd_test/benches/benchmarks.rs @@ -0,0 +1,162 @@ +#![feature(portable_simd)] + +use breakwater::{framebuffer::FrameBuffer, parser::ParserState, test::helpers::DevNullTcpStream}; +use criterion::{ + BenchmarkId, Criterion, {criterion_group, criterion_main}, +}; +use pixelbomber::image_handler; +use pixelbomber::image_handler::ImageConfig; +use std::{sync::Arc, time::Duration}; + +const FRAMEBUFFER_WIDTH: usize = 1920; +const FRAMEBUFFER_HEIGHT: usize = 1080; + +async fn invoke_parse_pixelflut_commands_base( + input: &[u8], + fb: &Arc, + parser_state: ParserState, +) { + let mut stream = DevNullTcpStream::default(); + breakwater::parser::parse_pixelflut_commands(input, fb, &mut stream, parser_state).await; +} + +async fn invoke_parse_pixelflut_commands_simd( + input: &[u8], + fb: &Arc, + parser_state: ParserState, +) { + let mut stream = DevNullTcpStream::default(); + simd_test::parser::parse_pixelflut_commands(input, fb, &mut stream, parser_state).await; +} + +fn benchmark_base(c: &mut Criterion, name: &str, file: &str, config: ImageConfig) { + let mut commands = image_handler::load(vec![file], &config); + let command = commands.pop().unwrap(); + c.bench_with_input( + BenchmarkId::new(name, format!("{FRAMEBUFFER_WIDTH} x {FRAMEBUFFER_HEIGHT}")), + &command, + |b, input| { + let fb = Arc::new(FrameBuffer::new(FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT)); + let parser_state = ParserState::default(); + b.to_async(tokio::runtime::Runtime::new().unwrap()) + .iter(|| invoke_parse_pixelflut_commands_base(input, &fb, parser_state.clone())); + }, + ); +} + +fn benchmark_simd(c: &mut Criterion, name: &str, file: &str, config: ImageConfig) { + let mut commands = image_handler::load(vec![file], &config); + let command = commands.pop().unwrap(); + c.bench_with_input( + BenchmarkId::new(name, format!("{FRAMEBUFFER_WIDTH} x {FRAMEBUFFER_HEIGHT}")), + &command, + |b, input| { + let fb = Arc::new(FrameBuffer::new(FRAMEBUFFER_WIDTH, FRAMEBUFFER_HEIGHT)); + let parser_state = ParserState::default(); + b.to_async(tokio::runtime::Runtime::new().unwrap()) + .iter(|| invoke_parse_pixelflut_commands_simd(input, &fb, parser_state.clone())); + }, + ); +} + +fn add_benches(c: &mut Criterion) { + // benchmark_base( + // c, + // "parse_draw_commands_ordered", + // "benches/non-transparent.png", + // image_handler::ImageConfigBuilder::new() + // .width(FRAMEBUFFER_WIDTH as u32) + // .height(FRAMEBUFFER_HEIGHT as u32) + // .shuffle(false) + // .build(), + // ); + + benchmark_base( + c, + "base_parse_draw_commands_shuffled", + "benches/non-transparent.png", + image_handler::ImageConfigBuilder::new() + .width(FRAMEBUFFER_WIDTH as u32) + .height(FRAMEBUFFER_HEIGHT as u32) + .shuffle(true) + .build(), + ); + + // benchmark_base( + // c, + // "parse_mixed_draw_commands", + // "benches/mixed.png", + // image_handler::ImageConfigBuilder::new() + // .width(FRAMEBUFFER_WIDTH as u32) + // .height(FRAMEBUFFER_HEIGHT as u32) + // .shuffle(false) + // .gray_usage(true) + // .build(), + // ); + + // benchmark_base( + // c, + // "parse_draw_commands_with_offset", + // "benches/non-transparent.png", + // image_handler::ImageConfigBuilder::new() + // .width(FRAMEBUFFER_WIDTH as u32) + // .height(FRAMEBUFFER_HEIGHT as u32) + // .shuffle(false) + // .offset_usage(true) + // .build(), + // ); + + // benchmark_simd( + // c, + // "parse_draw_commands_ordered", + // "benches/non-transparent.png", + // image_handler::ImageConfigBuilder::new() + // .width(FRAMEBUFFER_WIDTH as u32) + // .height(FRAMEBUFFER_HEIGHT as u32) + // .shuffle(false) + // .build(), + // ); + + benchmark_simd( + c, + "simd_parse_draw_commands_shuffled", + "benches/non-transparent.png", + image_handler::ImageConfigBuilder::new() + .width(FRAMEBUFFER_WIDTH as u32) + .height(FRAMEBUFFER_HEIGHT as u32) + .shuffle(true) + .build(), + ); + + // benchmark_simd( + // c, + // "parse_mixed_draw_commands", + // "benches/mixed.png", + // image_handler::ImageConfigBuilder::new() + // .width(FRAMEBUFFER_WIDTH as u32) + // .height(FRAMEBUFFER_HEIGHT as u32) + // .shuffle(false) + // .gray_usage(true) + // .build(), + // ); + + // benchmark_simd( + // c, + // "parse_draw_commands_with_offset", + // "benches/non-transparent.png", + // image_handler::ImageConfigBuilder::new() + // .width(FRAMEBUFFER_WIDTH as u32) + // .height(FRAMEBUFFER_HEIGHT as u32) + // .shuffle(false) + // .offset_usage(true) + // .build(), + // ); +} + +criterion_group!( + name = benches; + config = Criterion::default().warm_up_time(Duration::from_secs(2)).measurement_time(Duration::from_secs(3)); + targets = add_benches, +); + +criterion_main!(benches); diff --git a/simd_test/benches/mixed.png b/simd_test/benches/mixed.png new file mode 100644 index 0000000..0cdb00f Binary files /dev/null and b/simd_test/benches/mixed.png differ diff --git a/simd_test/benches/non-transparent.png b/simd_test/benches/non-transparent.png new file mode 100644 index 0000000..5061f33 Binary files /dev/null and b/simd_test/benches/non-transparent.png differ diff --git a/simd_test/src/lib.rs b/simd_test/src/lib.rs new file mode 100644 index 0000000..5b00297 --- /dev/null +++ b/simd_test/src/lib.rs @@ -0,0 +1,3 @@ +#![feature(portable_simd)] + +pub mod parser; diff --git a/simd_test/src/parser.rs b/simd_test/src/parser.rs new file mode 100644 index 0000000..9cc6a29 --- /dev/null +++ b/simd_test/src/parser.rs @@ -0,0 +1,233 @@ +use breakwater::framebuffer::FrameBuffer; +use breakwater::parser::{ParserState, HELP_TEXT}; +use std::simd::{u16x16, u16x32, u16x8, SimdPartialOrd, SimdUint, ToBitMask}; +use std::sync::Arc; +use tokio::io::AsyncWriteExt; + +pub fn main() {} + +/// Returns the offset (think of index in [u8]) of the last bytes of the last fully parsed command. +/// +/// TODO: Implement support for 16K (15360 × 8640). +/// Currently the parser only can read up to 4 digits of x or y coordinates. +/// If you buy me a big enough screen I will kindly implement this feature. +pub async fn parse_pixelflut_commands( + buffer: &[u8], + fb: &Arc, + mut stream: impl AsyncWriteExt + Unpin, + // We don't pass this as mutual reference but instead hand it around - I guess on the stack? + // I don't know what I'm doing, hoping for best performance anyway ;) + parser_state: ParserState, +) -> ParserState { + let mut last_byte_parsed = 0; + let mut connection_x_offset = parser_state.connection_x_offset; + let mut connection_y_offset = parser_state.connection_y_offset; + + let mut i = 0; // We can't use a for loop here because Rust don't lets use skip characters by incrementing i + let loop_end = buffer.len().saturating_sub(PARSER_LOOKAHEAD as usize); // Let's extract the .len() call and the subtraction into it's own variable so we only compute it once + + while i < loop_end { + let current_command = unsafe { (buffer.as_ptr().add(i) as *const u64).read_unaligned() }; + if current_command & 0x00ff_ffff == string_to_number(b"PX \0\0\0\0\0") { + i += 3; + // TODO: Use variant that does not check bounds to get &buffer[i..i + 19] + let ParseResult { + bytes_parsed, + x, + y, + rgba, + has_alpha, + read_request, + } = parse_coords_and_rgba(&buffer[i..i + 19]); + // let x = 0; + // let y = 0; + // let rgba = 0; + // let read_request = false; + // let bytes_parsed = 17; + i += bytes_parsed; + last_byte_parsed = i - 1; + } else if current_command & 0x0000_ffff_ffff_ffff == string_to_number(b"OFFSET \0\0") { + i += 7; + + let (x, y, present) = parse_pixel_coordinates(buffer.as_ptr(), &mut i); + + // End of command to set offset + if present && unsafe { *buffer.get_unchecked(i) } == b'\n' { + last_byte_parsed = i; + connection_x_offset = x; + connection_y_offset = y; + continue; + } + } else if current_command & 0xffff_ffff == string_to_number(b"SIZE\0\0\0\0") { + i += 4; + last_byte_parsed = i - 1; + + stream + .write_all(format!("SIZE {} {}\n", fb.get_width(), fb.get_height()).as_bytes()) + .await + .expect("Failed to write bytes to tcp socket"); + continue; + } else if current_command & 0xffff_ffff == string_to_number(b"HELP\0\0\0\0") { + i += 4; + last_byte_parsed = i - 1; + + stream + .write_all(HELP_TEXT) + .await + .expect("Failed to write bytes to tcp socket"); + continue; + } + + i += 1; + } + + ParserState { + connection_x_offset, + connection_y_offset, + last_byte_parsed, + } +} + +const fn string_to_number(input: &[u8]) -> u64 { + (input[7] as u64) << 56 + | (input[6] as u64) << 48 + | (input[5] as u64) << 40 + | (input[4] as u64) << 32 + | (input[3] as u64) << 24 + | (input[2] as u64) << 16 + | (input[1] as u64) << 8 + | (input[0] as u64) +} + +#[inline(always)] +fn parse_coordinate(buffer: *const u8, current_index: &mut usize) -> (usize, bool) { + let digits = unsafe { (buffer.add(*current_index) as *const usize).read_unaligned() }; + + let mut result = 0; + let mut visited = false; + // The compiler will unroll this loop, but this way, it is more maintainable + for pos in 0..4 { + let digit = (digits >> (pos * 8)) & 0xff; + if digit >= b'0' as usize && digit <= b'9' as usize { + result = 10 * result + digit - b'0' as usize; + *current_index += 1; + visited = true; + } else { + break; + } + } + + (result, visited) +} + +#[inline(always)] +fn parse_pixel_coordinates(buffer: *const u8, current_index: &mut usize) -> (usize, usize, bool) { + let (x, x_visited) = parse_coordinate(buffer, current_index); + *current_index += 1; + let (y, y_visited) = parse_coordinate(buffer, current_index); + (x, y, x_visited && y_visited) +} + +// Longest possible space bitmask = "1234 1234 rrggbbaa\n" => 19 chars +const PARSER_LOOKAHEAD: u8 = 42; +const SPACES_BITMASK_RELEVANT_BITS: u8 = 19; +const SPACES_BITMASK_RELEVANT_BITS_MASK: u32 = 0b0000_0000_0111_1111_1111_1111_1111; +const FACTORS_FOR_BITMASK: [(u16x32, u16x32, u16x32, u16x32); + (1 << SPACES_BITMASK_RELEVANT_BITS) + 1] = calculate_factors_for_bitmask(); +const SIMD_U16X16_9: u16x16 = u16x16::from_array([9; 16]); +const SIMD_U16X32_9: u16x32 = u16x32::from_array([9; 32]); +const SIMD_U16X16_0_CHAR: u16x16 = u16x16::from_array([b'0' as u16; 16]); +const SIMD_U16X32_0_CHAR: u16x32 = u16x32::from_array([b'0' as u16; 32]); +const SIMD_U16X8_0_CHAR: u16x8 = u16x8::from_array([b'0' as u16; 8]); + +struct ParseResult { + bytes_parsed: usize, + x: u16, + y: u16, + // aabbggrr + rgba: u32, + read_request: bool, + has_alpha: bool, +} + +// Input: 19 characters starting where the x coordinate starts, eg. "1234 4321 \n" +// Returns: (x, y, total length of text containing " ") +// +// Inspect assembler code using +// RUSTFLAGS="-C target-cpu=native" CARGO_INCREMENTAL=0 cargo -Z build-std asm --build-type release --rust breakwater::parser::parse_coords_and_rgba +// Don't forget to #[inline(never)]! +#[inline(never)] +fn parse_coords_and_rgba(bytes: &[u8]) -> ParseResult { + // #[cfg(debug_assertions)] + assert!(bytes.len() >= 19); + let chars = u16x32::from_array([ + bytes[0] as u16, + bytes[1] as u16, + bytes[2] as u16, + bytes[3] as u16, + bytes[4] as u16, + bytes[5] as u16, + bytes[6] as u16, + bytes[7] as u16, + bytes[8] as u16, + bytes[9] as u16, + bytes[10] as u16, + bytes[11] as u16, + bytes[12] as u16, + bytes[13] as u16, + bytes[14] as u16, + bytes[15] as u16, + bytes[16] as u16, + bytes[17] as u16, + bytes[18] as u16, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ]); + // let digits = chars - SIMD_U16X32_0_CHAR; + // let space_bitmask = digits.simd_gt(SIMD_U16X32_9).to_bitmask(); + // // SAFETY: As only take the last {SPACES_BITMASK_RELEVANT_BITS} bits, this number will alway be a valid index + // let (x_factors, y_factors, rg_factors, ba_factors) = + // unsafe { FACTORS_FOR_BITMASK.get_unchecked(space_bitmask as usize) }; + // // let (x_factors, y_factors, rg_factors, ba_factors) = + // // FACTORS_FOR_BITMASK[space_bitmask as usize]; + // let x = (digits * x_factors).reduce_sum(); + // let y = (digits * y_factors).reduce_sum(); + // let rg = (digits * rg_factors).reduce_sum(); + // let ba = (digits * ba_factors).reduce_sum(); + let x = 0; + let y = 0; + let rg = 0; + let ba = 0; + + ParseResult { + bytes_parsed: 10, + x, + y, + rgba: (rg as u32) << 16 | ba as u32, + has_alpha: false, + read_request: false, + } +} + +const fn calculate_factors_for_bitmask( +) -> [(u16x32, u16x32, u16x32, u16x32); (1 << SPACES_BITMASK_RELEVANT_BITS) + 1] { + let mut result = [( + u16x32::from_array([0; 32]), + u16x32::from_array([0; 32]), + u16x32::from_array([0; 32]), + u16x32::from_array([0; 32]), + ); (1 << SPACES_BITMASK_RELEVANT_BITS) + 1]; + + result +} diff --git a/src/parser.rs b/src/parser.rs index cc7b92b..1076e35 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -5,7 +5,7 @@ use std::simd::{u32x8, Simd, SimdUint}; use std::sync::Arc; use tokio::io::AsyncWriteExt; -pub const PARSER_LOOKAHEAD: usize = "PX 1234 1234 rrggbbaa\n".len(); // Longest possible command +pub const PARSER_LOOKAHEAD: usize = 42; // "PX 1234 1234 rrggbbaa\n".len(); // Longest possible command pub const HELP_TEXT: &[u8] = formatcp!("\ Pixelflut server powered by breakwater https://github.com/sbernauer/breakwater Available commands: @@ -26,9 +26,9 @@ if cfg!(feature = "alpha") { #[derive(Clone, Default, Debug)] pub struct ParserState { - connection_x_offset: usize, - connection_y_offset: usize, - last_byte_parsed: usize, + pub connection_x_offset: usize, + pub connection_y_offset: usize, + pub last_byte_parsed: usize, } impl ParserState {