diff --git a/Cargo.lock b/Cargo.lock index 358b85c32068..82cea6dee64f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,10 +1,16 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "adler32" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" + [[package]] name = "aho-corasick" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f56c476256dc249def911d6f7580b5fc7e875895b5d7ee88f5d602208035744" +checksum = "743ad5a418686aad3b87fd14c43badd828cf26e214a00f92a384291cf22e1811" dependencies = [ "memchr", ] @@ -85,9 +91,9 @@ checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" [[package]] name = "backtrace" -version = "0.3.43" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f80256bc78f67e7df7e36d77366f636ed976895d91fe2ab9efa3973e8fe8c4f" +checksum = "e4036b9bf40f3cf16aba72a3d65e8a520fc4bafcdc7079aea8f848c58c5b5536" dependencies = [ "backtrace-sys", "cfg-if", @@ -159,8 +165,8 @@ dependencies = [ "lazycell", "log", "peeking_take_while", - "proc-macro2", - "quote", + "proc-macro2 1.0.8", + "quote 1.0.2", "regex", "rustc-hash", "shlex", @@ -213,9 +219,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "byteorder" -version = "1.3.2" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" [[package]] name = "c2-chacha" @@ -354,7 +360,7 @@ dependencies = [ "log", "serde", "smallvec", - "target-lexicon", + "target-lexicon 0.10.0", "thiserror", ] @@ -392,7 +398,7 @@ dependencies = [ "cranelift-codegen", "log", "smallvec", - "target-lexicon", + "target-lexicon 0.10.0", ] [[package]] @@ -403,7 +409,7 @@ checksum = "564ee82268bc25b914fcf331edfc2452f2d9ca34f976b187b4ca668beba250c8" dependencies = [ "cranelift-codegen", "raw-cpuid", - "target-lexicon", + "target-lexicon 0.10.0", ] [[package]] @@ -421,6 +427,15 @@ dependencies = [ "wasmparser 0.48.2", ] +[[package]] +name = "crc32fast" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" +dependencies = [ + "cfg-if", +] + [[package]] name = "crossbeam-deque" version = "0.7.2" @@ -472,8 +487,8 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd8ce37ad4184ab2ce004c33bf6379185d3b1c95801cab51026bd271bf68eedc" dependencies = [ - "quote", - "syn", + "quote 1.0.2", + "syn 1.0.14", ] [[package]] @@ -491,8 +506,8 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dab2f0544254a47cabc58956cc7ebda74c3b796bb2761e3fe8f29fdde632ad95" dependencies = [ - "proc-macro2", - "syn", + "proc-macro2 1.0.8", + "syn 1.0.14", "synstructure", ] @@ -537,9 +552,9 @@ dependencies = [ "byteorder", "lazy_static", "owning_ref", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.8", + "quote 1.0.2", + "syn 1.0.14", ] [[package]] @@ -612,15 +627,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74b9ed6159e4a6212c61d9c6a86bee01876b192a64accecf58d5b5ae3b667b52" dependencies = [ "anyhow", - "goblin", + "goblin 0.1.3", "indexmap", "log", - "scroll", + "scroll 0.10.1", "string-interner", - "target-lexicon", + "target-lexicon 0.10.0", "thiserror", ] +[[package]] +name = "failure" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" +dependencies = [ + "failure_derive", +] + +[[package]] +name = "failure_derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" +dependencies = [ + "proc-macro2 1.0.8", + "quote 1.0.2", + "syn 1.0.14", + "synstructure", +] + [[package]] name = "fake-simd" version = "0.1.2" @@ -655,6 +691,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "flate2" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bd6d6f4752952feb71363cffc9ebac9411b75b87c6ab6058c40c8900cf43c0f" +dependencies = [ + "cfg-if", + "crc32fast", + "libc", + "miniz_oxide", +] + [[package]] name = "gcc" version = "0.3.55" @@ -687,9 +735,9 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a36606a68532b5640dc86bb1f33c64b45c4682aad4c50f3937b317ea387f3d6" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.8", + "quote 1.0.2", + "syn 1.0.14", ] [[package]] @@ -721,6 +769,28 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +[[package]] +name = "goblin" +version = "0.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f55d53401eb2fd30afd025c570b1946b6966344acf21b42e31286f3bf89e6a8" +dependencies = [ + "log", + "plain", + "scroll 0.9.2", +] + +[[package]] +name = "goblin" +version = "0.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3fa261d919c1ae9d1e4533c4a2f99e10938603c4208d56c05bec7a872b661b0" +dependencies = [ + "log", + "plain", + "scroll 0.9.2", +] + [[package]] name = "goblin" version = "0.1.3" @@ -729,7 +799,7 @@ checksum = "3081214398d39e4bd7f2c1975f0488ed04614ffdd976c6fc7a0708278552c0da" dependencies = [ "log", "plain", - "scroll", + "scroll 0.10.1", ] [[package]] @@ -767,9 +837,9 @@ checksum = "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005" [[package]] name = "indexmap" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b54058f0a6ff80b6803da8faf8997cde53872b38f4023728f6830b06cd3c0dc" +checksum = "076f042c5b7b98f31d205f1249267e12a6518c1481e9dae9764af19b707d2292" dependencies = [ "autocfg 1.0.0", ] @@ -791,9 +861,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b714fc08d0961716390977cdff1536234415ac37b509e34e5a983def8340fb75" dependencies = [ "proc-macro-hack", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.8", + "quote 1.0.2", + "syn 1.0.14", "unindent", ] @@ -814,9 +884,9 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a8e30575afe28eea36a9a39136b70b2fb6b0dd0a212a5bd1f30a498395c0274" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.8", + "quote 1.0.2", + "syn 1.0.14", ] [[package]] @@ -953,6 +1023,15 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "miniz_oxide" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa679ff6578b1cddee93d7e82e263b94a575e0bfced07284eb0c037c1d2416a5" +dependencies = [ + "adler32", +] + [[package]] name = "more-asserts" version = "0.2.1" @@ -1055,6 +1134,19 @@ dependencies = [ "libc", ] +[[package]] +name = "object" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df4af347f5ac3d0e83e78c26be33cd10e8e874dcb68517a909ad802ba50a90b5" +dependencies = [ + "flate2", + "goblin 0.0.22", + "parity-wasm", + "scroll 0.9.2", + "uuid", +] + [[package]] name = "opaque-debug" version = "0.2.3" @@ -1080,6 +1172,12 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "parity-wasm" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20d7e522a7f994cc4ae32970b1ce0d99ecf91b8e1df080517a26faa6d2e2ee62" + [[package]] name = "paste" version = "0.1.6" @@ -1097,9 +1195,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4214c9e912ef61bf42b81ba9a47e8aad1b2ffaf739ab162bf96d1e011f54e6c5" dependencies = [ "proc-macro-hack", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.8", + "quote 1.0.2", + "syn 1.0.14", ] [[package]] @@ -1138,10 +1236,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "875077759af22fa20b610ad4471d8155b321c89c3f2785526c9839b099be4e0a" dependencies = [ "proc-macro-error-attr", - "proc-macro2", - "quote", + "proc-macro2 1.0.8", + "quote 1.0.2", "rustversion", - "syn", + "syn 1.0.14", ] [[package]] @@ -1150,10 +1248,10 @@ version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5717d9fa2664351a01ed73ba5ef6df09c01a521cb42cb65a061432a826f3c7a" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.8", + "quote 1.0.2", "rustversion", - "syn", + "syn 1.0.14", "syn-mid", ] @@ -1163,9 +1261,18 @@ version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.8", + "quote 1.0.2", + "syn 1.0.14", +] + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid 0.1.0", ] [[package]] @@ -1174,7 +1281,7 @@ version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548" dependencies = [ - "unicode-xid", + "unicode-xid 0.2.0", ] [[package]] @@ -1204,9 +1311,9 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4882d8237fd8c7373cc25cb802fe0dab9ff70830fd56f47ef6c7f3f287fcc057" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.8", + "quote 1.0.2", + "syn 1.0.14", ] [[package]] @@ -1215,10 +1322,10 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdf321cfab555f7411298733c86d21e5136f5ded13f5872fabf9de3337beecda" dependencies = [ - "proc-macro2", + "proc-macro2 1.0.8", "pyo3-derive-backend", - "quote", - "syn", + "quote 1.0.2", + "syn 1.0.14", ] [[package]] @@ -1239,13 +1346,22 @@ dependencies = [ "rand_core", ] +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +dependencies = [ + "proc-macro2 0.4.30", +] + [[package]] name = "quote" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" dependencies = [ - "proc-macro2", + "proc-macro2 1.0.8", ] [[package]] @@ -1410,12 +1526,9 @@ checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" [[package]] name = "rustc-hash" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" -dependencies = [ - "byteorder", -] +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc_version" @@ -1432,9 +1545,9 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3bba175698996010c4f6dce5e7f173b6eb781fce25d2cfc45e27091ce0b79f6" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.8", + "quote 1.0.2", + "syn 1.0.14", ] [[package]] @@ -1449,13 +1562,34 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" +[[package]] +name = "scroll" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f84d114ef17fd144153d608fba7c446b0145d038985e7a8cc5d08bb0ce20383" +dependencies = [ + "rustc_version", + "scroll_derive 0.9.5", +] + [[package]] name = "scroll" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abb2332cb595d33f7edd5700f4cbf94892e680c7f0ae56adab58a35190b66cb1" dependencies = [ - "scroll_derive", + "scroll_derive 0.10.1", +] + +[[package]] +name = "scroll_derive" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1aa96c45e7f5a91cb7fabe7b279f02fea7126239fc40b732316e8b6a2d0fcb" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", ] [[package]] @@ -1464,9 +1598,9 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8584eea9b9ff42825b46faf46a8c24d2cff13ec152fa2a50df788b87c07ee28" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.8", + "quote 1.0.2", + "syn 1.0.14", ] [[package]] @@ -1499,16 +1633,16 @@ version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.8", + "quote 1.0.2", + "syn 1.0.14", ] [[package]] name = "serde_json" -version = "1.0.46" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b01d7f0288608a01dca632cf1df859df6fd6ffa885300fc275ce2ba6221953" +checksum = "15913895b61e0be854afd32fd4163fcd2a3df34142cf2cb961b310ce694cbf90" dependencies = [ "itoa", "ryu", @@ -1585,9 +1719,20 @@ checksum = "095064aa1f5b94d14e635d0a5684cf140c43ae40a0fd990708d38f5d669e5f64" dependencies = [ "heck", "proc-macro-error", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.8", + "quote 1.0.2", + "syn 1.0.14", +] + +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "unicode-xid 0.1.0", ] [[package]] @@ -1596,9 +1741,9 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5" dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", + "proc-macro2 1.0.8", + "quote 1.0.2", + "unicode-xid 0.2.0", ] [[package]] @@ -1607,9 +1752,9 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.8", + "quote 1.0.2", + "syn 1.0.14", ] [[package]] @@ -1618,10 +1763,21 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" dependencies = [ - "proc-macro2", - "quote", - "syn", - "unicode-xid", + "proc-macro2 1.0.8", + "quote 1.0.2", + "syn 1.0.14", + "unicode-xid 0.2.0", +] + +[[package]] +name = "target-lexicon" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b0ab4982b8945c35cc1c46a83a9094c414f6828a099ce5dcaa8ee2b04642dcb" +dependencies = [ + "failure", + "failure_derive", + "serde_json", ] [[package]] @@ -1661,7 +1817,7 @@ dependencies = [ "cfg-if", "os_pipe", "pretty_env_logger", - "target-lexicon", + "target-lexicon 0.10.0", "tempfile", "wasi-common", "wasmtime", @@ -1693,9 +1849,9 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57e4d2e50ca050ed44fb58309bdce3efa79948f84f9993ad1978de5eebdce5a7" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.8", + "quote 1.0.2", + "syn 1.0.14", ] [[package]] @@ -1760,6 +1916,12 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + [[package]] name = "unicode-xid" version = "0.2.0" @@ -1781,6 +1943,12 @@ dependencies = [ "traitobject", ] +[[package]] +name = "uuid" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" + [[package]] name = "vec_map" version = "0.8.1" @@ -1820,9 +1988,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8757b0da38353d55a9687f4dee68a8f441f980dd36e16ab07d6e6c673f505f76" dependencies = [ "heck", - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.8", + "quote 1.0.2", + "syn 1.0.14", ] [[package]] @@ -1905,11 +2073,12 @@ dependencies = [ "rayon", "region", "rustc-demangle", - "target-lexicon", + "target-lexicon 0.10.0", "wasi-common", "wasmparser 0.51.1", "wasmtime-environ", "wasmtime-jit", + "wasmtime-profiling", "wasmtime-runtime", "wat", "winapi", @@ -1934,7 +2103,7 @@ dependencies = [ "pretty_env_logger", "rayon", "structopt", - "target-lexicon", + "target-lexicon 0.10.0", "tempfile", "test-programs", "wasi-common", @@ -1945,6 +2114,7 @@ dependencies = [ "wasmtime-interface-types", "wasmtime-jit", "wasmtime-obj", + "wasmtime-profiling", "wasmtime-runtime", "wasmtime-wasi", "wasmtime-wast", @@ -1959,7 +2129,7 @@ dependencies = [ "faerie", "gimli 0.19.0", "more-asserts", - "target-lexicon", + "target-lexicon 0.10.0", "thiserror", "wasmparser 0.51.1", "wasmtime-environ", @@ -1990,7 +2160,7 @@ dependencies = [ "rayon", "serde", "sha2", - "target-lexicon", + "target-lexicon 0.10.0", "tempfile", "thiserror", "toml", @@ -2052,11 +2222,12 @@ dependencies = [ "cranelift-wasm", "more-asserts", "region", - "target-lexicon", + "target-lexicon 0.10.0", "thiserror", "wasmparser 0.51.1", "wasmtime-debug", "wasmtime-environ", + "wasmtime-profiling", "wasmtime-runtime", "winapi", ] @@ -2071,6 +2242,20 @@ dependencies = [ "wasmtime-environ", ] +[[package]] +name = "wasmtime-profiling" +version = "0.1.0" +dependencies = [ + "gimli 0.19.0", + "goblin 0.0.24", + "lazy_static", + "libc", + "object", + "scroll 0.9.2", + "serde", + "target-lexicon 0.4.0", +] + [[package]] name = "wasmtime-py" version = "0.9.0" @@ -2078,7 +2263,7 @@ dependencies = [ "anyhow", "pyo3", "region", - "target-lexicon", + "target-lexicon 0.10.0", "wasmparser 0.51.1", "wasmtime", "wasmtime-interface-types", @@ -2099,6 +2284,7 @@ dependencies = [ "region", "thiserror", "wasmtime-environ", + "wasmtime-profiling", "winapi", ] @@ -2117,9 +2303,9 @@ dependencies = [ name = "wasmtime-rust-macro" version = "0.9.0" dependencies = [ - "proc-macro2", - "quote", - "syn", + "proc-macro2 1.0.8", + "quote 1.0.2", + "syn 1.0.14", ] [[package]] @@ -2184,8 +2370,8 @@ name = "wig" version = "0.9.2" dependencies = [ "heck", - "proc-macro2", - "quote", + "proc-macro2 1.0.8", + "quote 1.0.2", "witx", ] diff --git a/Cargo.toml b/Cargo.toml index 8bceb9ba7518..45467fd5867b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ wasmtime-environ = { path = "crates/environ" } wasmtime-interface-types = { path = "crates/interface-types" } wasmtime-jit = { path = "crates/jit" } wasmtime-obj = { path = "crates/obj" } +wasmtime-profiling = { path = "crates/profiling" } wasmtime-wast = { path = "crates/wast" } wasmtime-wasi = { path = "crates/wasi" } wasi-common = { path = "crates/wasi-common" } @@ -74,6 +75,7 @@ lightbeam = [ "wasmtime-wast/lightbeam", "wasmtime/lightbeam", ] +profiling = ["wasmtime-jit/profiling", "wasmtime/profiling", "wasmtime-profiling/profiling"] test_programs = ["test-programs/test_programs"] [badges] diff --git a/crates/api/Cargo.toml b/crates/api/Cargo.toml index 599d5ea9b86c..722abb9972ca 100644 --- a/crates/api/Cargo.toml +++ b/crates/api/Cargo.toml @@ -12,6 +12,7 @@ edition = "2018" wasmtime-runtime = { path = "../runtime", version = "0.9.0" } wasmtime-environ = { path = "../environ", version = "0.9.0" } wasmtime-jit = { path = "../jit", version = "0.9.0" } +wasmtime-profiling = { path = "../profiling" } wasmparser = "0.51.1" target-lexicon = { version = "0.10.0", default-features = false } anyhow = "1.0.19" @@ -44,3 +45,4 @@ default = ['wat'] # to cranelift. Requires Nightly Rust currently, and this is not enabled by # default. lightbeam = ["wasmtime-jit/lightbeam"] +profiling = [] diff --git a/crates/api/src/module.rs b/crates/api/src/module.rs index c8f159e551c1..dd463d2fc55d 100644 --- a/crates/api/src/module.rs +++ b/crates/api/src/module.rs @@ -253,6 +253,7 @@ impl Module { &mut store.compiler_mut(), binary, store.engine().config().debug_info, + store.engine().config().profiler.as_ref(), )?; let names = Arc::new(Names { diff --git a/crates/api/src/runtime.rs b/crates/api/src/runtime.rs index 705491807991..09dea30bd777 100644 --- a/crates/api/src/runtime.rs +++ b/crates/api/src/runtime.rs @@ -3,11 +3,12 @@ use std::cell::RefCell; use std::fmt; use std::path::Path; use std::rc::Rc; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use wasmparser::{OperatorValidatorConfig, ValidatingParserConfig}; use wasmtime_environ::settings::{self, Configurable}; use wasmtime_environ::CacheConfig; use wasmtime_jit::{native, CompilationStrategy, Compiler}; +use wasmtime_profiling::{JitDumpAgent, ProfilingAgent, ProfilingStrategy}; // Runtime Environment @@ -25,6 +26,7 @@ pub struct Config { pub(crate) debug_info: bool, pub(crate) strategy: CompilationStrategy, pub(crate) cache_config: CacheConfig, + pub(crate) profiler: Option>>>, } impl Config { @@ -58,6 +60,7 @@ impl Config { flags, strategy: CompilationStrategy::Auto, cache_config: CacheConfig::new_cache_disabled(), + profiler: None, } } @@ -212,6 +215,20 @@ impl Config { Ok(self) } + /// Creates a default profiler based on the profiling strategy choosen + /// + /// Profiler creation calls the type's default initializer where the purpose is + /// really just to put in place the type used for profiling. + pub fn profiler(&mut self, profile: ProfilingStrategy) -> Result<&mut Self> { + match profile { + ProfilingStrategy::JitDumpProfiler => { + self.profiler = { Some(Arc::new(Mutex::new(Box::new(JitDumpAgent::default())))) } + } + _ => self.profiler = { None }, + }; + Ok(self) + } + /// Configures whether the debug verifier of Cranelift is enabled or not. /// /// When Cranelift is used as a code generation backend this will configure diff --git a/crates/jit/Cargo.toml b/crates/jit/Cargo.toml index 2212663384c5..2e426b1badc8 100644 --- a/crates/jit/Cargo.toml +++ b/crates/jit/Cargo.toml @@ -19,6 +19,7 @@ cranelift-frontend = "0.58.0" wasmtime-environ = { path = "../environ", version = "0.9.0" } wasmtime-runtime = { path = "../runtime", version = "0.9.0" } wasmtime-debug = { path = "../debug", version = "0.9.0" } +wasmtime-profiling = { path = "../profiling" } region = "2.0.0" thiserror = "1.0.4" target-lexicon = { version = "0.10.0", default-features = false } @@ -32,6 +33,7 @@ winapi = { version = "0.3.7", features = ["winnt", "impl-default"] } [features] lightbeam = ["wasmtime-environ/lightbeam"] +profiling = ["wasmtime-profiling/profiling"] [badges] maintenance = { status = "actively-developed" } diff --git a/crates/jit/src/code_memory.rs b/crates/jit/src/code_memory.rs index 2eb4806364a4..4670f40dfc67 100644 --- a/crates/jit/src/code_memory.rs +++ b/crates/jit/src/code_memory.rs @@ -5,6 +5,7 @@ use region; use std::mem::ManuallyDrop; use std::{cmp, mem}; use wasmtime_environ::{Compilation, CompiledFunction}; +use wasmtime_profiling::ProfilingAgent; use wasmtime_runtime::{Mmap, VMFunctionBody}; struct CodeMemoryEntry { @@ -230,4 +231,22 @@ impl CodeMemory { Ok(()) } + + /// Calls the module_load for a given ProfilerAgent. Includes + /// all memory address and length for the given module. + /// TODO: Properly handle the possibilities of multiple mmapped regions + /// which may, amongst other things, influence being more specific about + /// the module name. + pub fn profiler_module_load( + &mut self, + profiler: &mut Box, + module_name: &str, + dbg_image: Option<&[u8]>, + ) -> () { + for CodeMemoryEntry { mmap: m, table: _t } in &mut self.entries { + if m.len() > 0 { + profiler.module_load(module_name, m.as_ptr(), m.len(), dbg_image); + } + } + } } diff --git a/crates/jit/src/compiler.rs b/crates/jit/src/compiler.rs index 21a274eb23f6..34f55ae57142 100644 --- a/crates/jit/src/compiler.rs +++ b/crates/jit/src/compiler.rs @@ -20,6 +20,7 @@ use wasmtime_environ::{ Compiler as _C, FunctionBodyData, Module, ModuleMemoryOffset, ModuleVmctxInfo, Relocations, Traps, Tunables, VMOffsets, }; +use wasmtime_profiling::ProfilingAgent; use wasmtime_runtime::{ InstantiationError, SignatureRegistry, TrapRegistration, TrapRegistry, VMFunctionBody, }; @@ -240,6 +241,16 @@ impl Compiler { self.code_memory.publish(); } + pub(crate) fn profiler_module_load( + &mut self, + profiler: &mut Box, + module_name: &str, + dbg_image: Option<&[u8]>, + ) -> () { + self.code_memory + .profiler_module_load(profiler, module_name, dbg_image); + } + /// Shared signature registry. pub fn signatures(&self) -> &SignatureRegistry { &self.signatures diff --git a/crates/jit/src/instantiate.rs b/crates/jit/src/instantiate.rs index f6b33e41ffe3..66d24e32a43f 100644 --- a/crates/jit/src/instantiate.rs +++ b/crates/jit/src/instantiate.rs @@ -9,7 +9,7 @@ use crate::link::link_module; use crate::resolver::Resolver; use std::io::Write; use std::rc::Rc; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use thiserror::Error; use wasmtime_debug::read_debuginfo; use wasmtime_environ::entity::{BoxedSlice, PrimaryMap}; @@ -17,6 +17,8 @@ use wasmtime_environ::wasm::{DefinedFuncIndex, SignatureIndex}; use wasmtime_environ::{ CompileError, DataInitializer, DataInitializerLocation, Module, ModuleEnvironment, }; + +use wasmtime_profiling::ProfilingAgent; use wasmtime_runtime::{ GdbJitImageRegistration, InstanceHandle, InstantiationError, TrapRegistration, VMFunctionBody, VMSharedSignatureIndex, @@ -61,6 +63,7 @@ impl<'data> RawCompiledModule<'data> { compiler: &mut Compiler, data: &'data [u8], debug_info: bool, + profiler: Option<&Arc>>>, ) -> Result { let environ = ModuleEnvironment::new(compiler.frontend_config(), compiler.tunables()); @@ -103,6 +106,23 @@ impl<'data> RawCompiledModule<'data> { // Make all code compiled thus far executable. compiler.publish_compiled_code(); + // Initialize profiler and load the wasm module + let _: Option> = match profiler { + Some(_) => { + let region_name = String::from("wasm_module"); + let mut profiler_new = profiler.unwrap().lock().unwrap().clone(); + profiler_new.init().ok(); + match &dbg_image { + Some(dbg) => { + compiler.profiler_module_load(&mut profiler_new, ®ion_name, Some(&dbg)) + } + _ => compiler.profiler_module_load(&mut profiler_new, ®ion_name, None), + }; + Some(profiler_new) + } + _ => None, + }; + let dbg_jit_registration = if let Some(img) = dbg_image { let mut bytes = Vec::new(); bytes.write_all(&img).expect("all written"); @@ -139,8 +159,9 @@ impl CompiledModule { compiler: &mut Compiler, data: &'data [u8], debug_info: bool, + profiler: Option<&Arc>>>, ) -> Result { - let raw = RawCompiledModule::<'data>::new(compiler, data, debug_info)?; + let raw = RawCompiledModule::<'data>::new(compiler, data, debug_info, profiler)?; Ok(Self::from_parts( raw.module, @@ -246,7 +267,7 @@ impl OwnedDataInitializer { /// Create a new wasm instance by compiling the wasm module in `data` and instatiating it. /// -/// This is equivalent to createing a `CompiledModule` and calling `instantiate()` on it, +/// This is equivalent to creating a `CompiledModule` and calling `instantiate()` on it, /// but avoids creating an intermediate copy of the data initializers. /// /// # Unsafety @@ -258,7 +279,9 @@ pub unsafe fn instantiate( data: &[u8], resolver: &mut dyn Resolver, debug_info: bool, + profiler: Option<&Arc>>>, ) -> Result { - let instance = CompiledModule::new(compiler, data, debug_info)?.instantiate(resolver)?; + let instance = + CompiledModule::new(compiler, data, debug_info, profiler)?.instantiate(resolver)?; Ok(instance) } diff --git a/crates/profiling/Cargo.toml b/crates/profiling/Cargo.toml new file mode 100644 index 000000000000..1d621e657efe --- /dev/null +++ b/crates/profiling/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "wasmtime-profiling" +version = "0.1.0" +authors = ["The Wasmtime Project Developers"] +description = "Runtime library support for Wasmtime" +license = "Apache-2.0 WITH LLVM-exception" +categories = ["wasm"] +keywords = ["webassembly", "wasm"] +repository = "https://github.com/bytecodealliance/wasmtime" +readme = "README.md" +edition = "2018" + +[dependencies] +libc = { version = "0.2.60", default-features = false } +goblin = "0.0.24" +serde = { version = "1.0.99", features = ["derive"] } +scroll = "0.9.2" +gimli = "0.19.0" +object = "0.12.0" +target-lexicon = "0.4.0" +lazy_static = "1.4" + +[badges] +maintenance = { status = "actively-developed" } + +[features] +profiling = [] diff --git a/crates/profiling/src/jitdump.rs b/crates/profiling/src/jitdump.rs new file mode 100644 index 000000000000..fb5c79aaef5a --- /dev/null +++ b/crates/profiling/src/jitdump.rs @@ -0,0 +1,720 @@ +//! Support for jitdump files which can be used by perf for profiling jitted code. +//! Spec definitions for the output format is as described here: +//! https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/perf/Documentation/jitdump-specification.txt +//! +//! Usage Example: +//! Record +//! sudo perf record -k 1 -e instructions:u target/debug/wasmtime -g --jitdump test.wasm +//! Combine +//! sudo perf inject -v -j -i perf.data -o perf.jit.data +//! Report +//! sudo perf report -i perf.jit.data -F+period,srcline +//! Note: For descriptive results, the WASM file being executed should contain dwarf debug data +use libc::c_int; +#[cfg(not(target_os = "windows"))] +use libc::{c_void, clock_gettime, mmap, open, sysconf}; +use object::Object; +use scroll::{IOwrite, SizeWith, NATIVE}; +use serde::{Deserialize, Serialize}; +#[cfg(not(target_os = "windows"))] +use std::ffi::CString; +use std::fmt::Debug; +use std::fs::File; +use std::io::Write; +#[cfg(not(target_os = "windows"))] +use std::os::unix::io::FromRawFd; +use std::{borrow, mem, process}; +use target_lexicon::Architecture; + +#[cfg(target_pointer_width = "64")] +use goblin::elf64 as elf; + +#[cfg(target_pointer_width = "32")] +use goblin::elf32 as elf; + +/// Defines jitdump record types +#[repr(u32)] +pub enum RecordId { + /// Value 0: JIT_CODE_LOAD: record describing a jitted function + JitCodeLoad = 0, + /// Value 1: JIT_CODE_MOVE: record describing an already jitted function which is moved + _JitCodeMove = 1, + /// Value 2: JIT_CODE_DEBUG_INFO: record describing the debug information for a jitted function + JitCodeDebugInfo = 2, + /// Value 3: JIT_CODE_CLOSE: record marking the end of the jit runtime (optional) + _JitCodeClose = 3, + /// Value 4: JIT_CODE_UNWINDING_INFO: record describing a function unwinding information + _JitCodeUnwindingInfo = 4, +} + +/// Each record starts with this fixed size record header which describes the record that follows +#[derive(Serialize, Deserialize, Debug, Default, Clone, Copy, IOwrite, SizeWith)] +#[repr(C)] +pub struct RecordHeader { + /// uint32_t id: a value identifying the record type (see below) + id: u32, + /// uint32_t total_size: the size in bytes of the record including the header. + record_size: u32, + /// uint64_t timestamp: a timestamp of when the record was created. + timestamp: u64, +} + +/// The CodeLoadRecord is used for describing jitted functions +#[derive(Serialize, Deserialize, Debug, Default, Clone, Copy, IOwrite, SizeWith)] +#[repr(C)] +pub struct CodeLoadRecord { + /// Fixed sized header that describes this record + header: RecordHeader, + /// uint32_t pid: OS process id of the runtime generating the jitted code + pid: u32, + /// uint32_t tid: OS thread identification of the runtime thread generating the jitted code + tid: u32, + /// uint64_t vma: virtual address of jitted code start + virtual_address: u64, + /// uint64_t code_addr: code start address for the jitted code. By default vma = code_addr + address: u64, + /// uint64_t code_size: size in bytes of the generated jitted code + size: u64, + /// uint64_t code_index: unique identifier for the jitted code (see below) + index: u64, +} + +/// Describes source line information for a jitted function +#[derive(Serialize, Deserialize, Debug, Default)] +#[repr(C)] +pub struct DebugEntry { + /// uint64_t code_addr: address of function for which the debug information is generated + address: u64, + /// uint32_t line: source file line number (starting at 1) + line: u32, + /// uint32_t discrim: column discriminator, 0 is default + discriminator: u32, + /// char name[n]: source file name in ASCII, including null termination + filename: String, +} + +/// Describes debug information for a jitted function. An array of debug entries are +/// appended to this record during writting. Note, this record must preceed the code +/// load record that describes the same jitted function. +#[derive(Serialize, Deserialize, Debug, Default, Clone, Copy, IOwrite, SizeWith)] +#[repr(C)] +pub struct DebugInfoRecord { + /// Fixed sized header that describes this record + header: RecordHeader, + /// uint64_t code_addr: address of function for which the debug information is generated + address: u64, + /// uint64_t nr_entry: number of debug entries for the function appended to this record + count: u64, +} + +/// Fixed-sized header for each jitdump file +#[derive(Serialize, Deserialize, Debug, Default, IOwrite, SizeWith)] +#[repr(C)] +pub struct FileHeader { + /// uint32_t magic: a magic number tagging the file type. The value is 4-byte long and represents the + /// string "JiTD" in ASCII form. It is 0x4A695444 or 0x4454694a depending on the endianness. The field can + /// be used to detect the endianness of the file + magic: u32, + /// uint32_t version: a 4-byte value representing the format version. It is currently set to 2 + version: u32, + /// uint32_t total_size: size in bytes of file header + size: u32, + /// uint32_t elf_mach: ELF architecture encoding (ELF e_machine value as specified in /usr/include/elf.h) + e_machine: u32, + /// uint32_t pad1: padding. Reserved for future use + pad1: u32, + /// uint32_t pid: JIT runtime process identification (OS specific) + pid: u32, + /// uint64_t timestamp: timestamp of when the file was created + timestamp: u64, + /// uint64_t flags: a bitmask of flags + flags: u64, +} + +/// Interface for driving the creation of jitdump files +#[derive(Debug, Default)] +pub struct JitDumpAgent { + /// File instance for the jit dump file + pub jitdump_file: Option, + /// Unique identifier for jitted code + pub code_index: u64, + /// Flag for experimenting with dumping code load record + /// after each function (true) or after each module. This + /// flag is currently set to true. + pub dump_funcs: bool, +} + +impl JitDumpAgent { + /// Intialize a JitDumpAgent and write out the header + pub fn init(&mut self) -> Result<(), Box> { + #[cfg(target_os = "windows")] + return Err(Error::NulError); + #[cfg(not(target_os = "windows"))] + { + let filename = format!("./jit-{}.dump", process::id()); + let mut jitdump_file; + unsafe { + let filename_c = CString::new(filename)?; + let fd = open( + filename_c.as_ptr(), + libc::O_CREAT | libc::O_TRUNC | libc::O_RDWR, + 0666, + ); + let pgsz = sysconf(libc::_SC_PAGESIZE) as usize; + mmap( + 0 as *mut c_void, + pgsz, + libc::PROT_EXEC | libc::PROT_READ, + libc::MAP_PRIVATE, + fd, + 0, + ); + jitdump_file = File::from_raw_fd(fd); + } + JitDumpAgent::write_file_header(&mut jitdump_file)?; + self.jitdump_file = Some(jitdump_file); + self.code_index = 0; + self.dump_funcs = true; + Ok(()) + } + } + + /// Returns timestamp from a single source + #[allow(unused_variables)] + fn get_time_stamp(timestamp: &mut u64) -> c_int { + #[cfg(not(target_os = "windows"))] + { + unsafe { + let mut ts = mem::MaybeUninit::zeroed().assume_init(); + clock_gettime(libc::CLOCK_MONOTONIC, &mut ts); + // TODO: What does it mean for either sec or nsec to be negative? + *timestamp = (ts.tv_sec * 1000000000 + ts.tv_nsec) as u64; + } + } + return 0; + } + + /// Returns the ELF machine architecture. + #[allow(dead_code)] + fn get_e_machine() -> u32 { + match target_lexicon::HOST.architecture { + Architecture::X86_64 => elf::header::EM_X86_64 as u32, + Architecture::I686 => elf::header::EM_386 as u32, + Architecture::Arm => elf::header::EM_ARM as u32, + Architecture::Armv4t => elf::header::EM_ARM as u32, + Architecture::Armv5te => elf::header::EM_ARM as u32, + Architecture::Armv7 => elf::header::EM_ARM as u32, + Architecture::Armv7s => elf::header::EM_ARM as u32, + Architecture::Aarch64 => elf::header::EM_AARCH64 as u32, + _ => unimplemented!("unrecognized architecture"), + } + } + + #[allow(dead_code)] + fn write_file_header(file: &mut File) -> Result<(), JitDumpError> { + let mut header: FileHeader = Default::default(); + let mut timestamp: u64 = 0; + JitDumpAgent::get_time_stamp(&mut timestamp); + header.timestamp = timestamp; + + let e_machine = JitDumpAgent::get_e_machine(); + if e_machine != elf::header::EM_NONE as u32 { + header.e_machine = e_machine; + } + + if cfg!(target_endian = "little") { + header.magic = 0x4A695444 + } else { + header.magic = 0x4454694a + } + header.version = 1; + header.size = mem::size_of::() as u32; + header.pad1 = 0; + header.pid = process::id(); + header.flags = 0; + + file.iowrite_with(header, NATIVE)?; + Ok(()) + } + + fn write_code_load_record( + &mut self, + record_name: &str, + cl_record: CodeLoadRecord, + code_buffer: &[u8], + ) -> Result<(), Error> { + let mut jitdump_file = self.jitdump_file.as_ref().unwrap(); + jitdump_file.iowrite_with(cl_record, NATIVE)?; + jitdump_file.write_all(record_name.as_bytes())?; + jitdump_file.write_all(b"\0")?; + jitdump_file.write_all(code_buffer)?; + Ok(()) + } + + /// Write DebugInfoRecord to open jit dump file. + /// Must be written before the corresponding CodeLoadRecord. + fn write_debug_info_record(&mut self, dir_record: DebugInfoRecord) -> Result<(), Error> { + self.jitdump_file + .as_ref() + .unwrap() + .iowrite_with(dir_record, NATIVE)?; + Ok(()) + } + + /// Write DebugInfoRecord to open jit dump file. + /// Must be written before the corresponding CodeLoadRecord. + fn write_debug_info_entries(&mut self, die_entries: Vec) -> Result<(), Error> { + for entry in die_entries.iter() { + let mut jitdump_file = self.jitdump_file.as_ref().unwrap(); + jitdump_file.iowrite_with(entry.address, NATIVE)?; + jitdump_file.iowrite_with(entry.line, NATIVE)?; + jitdump_file.iowrite_with(entry.discriminator, NATIVE)?; + jitdump_file.write_all(entry.filename.as_bytes())?; + jitdump_file.write_all(b"\0")?; + } + Ok(()) + } + + /// Sent when a method is compiled and loaded into memory by the VM. + pub fn module_load( + &mut self, + module_name: &str, + addr: *const u8, + len: usize, + dbg_image: Option<&[u8]>, + ) -> () { + let pid = process::id(); + let tid = pid; // ThreadId does appear to track underlying thread. Using PID. + + if let Some(img) = &dbg_image { + let _ = self.dump_from_debug_image(img, module_name, addr, len, pid, tid); + } else { + let mut timestamp: u64 = 0; + JitDumpAgent::get_time_stamp(&mut timestamp); + self.dump_code_load_record(module_name, addr, len, timestamp, pid, tid); + } + } + + fn dump_code_load_record( + &mut self, + method_name: &str, + addr: *const u8, + len: usize, + timestamp: u64, + pid: u32, + tid: u32, + ) -> () { + let name_len = method_name.len() + 1; + let size_limit = mem::size_of::(); + + let rh = RecordHeader { + id: RecordId::JitCodeLoad as u32, + record_size: size_limit as u32 + name_len as u32 + len as u32, + timestamp: timestamp, + }; + + let clr = CodeLoadRecord { + header: rh, + pid: pid, + tid: tid, + virtual_address: addr as u64, + address: addr as u64, + size: len as u64, + index: self.code_index, + }; + self.code_index += 1; + + unsafe { + let code_buffer: &[u8] = std::slice::from_raw_parts(addr, len); + let _ = self.write_code_load_record(method_name, clr, code_buffer); + } + } + + /// Attempts to dump debuginfo data structures, adding method and line level + /// for the jitted function. + pub fn dump_from_debug_image( + &mut self, + dbg_image: &[u8], + module_name: &str, + addr: *const u8, + len: usize, + pid: u32, + tid: u32, + ) -> Result<(), Error> { + let file = object::File::parse(&dbg_image).unwrap(); + let endian = if file.is_little_endian() { + gimli::RunTimeEndian::Little + } else { + gimli::RunTimeEndian::Big + }; + + let load_section = |id: gimli::SectionId| -> Result, Error> { + Ok(file + .section_data_by_name(id.name()) + .unwrap_or(borrow::Cow::Borrowed(&[][..]))) + }; + + let load_section_sup = |_| Ok(borrow::Cow::Borrowed(&[][..])); + let dwarf_cow = gimli::Dwarf::load(&load_section, &load_section_sup)?; + let borrow_section: &dyn for<'a> Fn( + &'a borrow::Cow<[u8]>, + ) + -> gimli::EndianSlice<'a, gimli::RunTimeEndian> = + &|section| gimli::EndianSlice::new(&*section, endian); + + let dwarf = dwarf_cow.borrow(&borrow_section); + + let mut iter = dwarf.units(); + while let Some(header) = iter.next()? { + let unit = match dwarf.unit(header) { + Ok(unit) => unit, + Err(_err) => { + return Ok(()); + } + }; + self.dump_entries(unit, &dwarf, module_name, addr, len, pid, tid)?; + // TODO: Temp exit to avoid duplicate addresses being covered by only + // processing the top unit + break; + } + if !self.dump_funcs { + let mut timestamp: u64 = 0; + JitDumpAgent::get_time_stamp(&mut timestamp); + self.dump_code_load_record(module_name, addr, len, timestamp, pid, tid); + } + Ok(()) + } + + fn dump_entries( + &mut self, + unit: gimli::Unit, + dwarf: &gimli::Dwarf, + module_name: &str, + addr: *const u8, + len: usize, + pid: u32, + tid: u32, + ) -> Result<(), Error> { + let mut depth = 0; + let mut entries = unit.entries(); + while let Some((delta_depth, entry)) = entries.next_dfs()? { + if self.dump_funcs { + let record_header = RecordHeader { + id: RecordId::JitCodeLoad as u32, + record_size: 0, + timestamp: 0, + }; + + let mut clr = CodeLoadRecord { + header: record_header, + pid: pid, + tid: tid, + virtual_address: 0, + address: 0, + size: 0, + index: 0, + }; + let mut clr_name: String = String::from(module_name); + let mut get_debug_entry = false; + depth += delta_depth; + assert!(depth >= 0); + + if entry.tag() == gimli::constants::DW_TAG_subprogram { + get_debug_entry = true; + + let mut attrs = entry.attrs(); + while let Some(attr) = attrs.next()? { + if let Some(n) = attr.name().static_string() { + if n == "DW_AT_low_pc" { + clr.address = match attr.value() { + gimli::AttributeValue::Addr(address) => address, + _ => 0, + }; + clr.virtual_address = clr.address; + } else if n == "DW_AT_high_pc" { + clr.size = match attr.value() { + gimli::AttributeValue::Udata(data) => data, + _ => 0, + }; + } else if n == "DW_AT_name" { + clr_name = match attr.value() { + gimli::AttributeValue::DebugStrRef(offset) => { + if let Ok(s) = dwarf.debug_str.get_str(offset) { + clr_name.push_str("::"); + clr_name.push_str(&s.to_string_lossy()?); + clr_name + } else { + clr_name.push_str("::"); + clr_name.push_str("?"); + clr_name + } + } + _ => { + clr_name.push_str("??"); + clr_name + } + }; + } + } + } + } + if get_debug_entry { + // TODO: Temp check to make sure well only formed data is processed. + if clr.address == 0 { + continue; + } + // TODO: Temp check to make sure well only formed data is processed. + if clr_name == "?" { + continue; + } + if clr.address == 0 || clr.size == 0 { + clr.address = addr as u64; + clr.virtual_address = addr as u64; + clr.size = len as u64; + } + clr.header.record_size = mem::size_of::() as u32 + + (clr_name.len() + 1) as u32 + + clr.size as u32; + clr.index = self.code_index; + self.code_index += 1; + self.dump_debug_info(&unit, &dwarf, clr.address, clr.size, None)?; + + let mut timestamp: u64 = 0; + JitDumpAgent::get_time_stamp(&mut timestamp); + clr.header.timestamp = timestamp; + + unsafe { + let code_buffer: &[u8] = + std::slice::from_raw_parts(clr.address as *const u8, clr.size as usize); + let _ = self.write_code_load_record(&clr_name, clr, code_buffer); + } + } + } else { + let mut func_name: String = String::from("?"); + let mut func_addr = 0; + let mut func_size = 0; + + let mut get_debug_entry = false; + depth += delta_depth; + assert!(depth >= 0); + if entry.tag() == gimli::constants::DW_TAG_subprogram { + get_debug_entry = true; + + let mut attrs = entry.attrs(); + while let Some(attr) = attrs.next()? { + if let Some(n) = attr.name().static_string() { + if n == "DW_AT_low_pc" { + func_addr = match attr.value() { + gimli::AttributeValue::Addr(address) => address, + _ => 0, + }; + } else if n == "DW_AT_high_pc" { + func_size = match attr.value() { + gimli::AttributeValue::Udata(data) => data, + _ => 0, + }; + } else if n == "DW_AT_name" { + func_name = match attr.value() { + gimli::AttributeValue::DebugStrRef(offset) => { + if let Ok(s) = dwarf.debug_str.get_str(offset) { + func_name.clear(); + func_name.push_str(&s.to_string_lossy()?); + func_name + } else { + func_name.push_str("?"); + func_name + } + } + _ => { + func_name.push_str("??"); + func_name + } + }; + } + } + } + } + if get_debug_entry { + // TODO: Temp check to make sure well only formed data is processed. + if func_addr == 0 { + continue; + } + // TODO: Temp check to make sure well only formed data is processed. + if func_name == "?" { + continue; + } + self.dump_debug_info( + &unit, + &dwarf, + func_addr, + func_size, + Some(func_name.as_str()), + )?; + } + } + } + Ok(()) + } + + fn dump_debug_info( + &mut self, + unit: &gimli::Unit, + dwarf: &gimli::Dwarf, + address: u64, + size: u64, + file_suffix: Option<&str>, + ) -> Result<(), Error> { + let mut timestamp: u64 = 0; + JitDumpAgent::get_time_stamp(&mut timestamp); + if let Some(program) = unit.line_program.clone() { + let mut debug_info_record = DebugInfoRecord { + header: RecordHeader { + id: RecordId::JitCodeDebugInfo as u32, + record_size: 0, + timestamp: timestamp, + }, + address: address, + count: 0, + }; + + let mut debug_entries = Vec::new(); + let mut debug_entries_total_filenames_len = 0; + let mut rows = program.rows(); + while let Some((header, row)) = rows.next_row()? { + let row_file_index = row.file_index() - 1; + let myfile = dwarf + .attr_string( + &unit, + header.file_names()[row_file_index as usize].path_name(), + ) + .unwrap(); + let filename = myfile.to_string_lossy()?; + let line = row.line().unwrap_or(0); + let column = match row.column() { + gimli::ColumnType::Column(column) => column, + gimli::ColumnType::LeftEdge => 0, + }; + + if (row.address() < address) || (row.address() > (address + size)) { + continue; + } + let mut debug_entry = DebugEntry { + address: row.address(), + line: line as u32, + discriminator: column as u32, + filename: filename.to_string(), + }; + + if let Some(suffix) = file_suffix { + debug_entry.filename.push_str("::"); + debug_entry.filename.push_str(suffix); + } + + debug_entries_total_filenames_len += debug_entry.filename.len() + 1; + debug_entries.push(debug_entry); + } + + debug_info_record.count = debug_entries.len() as u64; + + let debug_entries_size = (debug_info_record.count + * (mem::size_of::() as u64 - mem::size_of::() as u64)) + + debug_entries_total_filenames_len as u64; + debug_info_record.header.record_size = + mem::size_of::() as u32 + debug_entries_size as u32; + + let _ = self.write_debug_info_record(debug_info_record); + let _ = self.write_debug_info_entries(debug_entries); + } + Ok(()) + } +} + +use crate::ProfilingAgent; +impl ProfilingAgent for JitDumpAgent { + fn init(&mut self) -> Result<(), Box> { + JitDumpAgent::init(self) + } + + fn module_load( + &mut self, + module_name: &str, + addr: *const u8, + len: usize, + dbg_image: Option<&[u8]>, + ) -> () { + JitDumpAgent::module_load(self, module_name, addr, len, dbg_image); + } + + fn box_clone(&self) -> Box { + Box::new((*self).clone()) + } +} + +impl Clone for JitDumpAgent { + fn clone(&self) -> Self { + Self { + jitdump_file: match self.jitdump_file.as_ref() { + Some(file) => Some(file.try_clone().unwrap()), + None => None, + }, + code_index: self.code_index, + dump_funcs: self.dump_funcs, + } + } +} + +#[derive(Debug)] +struct JitDumpError; + +impl std::fmt::Display for JitDumpError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "A profiler agent is not supported by this build") + } +} + +// This is important for other errors to wrap this one. +impl std::error::Error for JitDumpError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + // Generic error, underlying cause isn't tracked. + None + } +} + +impl From for JitDumpError { + fn from(_err: std::io::Error) -> Self { + //Error::IOError + JitDumpError + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Error { + GimliError(gimli::Error), + IOError, + NulError, +} + +impl From for Error { + fn from(err: gimli::Error) -> Self { + Error::GimliError(err) + } +} + +impl From for Error { + fn from(_err: std::io::Error) -> Self { + Error::IOError + } +} + +impl From for Error { + fn from(_err: std::ffi::NulError) -> Self { + Error::NulError + } +} + +trait Reader: gimli::Reader + Send + Sync {} + +impl<'input, Endian> Reader for gimli::EndianSlice<'input, Endian> where + Endian: gimli::Endianity + Send + Sync +{ +} diff --git a/crates/profiling/src/lib.rs b/crates/profiling/src/lib.rs new file mode 100644 index 000000000000..a7c5181219d1 --- /dev/null +++ b/crates/profiling/src/lib.rs @@ -0,0 +1,84 @@ +use std::error::Error; +use std::fmt; + +#[cfg(feature = "profiling")] +mod jitdump; + +#[cfg(feature = "profiling")] +pub use crate::jitdump::JitDumpAgent; + +#[cfg(not(feature = "profiling"))] +pub type JitDumpAgent = NullProfilerAgent; + +/// Select which profiling technique to use +#[derive(Debug, Clone, Copy)] +pub enum ProfilingStrategy { + /// No profiler support + NullProfiler, + + /// Collect profile for jitdump file format + JitDumpProfiler, +} + +/// Common interface for profiling tools. +pub trait ProfilingAgent { + /// Initialize the profiler + fn init(&mut self) -> Result<(), Box>; + + /// Support for conditional profiling build. + fn module_load( + &mut self, + module_name: &str, + addr: *const u8, + len: usize, + dbg_image: Option<&[u8]>, + ) -> (); + + fn box_clone(&self) -> Box; +} + +impl Clone for Box { + fn clone(&self) -> Box { + self.box_clone() + } +} + +/// Default agent for unsupported profiling build. +#[derive(Debug, Default, Clone, Copy)] +pub struct NullProfilerAgent {} + +#[derive(Debug)] +struct NullProfilerAgentError; + +impl fmt::Display for NullProfilerAgentError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "A profiler agent is not supported by this build") + } +} + +// This is important for other errors to wrap this one. +impl Error for NullProfilerAgentError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + // Generic error, underlying cause isn't tracked. + None + } +} + +impl ProfilingAgent for NullProfilerAgent { + fn init(&mut self) -> Result<(), Box> { + Ok(()) + } + + fn module_load( + &mut self, + _module_name: &str, + _addr: *const u8, + _len: usize, + _dbg_image: Option<&[u8]>, + ) -> () { + } + + fn box_clone(&self) -> Box { + Box::new((*self).clone()) + } +} diff --git a/crates/runtime/Cargo.toml b/crates/runtime/Cargo.toml index 6f8e8c86086d..e6ac4792fb70 100644 --- a/crates/runtime/Cargo.toml +++ b/crates/runtime/Cargo.toml @@ -11,6 +11,7 @@ readme = "README.md" edition = "2018" [dependencies] +wasmtime-profiling = { path = "../profiling" } wasmtime-environ = { path = "../environ", version = "0.9.0" } region = "2.0.0" libc = { version = "0.2.60", default-features = false } diff --git a/src/lib.rs b/src/lib.rs index 60ea36230bb5..d4c8d63309ca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,6 +30,7 @@ use anyhow::{bail, Result}; use std::path::PathBuf; use structopt::StructOpt; use wasmtime::{Config, Strategy}; +use wasmtime_profiling::ProfilingStrategy; fn pick_compilation_strategy(cranelift: bool, lightbeam: bool) -> Result { Ok(match (lightbeam, cranelift) { @@ -40,6 +41,13 @@ fn pick_compilation_strategy(cranelift: bool, lightbeam: bool) -> Result Result { + Ok(match jitdump { + true => ProfilingStrategy::JitDumpProfiler, + false => ProfilingStrategy::NullProfiler, + }) +} + fn init_file_per_thread_logger(prefix: &'static str) { file_per_thread_logger::initialize(prefix); @@ -117,6 +125,10 @@ struct CommonOptions { #[structopt(long, conflicts_with = "cranelift")] lightbeam: bool, + /// Generate jitdump file (supported on --features=profiling build) + #[structopt(long)] + jitdump: bool, + /// Run optimization passes on translated functions #[structopt(short = "O", long)] optimize: bool, @@ -133,7 +145,8 @@ impl CommonOptions { .wasm_reference_types(self.enable_reference_types || self.enable_all) .wasm_multi_value(self.enable_multi_value || self.enable_all) .wasm_threads(self.enable_threads || self.enable_all) - .strategy(pick_compilation_strategy(self.cranelift, self.lightbeam)?)?; + .strategy(pick_compilation_strategy(self.cranelift, self.lightbeam)?)? + .profiler(pick_profiling_strategy(self.jitdump)?)?; if self.optimize { config.cranelift_opt_level(wasmtime::OptLevel::Speed); } diff --git a/tests/instantiate.rs b/tests/instantiate.rs index 7b21cdf78465..b9bd6e1064eb 100644 --- a/tests/instantiate.rs +++ b/tests/instantiate.rs @@ -24,7 +24,7 @@ fn test_environ_translate() { let cache_config = CacheConfig::new_cache_disabled(); let mut compiler = Compiler::new(isa, CompilationStrategy::Auto, cache_config); unsafe { - let instance = instantiate(&mut compiler, &data, &mut resolver, false); + let instance = instantiate(&mut compiler, &data, &mut resolver, false, None); assert!(instance.is_ok()); } }