diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml new file mode 100644 index 00000000..59e75b7a --- /dev/null +++ b/.github/workflows/bench.yml @@ -0,0 +1,45 @@ +name: Run the benchmarks of the crate + +on: + push: + branches: [ main, develop ] + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Cache build data + uses: actions/cache@v2 + with: + path: | + target + ~/.cargo/ + key: ${{ runner.os }}-cargo + restore-keys: | + ${{ runner.os }}-cargo + + - name: Extract branch name + shell: bash + run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})" + id: extract_branch + + - name: Run benchmark + run: cargo bench -- --save-baseline ${{steps.extract_branch.outputs.branch}} + + - name: upload artifact + uses: actions/upload-artifact@v2 + with: + name: benchmark-results + path: target/criterion/ + - name: deploy to github pages + uses: JamesIves/github-pages-deploy-action@4.1.5 + with: + branch: gh-pages + folder: target/criterion/ \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index e45be309..1b6a2e9a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,47 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bstr" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +dependencies = [ + "lazy_static", + "memchr", + "regex-automata", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" + [[package]] name = "byteorder" version = "1.4.3" @@ -20,12 +55,210 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +[[package]] +name = "cast" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c24dab4283a142afa2fdca129b80ad2c6284e073930f964c3a1293c225ee39a" +dependencies = [ + "rustc_version", +] + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "clap" +version = "2.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +dependencies = [ + "bitflags", + "textwrap", + "unicode-width", +] + +[[package]] +name = "criterion" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10" +dependencies = [ + "atty", + "cast", + "clap", + "criterion-plot", + "csv", + "futures", + "itertools", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_cbor", + "serde_derive", + "serde_json", + "tinytemplate", + "tokio", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d00996de9f2f7559f7f4dc286073197f83e92256a59ed395f9aac01fe717da57" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "csv" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" +dependencies = [ + "bstr", + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +dependencies = [ + "memchr", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "futures" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" + +[[package]] +name = "futures-io" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" + +[[package]] +name = "futures-sink" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" + +[[package]] +name = "futures-task" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" + +[[package]] +name = "futures-util" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" +dependencies = [ + "autocfg", + "futures-core", + "futures-sink", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -35,6 +268,30 @@ dependencies = [ "libc", ] +[[package]] +name = "itertools" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + +[[package]] +name = "js-sys" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -62,6 +319,15 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +[[package]] +name = "memoffset" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +dependencies = [ + "autocfg", +] + [[package]] name = "mio" version = "0.7.13" @@ -112,12 +378,52 @@ dependencies = [ "libc", ] +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + [[package]] name = "pin-project-lite" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "plotters" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d88417318da0eaf0fdcdb51a0ee6c3bed624333bff8f946733049380be67ac1c" + +[[package]] +name = "plotters-svg" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521fa9638fa597e1dc53e9412a4f9cefb01187ee1f7413076f9e6749e2885ba9" +dependencies = [ + "plotters-backend", +] + [[package]] name = "proc-macro2" version = "1.0.29" @@ -136,6 +442,52 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rayon" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + [[package]] name = "rmp" version = "0.8.10" @@ -148,14 +500,15 @@ dependencies = [ [[package]] name = "rmp-ipc" -version = "0.7.0" +version = "0.7.1" dependencies = [ + "criterion", "lazy_static", - "log", "rmp-serde", "serde", "thiserror", "tokio", + "tracing", "typemap_rev", ] @@ -170,6 +523,42 @@ dependencies = [ "serde", ] +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "semver" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" + [[package]] name = "serde" version = "1.0.130" @@ -179,6 +568,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + [[package]] name = "serde_derive" version = "1.0.130" @@ -190,6 +589,17 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "syn" version = "1.0.80" @@ -201,6 +611,15 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + [[package]] name = "thiserror" version = "1.0.30" @@ -221,6 +640,16 @@ dependencies = [ "syn", ] +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "tokio" version = "1.12.0" @@ -249,18 +678,131 @@ dependencies = [ "syn", ] +[[package]] +name = "tracing" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" +dependencies = [ + "lazy_static", +] + [[package]] name = "typemap_rev" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5b74f0a24b5454580a79abb6994393b09adf0ab8070f15827cb666255de155" +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + [[package]] name = "unicode-xid" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" + +[[package]] +name = "web-sys" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" @@ -277,6 +819,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 9af750e7..99cba423 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rmp-ipc" -version = "0.7.0" +version = "0.7.1" authors = ["trivernis "] edition = "2018" readme = "README.md" @@ -8,12 +8,21 @@ license = "Apache-2.0" repository = "https://github.com/Trivernis/rmp-ipc" description = "IPC using Rust MessagePack (rmp)" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +bench=false + +[[bench]] +name = "serialization_benchmark" +harness = false + +[[bench]] +name = "deserialization_benchmark" +harness = false [dependencies] thiserror = "1.0.30" rmp-serde = "0.15.4" -log = "0.4.14" +tracing = "0.1.29" lazy_static = "1.4.0" typemap_rev = "0.1.5" @@ -25,6 +34,9 @@ features = ["serde_derive"] version = "1.12.0" features = ["net", "io-std", "io-util", "sync", "time"] +[dev-dependencies.criterion] +version = "0.3.5" +features = ["async_tokio", "html_reports"] [dev-dependencies.tokio] version = "1.12.0" diff --git a/README.md b/README.md index d0843361..8403b24b 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,10 @@ async fn main() { } ``` +## Benchmarks + +Benchmarks are generated on each commit. They can be reviewed [here](https://trivernis.github.io/rmp-ipc/report/). + ## License Apache-2.0 \ No newline at end of file diff --git a/benches/deserialization_benchmark.rs b/benches/deserialization_benchmark.rs new file mode 100644 index 00000000..86dbc302 --- /dev/null +++ b/benches/deserialization_benchmark.rs @@ -0,0 +1,41 @@ +use criterion::{black_box, BenchmarkId, Throughput}; +use criterion::{criterion_group, criterion_main}; +use criterion::{BatchSize, Criterion}; +use std::io::Cursor; + +use rmp_ipc::event::Event; +use tokio::runtime::Runtime; + +pub const EVENT_NAME: &str = "bench_event"; + +fn create_event_bytes_reader(data_size: usize) -> Cursor> { + let bytes = Event::new(EVENT_NAME.to_string(), vec![0u8; data_size], None) + .into_bytes() + .unwrap(); + Cursor::new(bytes) +} + +fn event_deserialization(c: &mut Criterion) { + let runtime = Runtime::new().unwrap(); + let mut group = c.benchmark_group("event_deserialization"); + + for size in (0..10) + .step_by(2) + .map(|i| 1024 * 2u32.pow(i as u32) as usize) + { + group.throughput(Throughput::Bytes(size as u64)); + group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| { + b.to_async(&runtime).iter_batched( + || black_box(create_event_bytes_reader(size)), + |mut reader| async move { + Event::from_async_read(&mut reader).await.unwrap(); + }, + BatchSize::LargeInput, + ) + }); + } + group.finish() +} + +criterion_group!(benches, event_deserialization); +criterion_main!(benches); diff --git a/benches/serialization_benchmark.rs b/benches/serialization_benchmark.rs new file mode 100644 index 00000000..865125af --- /dev/null +++ b/benches/serialization_benchmark.rs @@ -0,0 +1,32 @@ +use criterion::{ + black_box, criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion, Throughput, +}; +use rmp_ipc::event::Event; + +pub const EVENT_NAME: &str = "bench_event"; + +fn create_event(data_size: usize) -> Event { + Event::new(EVENT_NAME.to_string(), vec![0u8; data_size], None) +} + +fn event_serialization(c: &mut Criterion) { + let mut group = c.benchmark_group("event_serialization"); + + for size in (0..10) + .step_by(2) + .map(|i| 1024 * 2u32.pow(i as u32) as usize) + { + group.throughput(Throughput::Bytes(size as u64)); + group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, &size| { + b.iter_batched( + || black_box(create_event(size)), + |event| event.into_bytes().unwrap(), + BatchSize::LargeInput, + ) + }); + } + group.finish(); +} + +criterion_group!(benches, event_serialization); +criterion_main!(benches); diff --git a/src/events/event.rs b/src/events/event.rs index 40f3327b..768a55c8 100644 --- a/src/events/event.rs +++ b/src/events/event.rs @@ -2,17 +2,19 @@ use crate::error::Result; use crate::events::generate_event_id; use crate::events::payload::EventReceivePayload; use serde::{Deserialize, Serialize}; +use std::fmt::Debug; use tokio::io::{AsyncRead, AsyncReadExt}; /// A container representing an event and underlying binary data. /// The data can be decoded into an object representation or read /// as raw binary data. +#[derive(Debug)] pub struct Event { header: EventHeader, data: Vec, } -#[derive(Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] struct EventHeader { id: u64, ref_id: Option, @@ -22,6 +24,7 @@ struct EventHeader { impl Event { /// Creates a new event with a namespace + #[tracing::instrument(level = "trace")] pub fn with_namespace( namespace: String, name: String, @@ -38,6 +41,7 @@ impl Event { } /// Creates a new event + #[tracing::instrument(level = "trace")] pub fn new(name: String, data: Vec, ref_id: Option) -> Self { let header = EventHeader { id: generate_event_id(), @@ -60,6 +64,7 @@ impl Event { } /// Decodes the data to the given type + #[tracing::instrument(level = "trace", skip(self))] pub fn data(&self) -> Result { let data = T::from_payload_bytes(&self.data[..])?; @@ -82,16 +87,12 @@ impl Event { } /// Reads an event message + #[tracing::instrument(level = "trace", skip(reader))] pub async fn from_async_read(reader: &mut R) -> Result { let total_length = reader.read_u64().await?; let header_length = reader.read_u16().await?; let data_length = total_length - header_length as u64; - log::trace!( - "Parsing event of length {} ({} header, {} data)", - total_length, - header_length, - data_length - ); + tracing::trace!(total_length, header_length, data_length); let header: EventHeader = { let mut header_bytes = vec![0u8; header_length as usize]; @@ -106,11 +107,13 @@ impl Event { } /// Encodes the event into bytes + #[tracing::instrument(level = "trace")] pub fn into_bytes(mut self) -> Result> { let mut header_bytes = rmp_serde::to_vec(&self.header)?; let header_length = header_bytes.len() as u16; let data_length = self.data.len(); let total_length = header_length as u64 + data_length as u64; + tracing::trace!(total_length, header_length, data_length); let mut buf = Vec::with_capacity(total_length as usize); buf.append(&mut total_length.to_be_bytes().to_vec()); diff --git a/src/events/event_handler.rs b/src/events/event_handler.rs index 78ce5692..7df84bad 100644 --- a/src/events/event_handler.rs +++ b/src/events/event_handler.rs @@ -2,6 +2,7 @@ use crate::error::Result; use crate::events::event::Event; use crate::ipc::context::Context; use std::collections::HashMap; +use std::fmt::{Debug, Formatter}; use std::future::Future; use std::pin::Pin; use std::sync::Arc; @@ -18,6 +19,18 @@ pub struct EventHandler { callbacks: HashMap, } +impl Debug for EventHandler { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let callback_names: String = self + .callbacks + .keys() + .cloned() + .collect::>() + .join(", "); + format!("EventHandler {{callbacks: [{}]}}", callback_names).fmt(f) + } +} + impl EventHandler { /// Creates a new event handler pub fn new() -> Self { @@ -27,6 +40,7 @@ impl EventHandler { } /// Adds a new event callback + #[tracing::instrument(skip(self, callback))] pub fn on(&mut self, name: &str, callback: F) where F: for<'a> Fn( @@ -40,6 +54,7 @@ impl EventHandler { } /// Handles a received event + #[tracing::instrument(level = "debug", skip(self, ctx))] pub async fn handle_event(&self, ctx: &Context, event: Event) -> Result<()> { if let Some(cb) = self.callbacks.get(event.name()) { cb.as_ref()(ctx, event).await?; diff --git a/src/ipc/builder.rs b/src/ipc/builder.rs index 516349b9..cff2d4b3 100644 --- a/src/ipc/builder.rs +++ b/src/ipc/builder.rs @@ -57,11 +57,8 @@ impl IPCBuilder { handler.on(ERROR_EVENT_NAME, |_, event| { Box::pin(async move { let error_data = event.data::()?; - log::warn!( - "Received Error Response from Server: {} - {}", - error_data.code, - error_data.message - ); + tracing::warn!(error_data.code); + tracing::warn!("error_data.message = '{}'", error_data.message); Ok(()) }) @@ -117,6 +114,7 @@ impl IPCBuilder { } /// Builds an ipc server + #[tracing::instrument(skip(self))] pub async fn build_server(self) -> Result<()> { self.validate()?; let server = IPCServer { @@ -130,6 +128,7 @@ impl IPCBuilder { } /// Builds an ipc client + #[tracing::instrument(skip(self))] pub async fn build_client(self) -> Result { self.validate()?; let client = IPCClient { @@ -144,6 +143,7 @@ impl IPCBuilder { } /// Validates that all required fields have been provided + #[tracing::instrument(skip(self))] fn validate(&self) -> Result<()> { if self.address.is_none() { Err(Error::BuildError("Missing Address".to_string())) diff --git a/src/ipc/client.rs b/src/ipc/client.rs index adaae1f2..ba929738 100644 --- a/src/ipc/client.rs +++ b/src/ipc/client.rs @@ -23,6 +23,7 @@ pub struct IPCClient { impl IPCClient { /// Connects to a given address and returns an emitter for events to that address. /// Invoked by [IPCBuilder::build_client](crate::builder::IPCBuilder::build_client) + #[tracing::instrument(skip(self))] pub async fn connect(self, address: &str) -> Result { let stream = TcpStream::connect(address).await?; let (read_half, write_half) = stream.into_split(); @@ -35,7 +36,6 @@ impl IPCClient { ); let handler = Arc::new(self.handler); let namespaces = Arc::new(self.namespaces); - log::debug!("IPC client connected to {}", address); let handle = tokio::spawn({ let ctx = Context::clone(&ctx); diff --git a/src/ipc/context.rs b/src/ipc/context.rs index e625c25d..81914c83 100644 --- a/src/ipc/context.rs +++ b/src/ipc/context.rs @@ -48,6 +48,7 @@ impl Context { } /// Waits for a reply to the given message ID + #[tracing::instrument(level = "debug", skip(self))] pub async fn await_reply(&self, message_id: u64) -> Result { let (rx, tx) = oneshot::channel(); { @@ -60,6 +61,7 @@ impl Context { } /// Stops the listener and closes the connection + #[tracing::instrument(level = "debug", skip(self))] pub async fn stop(self) -> Result<()> { let mut sender = self.stop_sender.lock().await; if let Some(sender) = mem::take(&mut *sender) { diff --git a/src/ipc/mod.rs b/src/ipc/mod.rs index 3a84923c..e6e196af 100644 --- a/src/ipc/mod.rs +++ b/src/ipc/mod.rs @@ -20,11 +20,11 @@ async fn handle_connection( ctx: Context, ) { while let Ok(event) = Event::from_async_read(&mut read_half).await { - log::debug!("Received {:?}:{} event", event.namespace(), event.name()); + tracing::trace!("event = {:?}", event); // check if the event is a reply if let Some(ref_id) = event.reference_id() { + tracing::trace!("Event has reference id. Passing to reply listener"); // get the listener for replies - log::trace!("Event is response to {}", ref_id); if let Some(sender) = ctx.get_reply_sender(ref_id).await { // try sending the event to the listener for replies if let Err(event) = sender.send(event) { @@ -32,18 +32,18 @@ async fn handle_connection( } continue; } - log::trace!("No response listener found for event. Passing to regular listener."); + tracing::trace!("No response listener found for event. Passing to regular listener."); } if let Some(namespace) = event.namespace().clone().and_then(|n| namespaces.get(&n)) { - log::trace!("Passing event to namespace listener"); + tracing::trace!("Passing event to namespace listener"); let handler = Arc::clone(&namespace.handler); handle_event(Context::clone(&ctx), handler, event); } else { - log::trace!("Passing event to global listener"); + tracing::trace!("Passing event to global listener"); handle_event(Context::clone(&ctx), Arc::clone(&handler), event); } } - log::debug!("Connection closed."); + tracing::debug!("Connection closed."); } /// Handles a single event in a different tokio context @@ -64,9 +64,9 @@ fn handle_event(ctx: Context, handler: Arc, event: Event) { ) .await { - log::error!("Error occurred when sending error response: {:?}", e); + tracing::error!("Error occurred when sending error response: {:?}", e); } - log::error!("Failed to handle event: {:?}", e); + tracing::error!("Failed to handle event: {:?}", e); } }); } diff --git a/src/ipc/server.rs b/src/ipc/server.rs index 6926eb60..d1ed1113 100644 --- a/src/ipc/server.rs +++ b/src/ipc/server.rs @@ -22,14 +22,17 @@ pub struct IPCServer { impl IPCServer { /// Starts the IPC Server. /// Invoked by [IPCBuilder::build_server](crate::builder::IPCBuilder::build_server) + #[tracing::instrument(skip(self))] pub async fn start(self, address: &str) -> Result<()> { let listener = TcpListener::bind(address).await?; let handler = Arc::new(self.handler); let namespaces = Arc::new(self.namespaces); let data = Arc::new(RwLock::new(self.data)); - log::debug!("IPC server listening on {}", address); + tracing::info!(address); - while let Ok((stream, _)) = listener.accept().await { + while let Ok((stream, remote_address)) = listener.accept().await { + let remote_address = remote_address.to_string(); + tracing::debug!("remote_address = {}", remote_address); let handler = Arc::clone(&handler); let namespaces = Arc::clone(&namespaces); let data = Arc::clone(&data); diff --git a/src/ipc/stream_emitter.rs b/src/ipc/stream_emitter.rs index b0c7a787..37cbef91 100644 --- a/src/ipc/stream_emitter.rs +++ b/src/ipc/stream_emitter.rs @@ -2,11 +2,11 @@ use crate::error::Result; use crate::events::event::Event; use crate::events::payload::EventSendPayload; use crate::ipc::context::Context; +use std::fmt::Debug; use std::sync::Arc; use tokio::io::AsyncWriteExt; use tokio::net::tcp::OwnedWriteHalf; use tokio::sync::Mutex; -use tokio::time::Instant; /// An abstraction over the raw tokio tcp stream /// to emit events and share a connection across multiple @@ -23,7 +23,8 @@ impl StreamEmitter { } } - pub async fn _emit( + #[tracing::instrument(level = "trace", skip(self))] + pub async fn _emit( &self, namespace: Option<&str>, event: &str, @@ -31,7 +32,6 @@ impl StreamEmitter { res_id: Option, ) -> Result { let data_bytes = data.to_payload_bytes()?; - log::debug!("Emitting event {:?}:{}", namespace, event); let event = if let Some(namespace) = namespace { Event::with_namespace(namespace.to_string(), event.to_string(), data_bytes, res_id) @@ -43,17 +43,16 @@ impl StreamEmitter { let event_bytes = event.into_bytes()?; { - let start = Instant::now(); let mut stream = self.stream.lock().await; (*stream).write_all(&event_bytes[..]).await?; - log::trace!("Wrote {} bytes in {:?}", event_bytes.len(), start.elapsed()); + tracing::trace!(bytes_len = event_bytes.len()); } Ok(EmitMetadata::new(event_id)) } /// Emits an event - pub async fn emit, T: EventSendPayload>( + pub async fn emit, T: EventSendPayload + Debug>( &self, event: S, data: T, @@ -62,7 +61,7 @@ impl StreamEmitter { } /// Emits an event to a specific namespace - pub async fn emit_to, S2: AsRef, T: EventSendPayload>( + pub async fn emit_to, S2: AsRef, T: EventSendPayload + Debug>( &self, namespace: S1, event: S2, @@ -73,7 +72,7 @@ impl StreamEmitter { } /// Emits a response to an event - pub async fn emit_response, T: EventSendPayload>( + pub async fn emit_response, T: EventSendPayload + Debug>( &self, event_id: u64, event: S, @@ -83,7 +82,7 @@ impl StreamEmitter { } /// Emits a response to an event to a namespace - pub async fn emit_response_to, S2: AsRef, T: EventSendPayload>( + pub async fn emit_response_to, S2: AsRef, T: EventSendPayload + Debug>( &self, event_id: u64, namespace: S1, diff --git a/src/namespaces/builder.rs b/src/namespaces/builder.rs index 9f9dd214..45862c7b 100644 --- a/src/namespaces/builder.rs +++ b/src/namespaces/builder.rs @@ -38,6 +38,7 @@ impl NamespaceBuilder { } /// Builds the namespace + #[tracing::instrument(skip(self))] pub fn build(self) -> IPCBuilder { let namespace = Namespace::new(self.name, self.handler); self.ipc_builder.add_namespace(namespace) diff --git a/src/namespaces/namespace.rs b/src/namespaces/namespace.rs index 4659eeb8..72dc77c8 100644 --- a/src/namespaces/namespace.rs +++ b/src/namespaces/namespace.rs @@ -1,7 +1,7 @@ use crate::events::event_handler::EventHandler; use std::sync::Arc; -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Namespace { name: String, pub(crate) handler: Arc, diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 8f29a871..9c52e641 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,3 +1,3 @@ +mod event_tests; mod ipc_tests; mod utils; -mod event_tests; diff --git a/src/tests/utils.rs b/src/tests/utils.rs index 0804847d..f3c4507e 100644 --- a/src/tests/utils.rs +++ b/src/tests/utils.rs @@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize}; use std::time::SystemTime; use tokio::sync::oneshot; -#[derive(Clone, Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize, Debug)] pub struct PingEventData { pub time: SystemTime, pub ttl: u8,