diff --git a/.gitignore b/.gitignore index c9ec3bbe..3f3436b8 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,19 @@ short-proc-loop.svg src/perf.data src/perf.data.old # ----------------# + + +# Auto-generated by autoignore: +# --------------- # +flamegraph.svg +new-efcl-lib.svg +normal-colored-lib.svg +# ----------------# + + +# Auto-generated by autoignore: +# --------------- # +autoclockspeed-0.1.11-x86_64.tar.gz +autoclockspeed-bin-0.1.11-1-x86_64.pkg.tar.zst +scripts/output.log +# ----------------# diff --git a/Cargo.lock b/Cargo.lock index 2ba838e1..48117a63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,60 +3,59 @@ version = 3 [[package]] -name = "aho-corasick" -version = "0.7.19" +name = "addr2line" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ - "memchr", + "gimli", ] [[package]] -name = "android_system_properties" -version = "0.1.5" +name = "adler" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] -name = "async-mutex" -version = "1.4.0" +name = "aho-corasick" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ - "event-listener", + "memchr", ] [[package]] -name = "async-rwlock" -version = "1.3.0" +name = "anes" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261803dcc39ba9e72760ba6e16d0199b1eef9fc44e81bffabbebb9f5aea3906c" -dependencies = [ - "async-mutex", - "event-listener", -] +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "async-trait" -version = "0.1.58" +version = "0.1.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c" +checksum = "461abc97219de0eaaf81fe3ef974a540158f3d079c2ab200f891f1a2ef201e85" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.53", ] +[[package]] +name = "async_once" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ce4f10ea3abcd6617873bae9f91d1c5332b4a778bd9ce34d0cd517474c1de82" + [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] @@ -69,11 +68,11 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "autoclockspeed" -version = "0.1.10" +version = "0.1.12" dependencies = [ "cached", - "chrono", - "colored", + "criterion", + "efcl", "env_logger", "globset", "log", @@ -81,71 +80,105 @@ dependencies = [ "rand", "rasciigraph", "serde", + "serde_json", "structopt", "termion", + "time", "toml", ] +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "bstr" -version = "0.2.17" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" +checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" dependencies = [ "memchr", + "serde", ] [[package]] name = "bumpalo" -version = "3.11.1" +version = "3.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" [[package]] name = "cached" -version = "0.30.0" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af4dfac631a8e77b2f327f7852bb6172771f5279c4512efe79fad6067b37be3d" +checksum = "5e5877db5d1af7fae60d06b5db9430b68056a69b3582a0be8e3691e87654aeb6" dependencies = [ - "async-mutex", - "async-rwlock", "async-trait", + "async_once", "cached_proc_macro", "cached_proc_macro_types", "futures", - "hashbrown", + "hashbrown 0.13.2", + "instant", + "lazy_static", "once_cell", + "thiserror", + "tokio", ] [[package]] name = "cached_proc_macro" -version = "0.9.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "725f434d6da2814b989bd905c62ca28a9383feff7440210dc279665fbbbc9511" +checksum = "e10ca87c81aaa3a949dbbe2b5e6c2c45dbc94ba4897e45ea31ff9ec5087be3dc" dependencies = [ "cached_proc_macro_types", "darling", + "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "cached_proc_macro_types" -version = "0.1.0" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade8366b8bd5ba243f0a58f036cc0ca8a2f069cff1a2351ef1cac6b083e16fc0" + +[[package]] +name = "cast" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a4f925191b4367301851c6d99b09890311d74b0d43f274c0b34c86d308a3663" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.75" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41ca34107f97baef6cfb231b32f36115781856b8f8208e8c580e0bcaea374842" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" [[package]] name = "cfg-if" @@ -154,18 +187,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "chrono" -version = "0.4.22" +name = "ciborium" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" dependencies = [ - "iana-time-zone", - "js-sys", - "num-integer", - "num-traits", - "time", - "wasm-bindgen", - "winapi", + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", ] [[package]] @@ -174,87 +219,104 @@ version = "2.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ - "bitflags", - "textwrap", + "bitflags 1.3.2", + "textwrap 0.11.0", "unicode-width", ] [[package]] -name = "codespan-reporting" -version = "0.11.1" +name = "clap" +version = "3.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ - "termcolor", - "unicode-width", + "bitflags 1.3.2", + "clap_lex", + "indexmap 1.9.3", + "textwrap 0.16.1", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", ] [[package]] -name = "colored" -version = "2.0.0" +name = "criterion" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" dependencies = [ + "anes", "atty", + "cast", + "ciborium", + "clap 3.2.25", + "criterion-plot", + "itertools", "lazy_static", - "winapi", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", ] [[package]] -name = "core-foundation-sys" -version = "0.8.3" +name = "criterion-plot" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools", +] [[package]] -name = "cxx" -version = "1.0.81" +name = "crossbeam-deque" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97abf9f0eca9e52b7f81b945524e76710e6cb2366aead23b7d4fbf72e281f888" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", + "crossbeam-epoch", + "crossbeam-utils", ] [[package]] -name = "cxx-build" -version = "1.0.81" +name = "crossbeam-epoch" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cc32cc5fea1d894b77d269ddb9f192110069a8a9c1f1d441195fba90553dea3" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn", + "crossbeam-utils", ] [[package]] -name = "cxxbridge-flags" -version = "1.0.81" +name = "crossbeam-utils" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca220e4794c934dc6b1207c3b42856ad4c302f2df1712e9f8d2eec5afaacf1f" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] -name = "cxxbridge-macro" -version = "1.0.81" +name = "crunchy" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b846f081361125bfc8dc9d3940c84e1fd83ba54bbca7b17cd29483c828be0704" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "darling" -version = "0.13.4" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" dependencies = [ "darling_core", "darling_macro", @@ -262,47 +324,68 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.13.4" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn", + "syn 1.0.109", ] [[package]] name = "darling_macro" -version = "0.13.4" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" dependencies = [ "darling_core", "quote", - "syn", + "syn 1.0.109", ] +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "efcl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cc5719498b622a4332139a599458627779053ff0220e59f6aaab0618e00a18e" + +[[package]] +name = "either" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" + [[package]] name = "env_logger" -version = "0.9.3" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" dependencies = [ - "atty", "humantime", + "is-terminal", "log", "regex", "termcolor", ] [[package]] -name = "event-listener" -version = "2.5.3" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "fnv" @@ -312,13 +395,12 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "futures" -version = "0.3.25" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", - "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -327,9 +409,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.25" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -337,97 +419,98 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" - -[[package]] -name = "futures-executor" -version = "0.3.25" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-io" -version = "0.3.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" - -[[package]] -name = "futures-macro" -version = "0.3.25" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-sink" -version = "0.3.25" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.25" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.25" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ - "futures-channel", "futures-core", - "futures-io", - "futures-macro", "futures-sink", "futures-task", - "memchr", "pin-project-lite", "pin-utils", - "slab", ] [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", ] +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + [[package]] name = "globset" -version = "0.4.9" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" +checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" dependencies = [ "aho-corasick", "bstr", - "fnv", "log", - "regex", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "half" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5eceaaeec696539ddaf7b333340f1af35a5aa87ae3e4f3ead0532f72affab2e" +dependencies = [ + "cfg-if", + "crunchy", ] [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" + +[[package]] +name = "hashbrown" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "heck" @@ -447,6 +530,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + [[package]] name = "humantime" version = "2.1.0" @@ -454,40 +543,71 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] -name = "iana-time-zone" -version = "0.1.53" +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "winapi", + "autocfg", + "hashbrown 0.12.3", ] [[package]] -name = "iana-time-zone-haiku" -version = "0.1.1" +name = "indexmap" +version = "2.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" dependencies = [ - "cxx", - "cxx-build", + "equivalent", + "hashbrown 0.14.3", ] [[package]] -name = "ident_case" -version = "1.0.1" +name = "instant" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "is-terminal" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "windows-sys", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -500,73 +620,86 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.137" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] -name = "link-cplusplus" -version = "1.0.7" +name = "libredox" +version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" +checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" dependencies = [ - "cc", + "bitflags 2.5.0", + "libc", + "redox_syscall", ] [[package]] name = "log" -version = "0.4.17" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "memoffset" -version = "0.6.5" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" dependencies = [ "autocfg", ] +[[package]] +name = "miniz_oxide" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +dependencies = [ + "adler", +] + [[package]] name = "nix" -version = "0.20.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5e06129fb611568ef4e868c14b326274959aa70ff7776e9d55323531c374945" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ - "bitflags", - "cc", + "bitflags 1.3.2", "cfg-if", "libc", "memoffset", + "pin-utils", ] [[package]] -name = "num-integer" -version = "0.1.45" +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-traits" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", - "num-traits", ] [[package]] -name = "num-traits" -version = "0.2.15" +name = "num_threads" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" dependencies = [ - "autocfg", + "libc", ] [[package]] @@ -575,17 +708,38 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + [[package]] name = "once_cell" -version = "1.16.0" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "os_str_bytes" +version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -593,6 +747,40 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "plotters" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" + +[[package]] +name = "plotters-svg" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -608,7 +796,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "version_check", ] @@ -625,18 +813,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.47" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.21" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -673,33 +861,62 @@ dependencies = [ [[package]] name = "rasciigraph" -version = "0.1.1" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a3273d76a0cdbb09ecead2f6007d6d169211f3c9c6dd30cd8a2e8175adcb74" + +[[package]] +name = "rayon" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f9690d7e935db7c1475554993ec7162d11a83fae5261be2d9191294a31ac82" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] [[package]] name = "redox_syscall" -version = "0.2.16" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] name = "redox_termios" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8440d8acb4fd3d277125b4bd01a6f38aee8d814b3b5fc09b3f2b825d37d3fe8f" +checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb" + +[[package]] +name = "regex" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ - "redox_syscall", + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", ] [[package]] -name = "regex" -version = "1.7.0" +name = "regex-automata" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", @@ -708,43 +925,69 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] -name = "scratch" -version = "1.0.2" +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "ryu" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" + +[[package]] +name = "same-file" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] [[package]] name = "serde" -version = "1.0.147" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.147" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.53", ] [[package]] -name = "slab" -version = "0.4.7" +name = "serde_json" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ - "autocfg", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ + "serde", ] [[package]] @@ -759,7 +1002,7 @@ version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" dependencies = [ - "clap", + "clap 2.34.0", "lazy_static", "structopt-derive", ] @@ -774,14 +1017,25 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.109", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] name = "syn" -version = "1.0.103" +version = "2.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" dependencies = [ "proc-macro2", "quote", @@ -790,22 +1044,22 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] [[package]] name = "termion" -version = "1.5.6" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "077185e2eac69c3f8379a4298e1e07cd36beb962290d4a51199acf0fdc10607e" +checksum = "c4648c7def6f2043b2568617b9f9b75eae88ca185dbc1f1fda30e95a85d49d7d" dependencies = [ "libc", + "libredox", "numtoa", - "redox_syscall", "redox_termios", ] @@ -818,43 +1072,148 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "textwrap" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" + +[[package]] +name = "thiserror" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", +] + [[package]] name = "time" -version = "0.1.44" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" dependencies = [ + "deranged", + "itoa", "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" +dependencies = [ + "num-conv", + "time-core", +] + +[[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.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +dependencies = [ + "backtrace", + "pin-project-lite", + "tokio-macros", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.53", ] [[package]] name = "toml" -version = "0.5.9" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ + "indexmap 2.2.5", "serde", + "serde_spanned", + "toml_datetime", + "winnow", ] [[package]] name = "unicode-ident" -version = "1.0.5" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-segmentation" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "version_check" @@ -863,10 +1222,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" +name = "walkdir" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] [[package]] name = "wasi" @@ -876,9 +1239,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -886,24 +1249,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.53", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -911,22 +1274,32 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.53", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "web-sys" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] [[package]] name = "winapi" @@ -946,9 +1319,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] @@ -958,3 +1331,78 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] diff --git a/Cargo.toml b/Cargo.toml index 007d4c1c..664d45c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "autoclockspeed" -version = "0.1.10" +version = "0.1.12" edition = "2021" license = "MIT OR MPL-2.0" description = "A utility to check stats about your CPU, and auto regulate clock speeds to help with either performance or battery life." @@ -13,19 +13,32 @@ authors = ["jakeroggenbuck +# Maintainer: cameron # Maintainer: shuzhengz # # This PKGBUILD was generated by `cargo aur`: https://crates.io/crates/cargo-aur pkgname=autoclockspeed-bin -pkgver=0.1.10 +pkgver=0.1.11 pkgrel=1 pkgdesc="A utility to check stats about your CPU, and auto regulate clock speeds to help with either performance or battery life." url="https://github.com/JakeRoggenbuck/auto-clock-speed" -license=("MIT") +license=("MIT OR MPL-2.0") arch=("x86_64") provides=("autoclockspeed") conflicts=("autoclockspeed") source=("https://github.com/JakeRoggenbuck/auto-clock-speed/releases/download/v$pkgver/autoclockspeed-$pkgver-x86_64.tar.gz") -sha256sums=("a85616cd8861e76c11791584879defa70b03c88f86a33ce86c348c7251227a1c") +sha256sums=("08d3f45df0e61466c93d28a3190f62f7ba60461b92304bf2dc5b8a94226ce06d") package() { install -Dm755 acs -t "$pkgdir/usr/bin" - install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE" + install -Dm644 LICENSE-MIT "$pkgdir/usr/share/licenses/$pkgname/LICENSE-MIT" } diff --git a/README.md b/README.md index dfd70943..95dacf6e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ ![Auto Clock Speed Banner Logo](https://user-images.githubusercontent.com/35516367/169680198-99d02746-22f7-433d-a9a1-d8858edef512.png) -![Rust](https://img.shields.io/github/workflow/status/jakeroggenbuck/auto-clock-speed/Rust?style=for-the-badge) -![Crates Version](https://img.shields.io/crates/v/autoclockspeed?style=for-the-badge) -![Downloads](https://img.shields.io/crates/d/autoclockspeed?style=for-the-badge) +[![Rust](https://img.shields.io/github/actions/workflow/status/jakeroggenbuck/auto-clock-speed/rust.yml?branch=main&style=for-the-badge)](https://github.com/JakeRoggenbuck/auto-clock-speed/actions) +[![Crates Version](https://img.shields.io/crates/v/autoclockspeed?style=for-the-badge)](https://crates.io/crates/autoclockspeed) +[![Downloads](https://img.shields.io/crates/d/autoclockspeed?style=for-the-badge)](https://crates.io/crates/autoclockspeed) +![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/jakeroggenbuck/auto-clock-speed?style=for-the-badge) #### [ACS Upstream](https://github.com/jakeroggenbuck/auto-clock-speed) - [autoclockspeed.org](https://autoclockspeed.org) - [Our crates.io](https://crates.io/crates/autoclockspeed) - [ACS Github Org](https://github.com/autoclockspeed) @@ -43,6 +44,9 @@ If you have cargo on your machine, skip to step 3 # This is needed to have the root version of acs match the local installed version sudo cp ~/.cargo/bin/acs /usr/bin/acs ``` + + Note: If you recieve error `linker 'cc' not found`, then you need to install a C compiler (gcc, cmake, etc.) first. +
Note: The latest release of acs can also be installed locally with the following @@ -58,7 +62,7 @@ Auto clock speed has been tested to work on the following devices. If you have a | Working | All parts of ACS are fully functional, the computer has enough data to make decisions on governor changes and can be run in edit mode | | Mostly Working | ACS is unable to understand some data from the computer however certain data (like battery life, battery condition, temperature etc) which is non essential in making governor decisions, is missing | | Partially Working | ACS is able to mostly work, although with one or more significant caveat (i.e. jailbreak on Apple devices or root access on Android) | -| Barely Working | ACS is unable to be ran in edit mode due to missing data from the system, monit mode may still work however functionality is limited. If you have a system that falls under this category please open an issue | +| Barely Working | ACS is unable to be run in edit mode due to missing data from the system, monit mode may still work however functionality is limited. If you have a system that falls under this category please open an issue | | Borked | ACS cannot find any useful data. Please open an issue | | Device Name | Functionality | Notes | @@ -67,12 +71,15 @@ Auto clock speed has been tested to work on the following devices. If you have a | Dell Latitude 7480 | Working | | | Steam Deck | Working | Edit mode not neccessary (use built in governor switcher) | | Thinkpad T400 | Working | | +| Thinkpad T460 | Working | | | Thinkpad X230 | Working | | +| Thinkpad X301 | Working | | | Thinkpad W540 | Working | | | ThinkPad X1 Extreme Gen 1 | Working | | | Thinkpad P1 Gen 4 (Intel Core) | Working | | | Thinkpad P14 Gen 2 (AMD) | Mostly Working | See [#443](https://github.com/JakeRoggenbuck/auto-clock-speed/issues/443) | | OnePlus 9 Pro (Snapdragon 888 SoC) | Partially Working | Needs root access; compile from source through termux | +| iPad Pro Gen 6 | Barely Working | Compiles with iSH, but cannot access any data | ## In Action diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..06689d6d --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,11 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +| ------- | ------------------ | +| 0.1.x | :white_check_mark: | + +## Reporting a Vulnerability + +Please send us an email at security@autoclockspeed.org diff --git a/benches/graph_benchmark.rs b/benches/graph_benchmark.rs new file mode 100644 index 00000000..41e40e81 --- /dev/null +++ b/benches/graph_benchmark.rs @@ -0,0 +1,41 @@ +use autoclockspeed::graph::{Graph, Grapher}; +use criterion::{black_box, criterion_group, criterion_main, Criterion}; + +fn update_all_benchmark(c: &mut Criterion) { + let mut graph = Graph::new(); + let vec = vec![0.0; 100]; + graph.vals = vec; + c.bench_function("update_all", |b| b.iter(|| graph.update_all())); +} + +fn update_one_benchmark(c: &mut Criterion) { + let graph = Graph::new(); + let mut vec = vec![0.0; 100]; + c.bench_function("update_one", |b| { + b.iter(|| black_box(graph.update_one(&mut vec))) + }); +} + +fn clear_before_benchmark(c: &mut Criterion) { + let graph = Graph::new(); + let mut vec = vec![0.0; 100]; + c.bench_function("clear_before", |b| { + b.iter(|| black_box(graph.clear_before(&mut vec))) + }); +} + +fn plot_benchmark(c: &mut Criterion) { + let graph = Graph::new(); + let nums = vec![0.0; 100]; + c.bench_function("plot", |b| b.iter(|| black_box(graph.plot(nums.clone())))); +} + +criterion_group!( + benches, + update_all_benchmark, + update_one_benchmark, + clear_before_benchmark, + plot_benchmark +); + +criterion_main!(benches); diff --git a/benches/system_benchmark.rs b/benches/system_benchmark.rs new file mode 100644 index 00000000..c5d256f5 --- /dev/null +++ b/benches/system_benchmark.rs @@ -0,0 +1,30 @@ +use autoclockspeed::{power, system}; +use criterion::{black_box, criterion_group, criterion_main, Criterion}; + +pub fn check_cpu_name_benchmark(c: &mut Criterion) { + c.bench_function("check_cpu_name", |b| b.iter(|| system::check_cpu_name())); +} + +pub fn check_available_governors_benchmark(c: &mut Criterion) { + c.bench_function("check_available_governors", |b| { + b.iter(|| system::check_available_governors()) + }); +} + +pub fn list_cpus_benchmark(c: &mut Criterion) { + c.bench_function("list_cpus", |b| b.iter(|| system::list_cpus())); +} + +pub fn set_best_path_benchmark(c: &mut Criterion) { + c.bench_function("set_best_path", |b| b.iter(|| power::set_best_path())); +} + +criterion_group!( + benches, + check_cpu_name_benchmark, + check_available_governors_benchmark, + list_cpus_benchmark, + set_best_path_benchmark +); + +criterion_main!(benches); diff --git a/build.rs b/build.rs index 60eca55e..c774aad7 100644 --- a/build.rs +++ b/build.rs @@ -1,11 +1,15 @@ +#![allow(clippy::uninlined_format_args)] + use std::process::Command; fn main() { + // Get commit hash of last commit let output = Command::new("git") - .args(&["rev-parse", "HEAD"]) + .args(["rev-parse", "HEAD"]) .output() .unwrap(); let git_hash = String::from_utf8(output.stdout).unwrap(); + // Set commit hash to env to read later with --commit option println!("cargo:rustc-env=GIT_HASH={}", git_hash); } diff --git a/scripts/battery-benchmark.py b/scripts/battery-benchmark.py new file mode 100644 index 00000000..3f173689 --- /dev/null +++ b/scripts/battery-benchmark.py @@ -0,0 +1,57 @@ +import subprocess +import time +import datetime + + +def log_internal(msg): + _, bat, _ = subprocess.check_output( + "acs get power --raw", + shell=True, + ).decode().split() + + time = datetime.datetime.now() + print(f"[LOG ({time}) bat={bat}]: {msg}") + + return f"{time},{bat},{msg}\n" + + +def log(msg): + out = log_internal(msg) + with open("output.log", "a") as file: + file.write(out) + + +def test(): + while 1: + log("Running...") + time.sleep(10) + + _, bat, _ = subprocess.check_output( + "acs get power --raw", + shell=True, + ).decode().split() + + if int(bat) <= 43: + log("Test ended!") + exit(1) + + +def start_test(): + log("Test Started!") + + test() + + +if __name__ == "__main__": + lid, bat, ac = subprocess.check_output( + "acs get power --raw", + shell=True, + ).decode().split() + + while 1: + if int(bat) == 45 and ac == "false": + start_test() + else: + print("Waiting to start test...") + + time.sleep(10) diff --git a/src/args.rs b/src/args.rs index 0df28693..5fa67b36 100644 --- a/src/args.rs +++ b/src/args.rs @@ -1,14 +1,17 @@ +#![forbid(unsafe_code)] use std::{thread, time}; use structopt::StructOpt; use super::config; -use super::config::{config_dir_exists, init_config}; +use super::config::init_config; use super::daemon; use super::daemon::daemon_init; use super::display::show_config; +use super::graph::{get_graph_type, GraphType}; use super::interactive::interactive; use super::interface::{DaemonControl, DaemonController, Get, Getter, Interface, Set, Setter}; -use super::settings::{get_graph_type, GraphType, Settings}; +use super::settings::Settings; +use super::setup::check_config_dir_exists; use super::warn_user; #[derive(StructOpt)] @@ -44,6 +47,9 @@ enum GetType { Usage { #[structopt(short, long)] raw: bool, + + #[structopt(short, long)] + delay: Option, }, /// The overall frequency of your cpu @@ -173,23 +179,27 @@ enum ACSCommand { #[structopt(short, long)] quiet: bool, - /// Milliseconds between update + /// Output the settings and quit + #[structopt(short, long)] + show_settings: bool, + + /// Milliseconds between update (when charging) #[structopt(short, long)] delay: Option, - /// Milliseconds between update + /// Milliseconds between update (when on battery) #[structopt(short = "b", long = "delay-battery")] delay_battery: Option, - /// No animations, for systemctl updating issue + /// Animations, for systemctl updating issue #[structopt(short, long)] - no_animation: bool, + animation: bool, - /// Graph - #[structopt(short = "g", long = "graph")] + /// Graph "freq", "usage", or "temp" + #[structopt(short = "g", long = "--graph")] graph_type: Option, - /// Commit hash + /// Show commit hash #[structopt(short, long)] commit: bool, @@ -197,12 +207,12 @@ enum ACSCommand { #[structopt(long = "csv")] csv_file: Option, - /// Log file size cutoff in MB + /// Log CSV file size cutoff in MB #[structopt(long = "log-size-cutoff", default_value = "20")] log_size_cutoff: i32, }, - /// Monitor each cpu, it's min, max, and current speed, along with the governor + /// Monitor each cpu, its min, max, and current speed, along with the governor #[structopt(name = "monitor", alias = "monit")] Monitor { /// Milliseconds between update @@ -213,19 +223,23 @@ enum ACSCommand { #[structopt(short = "b", long = "delay-battery")] delay_battery: Option, - /// No animations, for systemctl updating issue + /// Animations, for systemctl updating issue + #[structopt(short, long)] + animation: bool, + + /// Output the settings and quit #[structopt(short, long)] - no_animation: bool, + show_settings: bool, - /// Hook + /// Hook to other instance of ACS running as root to view live data #[structopt(short = "h", long = "--hook")] hook: bool, - /// Graph + /// Graph "freq", "usage", or "temp" #[structopt(short = "g", long = "--graph")] graph_type: Option, - /// Commit hash + /// Show commit hash #[structopt(short, long)] commit: bool, @@ -233,27 +247,14 @@ enum ACSCommand { #[structopt(long = "csv")] csv_file: Option, - /// Log file size cutoff in MB + /// Log CSV file size cutoff in MB #[structopt(long = "log-size-cutoff", default_value = "20")] log_size_cutoff: i32, }, } pub fn parse_args(config: config::Config) { - let set_settings = Settings { - verbose: true, - delay_battery: 0, - delay: 0, - edit: false, - hook: false, - no_animation: false, - graph: GraphType::Hidden, - commit: false, - testing: false, - csv_file: "".to_string(), - log_csv: false, - log_size_cutoff: 20, - }; + let set_settings = Settings::default(); let int = Interface { set: Set {}, @@ -272,7 +273,7 @@ pub fn parse_args(config: config::Config) { ACSCommand::Get { get } => match get { GetType::Freq { raw } => int.get.freq(raw), GetType::Power { raw } => int.get.power(raw), - GetType::Usage { raw } => int.get.usage(raw), + GetType::Usage { raw, delay } => int.get.usage(raw, delay), GetType::Thermal { raw } => int.get.thermal(raw), GetType::Turbo { raw } => int.get.turbo(raw), GetType::AvailableGovs { raw } => int.get.available_govs(raw), @@ -296,28 +297,22 @@ pub fn parse_args(config: config::Config) { quiet, delay, delay_battery, - no_animation, + animation, graph_type, commit, csv_file, log_size_cutoff, + show_settings, } => { - if !config_dir_exists() { - warn_user!("Config directory '/etc/acs' does not exist!"); - thread::sleep(time::Duration::from_millis(5000)); - } + check_config_dir_exists(); let mut parsed_graph_type = GraphType::Hidden; - - match graph_type { - Some(graph_name) => { - parsed_graph_type = get_graph_type(&graph_name); - if parsed_graph_type == GraphType::Unknown { - warn_user!("Graph type does not exist! Can be freq, usage, or temp Continuing in 5 seconds..."); - thread::sleep(time::Duration::from_millis(5000)); - } + if let Some(gt) = graph_type { + parsed_graph_type = get_graph_type(>); + if parsed_graph_type == GraphType::Unknown { + warn_user!("Graph type does not exist! Can be freq, usage, or temp Continuing in 5 seconds..."); + thread::sleep(time::Duration::from_millis(5000)); } - None => {} } let mut effective_delay_battery = delay_battery.unwrap_or(5000); @@ -331,7 +326,7 @@ pub fn parse_args(config: config::Config) { delay_battery: effective_delay_battery, delay: regular_delay, edit: true, - no_animation, + animation, hook: false, graph: parsed_graph_type, commit, @@ -339,42 +334,35 @@ pub fn parse_args(config: config::Config) { log_csv: csv_file.is_some(), csv_file: csv_file.unwrap_or_else(|| "/tmp/acs/".to_string()), log_size_cutoff, + show_settings, }; - match daemon_init(settings, config) { - Ok(d) => { - daemon::run(d).expect("Daemon did not run successfully."); - } - Err(_) => eprint!("Could not run daemon in edit mode"), - } + let d = daemon_init(settings, config); + daemon::run(d).expect("Daemon did not run successfully."); } // Monitor command ACSCommand::Monitor { delay, delay_battery, - no_animation, + animation, graph_type, hook, commit, csv_file, log_size_cutoff, + show_settings, } => { - if !config_dir_exists() { - warn_user!("Config directory '/etc/acs' does not exist!"); - } + check_config_dir_exists(); let mut parsed_graph_type = GraphType::Hidden; - match graph_type { - Some(graph_name) => { - parsed_graph_type = get_graph_type(&graph_name); - if parsed_graph_type == GraphType::Unknown { - warn_user!("Graph type does not exist! Can be freq, usage, or temp Continuing in 5 seconds..."); - thread::sleep(time::Duration::from_millis(5000)); - } + if let Some(gt) = graph_type { + parsed_graph_type = get_graph_type(>); + if parsed_graph_type == GraphType::Unknown { + warn_user!("Graph type does not exist! Can be freq, usage, or temp Continuing in 5 seconds..."); + thread::sleep(time::Duration::from_millis(5000)); } - None => {} } let mut effective_delay_battery = delay_battery.unwrap_or(5000); @@ -389,21 +377,18 @@ pub fn parse_args(config: config::Config) { delay_battery: effective_delay_battery, edit: false, hook, - no_animation, + animation, graph: parsed_graph_type, commit, testing: false, log_csv: csv_file.is_some(), csv_file: csv_file.unwrap_or_else(|| "/tmp/acs/".to_string()), log_size_cutoff, + show_settings, }; - match daemon_init(settings, config) { - Ok(d) => { - daemon::run(d).expect("Daemon did not run successfully."); - } - Err(_) => eprint!("Could not run daemon in monitor mode"), - } + let d = daemon_init(settings, config); + daemon::run(d).expect("Daemon did not run successfully."); } } } diff --git a/src/main.rs b/src/bin/main.rs similarity index 73% rename from src/main.rs rename to src/bin/main.rs index 29bd89e6..de7a75aa 100644 --- a/src/main.rs +++ b/src/bin/main.rs @@ -22,37 +22,18 @@ // https://crates.io/crates/autoclockspeed // https://github.com/autoclockspeed -use args::parse_args; -use config::get_config; -use error::Error; -use log::debug; +#![allow(clippy::uninlined_format_args)] +#![forbid(unsafe_code)] -pub mod args; -pub mod config; -pub mod cpu; -pub mod csv; -pub mod daemon; -pub mod display; -pub mod error; -pub mod graph; -pub mod interactive; -pub mod interface; -pub mod logger; -pub mod network; -pub mod power; -pub mod settings; -pub mod setup; -pub mod sysfs; -pub mod system; -pub mod terminal; -pub mod thermal; +use autoclockspeed::args::parse_args; +use autoclockspeed::config::get_config; fn main() { env_logger::init(); - setup::setup(); + autoclockspeed::setup::setup(); - let config: config::Config = get_config(); + let config: autoclockspeed::config::Config = get_config(); parse_args(config); } diff --git a/src/config.rs b/src/config.rs index 38e77ee4..5b653543 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,7 +1,9 @@ +#![forbid(unsafe_code)] use super::daemon::State; -use super::warn_user; +use super::{print_done, warn_user}; use crate::print_error; use serde::{Deserialize, Serialize}; +use std::default::Default; use std::fmt; use std::fs::File; use std::io::{ErrorKind, Read, Write}; @@ -24,17 +26,20 @@ pub fn config_dir_exists() -> bool { Path::new("/etc/acs/").exists() } -pub fn default_config() -> Config { - Config { - powersave_under: 20, - overheat_threshold: 80, - high_cpu_threshold: 50, - active_rules: vec![ - State::BatteryLow, - State::LidClosed, - State::Charging, - State::CpuUsageHigh, - ], +impl Default for Config { + fn default() -> Config { + Config { + powersave_under: 20, + overheat_threshold: 80, + high_cpu_threshold: 50, + high_cpu_time_needed: 15, + active_rules: vec![ + State::BatteryLow, + State::LidClosed, + State::Charging, + State::CpuUsageHigh, + ], + } } } @@ -73,7 +78,7 @@ pub fn init_config_dir() { /// Initialize the config file at /etc/acs/acs.toml pub fn init_config_file() { - let config_file = File::create(&config_path()); + let config_file = File::create(config_path()); let mut config = match config_file { Ok(file) => file, Err(error) => match error.kind() { @@ -88,23 +93,26 @@ pub fn init_config_file() { }, }; - let default_config = default_config(); + let default_config = Config::default(); let serialized = toml::to_string(&default_config).expect("Could not serialize default config"); config.write_all(serialized.as_bytes()).unwrap_or_else(|_| { panic!( "Could not write serialized output to file {}", - &config_path() + config_path() ) }); - println!("Created config file at '/etc/acs/acs.toml'"); + print_done!("Created config file at '/etc/acs/acs.toml'"); } #[derive(Debug, Serialize)] pub struct Config { + /// ACS in edit mode will activate powersave if the battery percentage is under this value pub powersave_under: i8, + /// ACS in edit mode will activate powersave if the temperature reaches this value pub overheat_threshold: i8, pub high_cpu_threshold: i8, + pub high_cpu_time_needed: u64, pub active_rules: Vec, } @@ -113,6 +121,7 @@ pub struct SafeConfig { pub powersave_under: Option, pub overheat_threshold: Option, pub high_cpu_threshold: Option, + pub high_cpu_time_needed: Option, pub active_rules: Option>, } @@ -135,7 +144,7 @@ impl SafeFillConfig for SafeConfig { // This approach coincidentally happens to be more efficient when more than half // of the values are not defined. This means that if no config is present, then no work // will be done to modify base. - let mut base = default_config(); + let mut base = Config::default(); if let Some(pu) = self.powersave_under { base.powersave_under = pu; @@ -149,6 +158,10 @@ impl SafeFillConfig for SafeConfig { base.high_cpu_threshold = hc; } + if let Some(ht) = self.high_cpu_time_needed { + base.high_cpu_time_needed = ht; + } + if let Some(ars) = &self.active_rules { base.active_rules.clear(); for rule in ars { @@ -189,6 +202,7 @@ fn parse_as_toml(config: String) -> Config { powersave_under: None, overheat_threshold: None, high_cpu_threshold: None, + high_cpu_time_needed: None, active_rules: None, }); @@ -197,7 +211,7 @@ fn parse_as_toml(config: String) -> Config { pub fn open_config() -> Result { let conf_path = config_path(); - let mut config_file: File = File::open(&conf_path)?; + let mut config_file: File = File::open(conf_path)?; let config_string = read_as_string(&mut config_file); let config_toml = parse_as_toml(config_string); @@ -211,7 +225,7 @@ pub fn get_config() -> Config { Err(_) => { warn_user!("Using default config. Create file '/etc/acs/acs.toml' for custom config or run 'acs initconfig' to setup default config automatically."); // Use default config as config - default_config() + Config::default() } } } @@ -222,7 +236,7 @@ mod tests { #[test] fn default_config_unit_test() { - let config: Config = default_config(); + let config: Config = Config::default(); assert!(config.powersave_under > 0 && config.powersave_under < 100); } diff --git a/src/cpu.rs b/src/cpu.rs index 7a828df1..6e3d4129 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -1,12 +1,16 @@ -use colored::Colorize; +#![forbid(unsafe_code)] +use efcl::{bold, color, Color}; use rand::Rng; use std::fmt; use std::fs::{self, File}; use std::io::Write; use std::path::Path; -use super::system::{calculate_cpu_percent, read_int, read_str, ProcStat}; -use super::Error; +use crate::proc::ProcStat; + +use crate::error::Error; +use crate::gov::Gov; +use crate::system::{calculate_cpu_percent, read_int, read_str}; /// Any trait relating to a CPU Core pub trait Speed { @@ -22,7 +26,7 @@ pub trait Speed { fn get_cur(&mut self); fn get_temp(&mut self) -> Result<(), Error>; fn get_gov(&mut self) -> Result<(), Error>; - fn set_gov(&mut self, gov: String) -> Result<(), Error>; + fn set_gov(&mut self, gov: Gov) -> Result<(), Error>; fn random() -> CPU; } @@ -187,8 +191,8 @@ impl Speed for CPU { } /// Set the governor - fn set_gov(&mut self, gov: String) -> Result<(), Error> { - self.gov = gov; + fn set_gov(&mut self, gov: Gov) -> Result<(), Error> { + self.gov = format!("{gov}"); self.write_value(WritableValue::Gov)?; Ok(()) } @@ -216,41 +220,49 @@ impl Speed for CPU { impl fmt::Display for CPU { /// Display any information about the cpu in a human readable and simple format fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let temp: colored::ColoredString; let reduced_cpu_cur_temp = self.cur_temp / 1000; - if reduced_cpu_cur_temp > 60 { - temp = format!("{}C", reduced_cpu_cur_temp).red(); + // Pick color based on temp + let temp_color = if reduced_cpu_cur_temp > 60 { + Color::RED } else if reduced_cpu_cur_temp > 40 { - temp = format!("{}C", reduced_cpu_cur_temp).yellow(); + Color::YELLOW } else if reduced_cpu_cur_temp == 1 || reduced_cpu_cur_temp == 0 { - temp = format!("{}C*", reduced_cpu_cur_temp).white(); + Color::LIGHTGRAY } else { - temp = format!("{}C", reduced_cpu_cur_temp).green(); - } + Color::GREEN + }; + + let temp: String = color!(temp_color, format!("{}C", reduced_cpu_cur_temp).as_str()); - let usage: colored::ColoredString; let scaled_cpus_cur_usage = self.cur_usage * 100.0; - if self.cur_usage > 0.9 { - usage = format!("{:.2}%", scaled_cpus_cur_usage).red(); + // Pick color based on usage + let usage_color = if self.cur_usage > 0.9 { + Color::RED } else if self.cur_usage > 0.5 { - usage = format!("{:.2}%", scaled_cpus_cur_usage).yellow(); - } else if self.cur_usage > 0.2 { - usage = format!("{:.2}%", scaled_cpus_cur_usage).white(); + Color::YELLOW } else if self.cur_usage > 0.0000 { - usage = format!("{:.2}%", scaled_cpus_cur_usage).green(); + Color::GREEN } else { - usage = format!("{:.2}%", scaled_cpus_cur_usage).purple(); - } + Color::LIGHTGRAY + }; + + let usage: String = color!( + usage_color, + format!("{:.2}%", scaled_cpus_cur_usage).as_str() + ); writeln!( f, "{}:\t{}MHz\t{}MHz\t{}\t{}\t{}\t{}", - self.name.bold(), + bold!(&self.name), self.max_freq / 1000, self.min_freq / 1000, - format!("{}MHz", self.cur_freq / 1000).green(), + color!( + Color::GREEN, + format!("{}MHz", self.cur_freq / 1000).as_str() + ), temp, usage, self.gov, diff --git a/src/csv.rs b/src/csv.rs index 724aa76d..0706b86d 100644 --- a/src/csv.rs +++ b/src/csv.rs @@ -1,3 +1,4 @@ +#![forbid(unsafe_code)] //! # CSV logging //! This file is reponsible for logging data about the running daemon. //! CSV Logging is by default disabled, however it can be enabled by passing a parameter to the @@ -6,6 +7,9 @@ //! //! It is the responsibility of the implementation of the CSV logger to call the write and init //! methods in order to actually log data. +//! +//! csv.rs logs system data the the state of each cpu to a csv file, not to be confused with +//! logger.rs which write operation logs to the screen during usage. use std::fs::File; use std::io::Write; @@ -24,8 +28,11 @@ use crate::{ pub const CSV_HEADER: &str = "epoch,name,number,max_freq,min_freq,cur_freq,cur_temp,cur_usage,gov"; pub struct CSVWriter { + /// The max amount of file space the csv logger will take up in MB log_size_cutoff: i32, + /// The path to be logged to path: String, + /// If the cpu writer is on enabled: bool, } @@ -50,6 +57,7 @@ pub trait Writable { } impl Writable for CPU { + /// Format the csv row fn to_csv(&self) -> String { format!( "{},{},{},{},{},{},{},{},{}\n", diff --git a/src/daemon.rs b/src/daemon.rs index f0ac5f70..48cea284 100644 --- a/src/daemon.rs +++ b/src/daemon.rs @@ -1,3 +1,4 @@ +#![forbid(unsafe_code)] //! The daemon handles the running auto clock speed instance //! //! # Modes @@ -28,34 +29,35 @@ //! When enabled by the user the daemon will log all of the cpu data to a csv file. use std::convert::TryInto; +use std::process::exit; use std::sync::{Arc, Mutex}; use std::time::SystemTime; use std::{thread, time}; -use colored::Colorize; +use efcl::{color, Color}; use nix::unistd::Uid; use serde::Serialize; -use super::config::Config; -use super::cpu::{Speed, CPU}; -use super::graph::{Graph, Grapher}; -use super::logger; -use super::logger::Interface; -use super::network::{hook, listen}; -use super::power::battery::{has_battery, Battery}; -use super::power::lid::{Lid, LidRetriever, LidState}; -use super::power::{Power, PowerRetriever}; -use super::settings::{GraphType, Settings}; -use super::setup::{inside_docker_message, inside_wsl_message}; -use super::system::{ - check_available_governors, check_cpu_freq, check_cpu_temperature, check_cpu_usage, - get_highest_temp, inside_docker, inside_wsl, list_cpus, parse_proc_file, read_proc_stat_file, - ProcStat, -}; -use super::terminal::terminal_width; -use super::Error; +use crate::config::Config; +use crate::cpu::{Speed, CPU}; use crate::csv::{gen_writer, CSVWriter, Writer}; use crate::display::{print_battery_status, print_turbo_status}; +use crate::error::Error; +use crate::gov::Gov; +use crate::graph::{Graph, GraphType, Grapher}; +use crate::logger; +use crate::logger::Interface; +use crate::network::{hook, listen}; +use crate::power::battery::{has_battery, Battery}; +use crate::power::lid::{Lid, LidRetriever, LidState}; +use crate::power::{Power, PowerRetriever}; +use crate::proc::{parse_proc_file, read_proc_stat_file, ProcStat}; +use crate::settings::Settings; +use crate::setup::{inside_docker_message, inside_wsl_message}; +use crate::system::{ + check_available_governors, check_cpu_freq, check_cpu_temperature, check_cpu_usage, + get_highest_temp, inside_docker, inside_wsl, list_cpus, +}; use crate::warn_user; /// Describes the state of the machine @@ -79,6 +81,8 @@ pub enum State { /// The cpu usage has been high for a certain amount of time /// The cpu will enter performance mode until the usage goes down CpuUsageHigh, + /// Cpu temp is too high + Overheating, /// We down know what state the system is in Unknown, } @@ -94,6 +98,7 @@ fn get_governor(current_state: &State) -> &'static str { State::LidClosed => "powersave", State::Charging => "performance", State::CpuUsageHigh => "performance", + State::Overheating => "powersave", State::Unknown => "powersave", } } @@ -146,27 +151,31 @@ pub struct Daemon { pub usage: f32, pub last_below_cpu_usage_percent: Option, pub graph: String, + /// Highest temperature seen last update cycle (highest of any cpu core) pub temp_max: i8, + /// The hash that is gathered at build time - used for testing versions pub commit_hash: String, pub paused: bool, pub do_update_battery: bool, pub csv_writer: CSVWriter, + /// How often to timeout per cycle when plugged in pub timeout: time::Duration, + /// How often to timeout per cycle when on battery pub timeout_battery: time::Duration, } fn make_gov_powersave(cpu: &mut CPU) -> Result<(), Error> { - cpu.set_gov("powersave".to_string())?; + cpu.set_gov(Gov::Powersave)?; Ok(()) } fn make_gov_performance(cpu: &mut CPU) -> Result<(), Error> { - cpu.set_gov("performance".to_string())?; + cpu.set_gov(Gov::Performance)?; Ok(()) } fn make_gov_schedutil(cpu: &mut CPU) -> Result<(), Error> { - cpu.set_gov("schedutil".to_string())?; + cpu.set_gov(Gov::Schedutil)?; Ok(()) } @@ -176,7 +185,7 @@ fn calculate_average_usage(cpus: &Vec) -> f32 { for cpu in cpus { sum += cpu.cur_usage; } - (sum / (cpus.len() as f32)) as f32 + sum / (cpus.len() as f32) } impl Checker for Daemon { @@ -207,21 +216,22 @@ impl Checker for Daemon { self.last_below_cpu_usage_percent = None; } - match self.last_below_cpu_usage_percent { - Some(last) => { - if SystemTime::now() - .duration_since(last) - .expect("Could not compare times") - .as_secs() - >= 15 - { - state = State::CpuUsageHigh; - } + if let Some(last) = self.last_below_cpu_usage_percent { + if SystemTime::now() + .duration_since(last) + .expect("Could not compare times") + .as_secs() + >= self.config.high_cpu_time_needed + { + state = State::CpuUsageHigh; } - None => {} } } + if self.temp_max > self.config.overheat_threshold { + state = State::Overheating; + } + if self.config.active_rules.contains(&State::LidClosed) && self.lid_state == LidState::Closed { @@ -241,6 +251,7 @@ impl Checker for Daemon { state } + /// Things to be done only at the start of auto clock speed daemon fn init(&mut self) { // Get the commit hash from the compile time env variable if self.settings.commit { @@ -285,6 +296,7 @@ impl Checker for Daemon { } } + /// One iteration of auto clock speed in edit mode fn single_edit(&mut self) -> Result<(), Error> { self.start_loop()?; @@ -309,6 +321,7 @@ impl Checker for Daemon { Ok(()) } + /// One iteration of auto clock speed in monitor mode fn single_monit(&mut self) -> Result<(), Error> { self.start_loop()?; self.end_loop(); @@ -331,7 +344,7 @@ impl Checker for Daemon { } } - let cur_proc = parse_proc_file(read_proc_stat_file()?)?; + let cur_proc = parse_proc_file(read_proc_stat_file()?); for cpu in self.cpus.iter_mut() { cpu.update()?; for (i, proc) in self.last_proc.iter().enumerate() { @@ -361,9 +374,12 @@ impl Checker for Daemon { Ok(()) } + /// All text is rendered before anything is printed + /// This method of rendering text reduces lag and fixes a flickering problem from before 0.1.8 + /// This section is just a chunk of the text that gets rendered fn preprint_render(&mut self) -> String { let message = format!("{}\n", self.message); - let title = "Name\tMax\tMin\tFreq\tTemp\tUsage\tGovernor\n".bold(); + let title = "Name\tMax\tMin\tFreq\tTemp\tUsage\tGovernor\n"; // Render each line of cpu core let cpus = &self.cpus.iter().map(|c| format!("{c}")).collect::(); @@ -377,6 +393,9 @@ impl Checker for Daemon { ) } + /// All text is rendered before anything is printed + /// This method of rendering text reduces lag and fixes a flickering problem from before 0.1.8 + /// This section is just a chunk of the text that gets rendered fn postprint_render(&mut self) -> String { // Display the current graph type let graph_type = if self.settings.graph != GraphType::Hidden { @@ -428,7 +447,7 @@ impl Checker for Daemon { self.graph = self.grapher.update_one(&mut self.grapher.vals.clone()); } - let term_width = terminal_width(); + let (term_width, _term_height) = termion::terminal_size().unwrap(); // Render two sections of the output // Rendering before screen is cleared reduces the time between clear and print @@ -456,8 +475,8 @@ impl Checker for Daemon { print_turbo_status( cores, - self.settings.no_animation, - term_width, + self.settings.animation, + term_width.into(), delay_in_millis, ); @@ -487,6 +506,7 @@ impl Checker for Daemon { } } +/// Message at the header of autoclockspeed - rendered before auto clock speed loop starts fn format_message( edit: bool, started_as_edit: bool, @@ -499,17 +519,17 @@ fn format_message( format!( "Auto Clock Speed daemon has been initialized in {} mode with a delay of {}ms normally and {}ms when on battery{}\n", if edit { - "edit".red() + color!(Color::RED, "edit") } else { - "monitor".yellow() + color!(Color::YELLOW, "monitor") }, delay, delay_battery, - if started_as_edit != edit { format!("\nForced to monitor mode because {}!", forced_reason).red() } else { "".normal() } + if started_as_edit != edit { color!(Color::RED, format!("\nForced to monitor mode because {}!", forced_reason).as_str()) } else { "".to_string() } ) } -pub fn daemon_init(settings: Settings, config: Config) -> Result>, Error> { +pub fn daemon_init(settings: Settings, config: Config) -> Arc> { let started_as_edit: bool = settings.edit; let mut edit = settings.edit; let mut forced_reason: String = String::new(); @@ -527,7 +547,7 @@ pub fn daemon_init(settings: Settings, config: Config) -> Result Result Result Result::new(), - }, + grapher: Graph::new(), temp_max: 0, commit_hash: String::new(), timeout: time::Duration::from_millis(1), @@ -643,7 +662,7 @@ pub fn daemon_init(settings: Settings, config: Config) -> Result>) -> Result<(), Error> { @@ -671,6 +690,11 @@ pub fn run(daemon_mutex: Arc>) -> Result<(), Error> { // Before runnig the loop drop the lock and aquire it again later within the loop let mode = daemon.settings.edit; + if daemon.settings.show_settings { + println!("{:#?}", daemon.settings); + exit(0); + } + drop(daemon); // Choose which mode acs runs in @@ -707,28 +731,14 @@ pub fn run(daemon_mutex: Arc>) -> Result<(), Error> { #[cfg(test)] mod tests { use super::*; - use crate::config::default_config; + use crate::settings::DefaultTesting; #[test] fn daemon_init_force_to_monit_integration_test() { - let settings = Settings { - verbose: true, - delay: 1, - delay_battery: 2, - hook: false, - edit: true, - no_animation: false, - graph: GraphType::Hidden, - commit: false, - testing: true, - csv_file: "".to_string(), - log_csv: false, - log_size_cutoff: 20, - }; - - let config = default_config(); + let settings = Settings::default_testing(); + let config = Config::default(); - let daemon_mutex = daemon_init(settings, config).unwrap(); + let daemon_mutex = daemon_init(settings, config); let daemon = daemon_mutex.lock().unwrap(); if Uid::effective().is_root() { @@ -742,24 +752,10 @@ mod tests { fn preprint_render_test_edit_integration_test() { // It should be possible to skip tests ):< // https://github.com/Camerooooon/dev-log/blob/main/logs/2022-06-13.md - let settings = Settings { - verbose: true, - delay: 1, - delay_battery: 2, - hook: false, - edit: true, - no_animation: false, - graph: GraphType::Hidden, - commit: false, - testing: true, - csv_file: "".to_string(), - log_csv: false, - log_size_cutoff: 20, - }; - - let config = default_config(); + let settings = Settings::default_testing(); + let config = Config::default(); - let daemon_mutex = daemon_init(settings, config).unwrap(); + let daemon_mutex = daemon_init(settings, config); let mut daemon = daemon_mutex.lock().unwrap(); let preprint = daemon.preprint_render(); if Uid::effective().is_root() { @@ -776,24 +772,10 @@ mod tests { #[test] fn preprint_render_test_monit_integration_test() { - let settings = Settings { - verbose: true, - delay: 1, - delay_battery: 2, - hook: false, - edit: false, - no_animation: false, - graph: GraphType::Hidden, - commit: false, - testing: true, - csv_file: "".to_string(), - log_csv: false, - log_size_cutoff: 20, - }; - - let config = default_config(); + let settings = Settings::default_testing(); + let config = Config::default(); - let daemon_mutex = daemon_init(settings, config).unwrap(); + let daemon_mutex = daemon_init(settings, config); let mut daemon = daemon_mutex.lock().unwrap(); let preprint = daemon.preprint_render(); assert!(preprint.contains("Auto Clock Speed daemon has been initialized in \u{1b}[33mmonitor\u{1b}[0m mode with a delay of 1ms normally and 2ms when on battery\n")); diff --git a/src/display.rs b/src/display.rs index 60715b33..f3d79f5d 100644 --- a/src/display.rs +++ b/src/display.rs @@ -1,3 +1,5 @@ +#![forbid(unsafe_code)] +use efcl::{color, Color}; use std::fmt::Display; use std::thread; @@ -6,21 +8,28 @@ use super::cpu::CPU; use super::power::lid::LidState; use super::system::check_turbo_enabled; use crate::power::battery::{has_battery, Battery, BatteryStatus}; -use colored::Colorize; #[macro_export] macro_rules! warn_user { ($a:expr) => {{ - use colored::Colorize; - println!("{}: {}", "WARN".bold().yellow(), $a,); + use efcl::{color, Color}; + println!("{}: {}", color!(Color::YELLOW, "WARN"), $a,); }}; } #[macro_export] macro_rules! print_error { ($a:expr) => {{ - use colored::Colorize; - println!("{}: {}", "ERROR".bold().red(), $a,); + use efcl::{color, Color}; + println!("{}: {}", color!(Color::RED, "ERROR"), $a,); + }}; +} + +#[macro_export] +macro_rules! print_done { + ($a:expr) => {{ + use efcl::{color, Color}; + println!("{}: {}", color!(Color::GREEN, "DONE"), $a,); }}; } @@ -82,13 +91,13 @@ pub fn print_battery_status(battery: &Battery) -> String { format!( "Battery: {}", if battery.status == BatteryStatus::Charging { - format!("{}%", battery.capacity).green() + color!(Color::GREEN, format!("{}%", battery.capacity).as_str()) } else { - format!("{}%", battery.capacity).red() + color!(Color::RED, format!("{}%", battery.capacity).as_str()) }, ) } else { - format!("Battery: {}", "N/A".bold()) + format!("Battery: {}", "N/A") } } @@ -110,7 +119,7 @@ pub fn print_turbo_animation(cpu: usize, y_pos: usize, delay: u64) { }); } -pub fn print_turbo_status(cores: usize, no_animation: bool, term_width: usize, delay: u64) { +pub fn print_turbo_status(cores: usize, animation: bool, term_width: usize, delay: u64) { let mut turbo_y_pos: usize = 8; let title_width = 94; @@ -120,12 +129,13 @@ pub fn print_turbo_status(cores: usize, no_animation: bool, term_width: usize, d match check_turbo_enabled() { Ok(turbo) => { - let enabled_message = if turbo { "yes" } else { "no" }; - - println!(" Turbo: {}", enabled_message.bold()); + let enabled_message = if turbo { "enabled" } else { "disabled" }; - if !no_animation { + if animation { + println!(" Turbo: {}", enabled_message); print_turbo_animation(cores, turbo_y_pos, delay); + } else { + println!("Turbo: {}", enabled_message); } } Err(..) => eprintln!("Could not check turbo. Expected for AMD.\n"), diff --git a/src/error.rs b/src/error.rs index e6ad2268..2a34213a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,3 +1,4 @@ +#![forbid(unsafe_code)] use std::fmt; const BUG_REPORT: &str = "\nGive us a bug report by opening an issue at diff --git a/src/gov.rs b/src/gov.rs new file mode 100644 index 00000000..e53f4606 --- /dev/null +++ b/src/gov.rs @@ -0,0 +1,23 @@ +#![forbid(unsafe_code)] +use std::fmt; + +/// Governor +/// +/// https://www.kernel.org/doc/html/v4.14/admin-guide/pm/cpufreq.html#generic-scaling-governors +pub enum Gov { + Powersave, + Performance, + Schedutil, +} + +impl fmt::Display for Gov { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let name = match &self { + Gov::Powersave => "powersave", + Gov::Performance => "performance", + Gov::Schedutil => "schedutil", + }; + + write!(f, "{}", name) + } +} diff --git a/src/graph.rs b/src/graph.rs index 9b8525cc..ab03b772 100644 --- a/src/graph.rs +++ b/src/graph.rs @@ -1,14 +1,20 @@ +#![forbid(unsafe_code)] use rasciigraph::{plot, Config}; +use std::default::Default; +use std::fmt; pub trait Grapher { fn update_all(&mut self); fn update_one(&self, vec: &mut Vec) -> String; fn clear_before(&self, vec: &mut Vec); fn plot(&self, nums: Vec) -> String; + fn new() -> Self; } pub struct Graph { + /// The values that get graphed pub vals: Vec, + max: usize, } impl Grapher for Graph { @@ -22,7 +28,7 @@ impl Grapher for Graph { } fn clear_before(&self, vec: &mut Vec) { - while vec.len() > 40 { + while vec.len() > self.max { vec.remove(0); } } @@ -33,4 +39,49 @@ impl Grapher for Graph { plot(nums, Config::default().with_offset(10).with_height(10)) ) } + + fn new() -> Self { + Graph { + vals: Vec::::new(), + max: 40, + } + } +} + +#[derive(PartialEq, Eq, Clone, Debug)] +pub enum GraphType { + Hidden, + Frequency, + Usage, + Temperature, + Unknown, +} + +impl Default for GraphType { + fn default() -> GraphType { + GraphType::Hidden + } +} + +impl fmt::Display for GraphType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + GraphType::Hidden => write!(f, "hidden"), + GraphType::Frequency => write!(f, "frequency"), + GraphType::Usage => write!(f, "usage"), + GraphType::Temperature => write!(f, "temperature"), + GraphType::Unknown => write!(f, "unknown"), + } + } +} + +/// Parse from graph_type parameter which type of graph will be displayed +pub fn get_graph_type(graph_type: &str) -> GraphType { + match graph_type.to_lowercase().as_str() { + "hidden" => GraphType::Hidden, + "freq" => GraphType::Frequency, + "usage" => GraphType::Usage, + "temp" => GraphType::Temperature, + _ => GraphType::Unknown, + } } diff --git a/src/interactive.rs b/src/interactive.rs index 9d06d677..dde558cf 100644 --- a/src/interactive.rs +++ b/src/interactive.rs @@ -1,7 +1,8 @@ +#![forbid(unsafe_code)] use super::config::{get_config, Config}; use super::interface::{DaemonControl, DaemonController, Get, Getter, Interface, Set, Setter}; -use super::settings::{GraphType, Settings}; -use colored::Colorize; +use super::settings::Settings; +use efcl::{bold, color, Color}; use std::io::{stdin, stdout, Write}; pub fn help() { @@ -32,8 +33,7 @@ pub fn help() { E.g. 'get cpus' "; - println!("{}\n", "Help:".bold().green()); - println!("{HELP_TEXT}") + println!("{}{HELP_TEXT}", color!(Color::GREEN, "Help:\n")); } pub fn interactive() { @@ -45,26 +45,13 @@ pub fn interactive() { let mut input; - println!("{}", "Auto Clock Speed".bold()); - println!("{}", "Interactive Mode".bold().blue()); - - let set_settings = Settings { - verbose: true, - delay_battery: 0, - delay: 0, - edit: false, - hook: false, - no_animation: false, - graph: GraphType::Hidden, - commit: false, - testing: false, - csv_file: "".to_string(), - log_csv: false, - log_size_cutoff: 20, - }; + println!("{}", bold!("Auto Clock Speed")); + println!("{}", color!(Color::BLUE, "Interactive Mode")); + + let set_settings = Settings::default(); loop { - print!("{}", "\n> ".bold().green()); + print!("{}", color!(Color::GREEN, "\n> ")); stdout().flush().expect("Failed to flush stdout"); input = String::new(); @@ -77,7 +64,7 @@ pub fn interactive() { "help" => help(), "get freq" => int.get.freq(false), "get power" => int.get.power(false), - "get usage" => int.get.usage(false), + "get usage" => int.get.usage(false, None), "get turbo" => int.get.turbo(false), "get available_governors" => int.get.available_govs(false), "get cpus" => int.get.cpus(false), @@ -110,7 +97,10 @@ pub fn interactive() { } _ => println!( "{}", - format!("Command '{}' not found. Use 'help'.", new).red() + color!( + Color::RED, + format!("Command '{}' not found. Use 'help'.", new).as_str() + ) ), }; } diff --git a/src/interface.rs b/src/interface.rs index b2890b8d..967a33a3 100644 --- a/src/interface.rs +++ b/src/interface.rs @@ -1,3 +1,11 @@ +#![forbid(unsafe_code)] +///! The interface creates an API for getting and setting values with ACS +///! +///! Note: this is not an API for all of the functions in ACS, it's only the ones that get used in +///! the command line tools made available in the ACS binary ('acs') and defined in src/args.rs +///! +///! This file offloads a lot of the work that was in src/args.rs but was too repetitive. +///! use super::config::Config; use super::daemon::{daemon_init, Checker}; use super::display::{ @@ -121,7 +129,7 @@ pub struct Get {} pub trait Getter { fn freq(&self, raw: bool); fn power(&self, raw: bool); - fn usage(&self, raw: bool); + fn usage(&self, raw: bool, delay: Option); fn thermal(&self, raw: bool); fn turbo(&self, raw: bool); fn available_govs(&self, raw: bool); @@ -175,11 +183,14 @@ impl Getter for Get { print_power(lid, battery.capacity, plugged, raw); } - fn usage(&self, raw: bool) { + fn usage(&self, raw: bool, delay: Option) { if !raw { - println!("Calculating cpu percentage over 1 second."); + println!( + "Calculating cpu percentage over {} second.", + delay.unwrap_or(1) + ); } - let percent = get_cpu_percent(); + let percent = get_cpu_percent(delay); if raw { println!("{}", percent) @@ -263,13 +274,11 @@ pub trait Setter { impl Setter for Set { fn gov(&self, value: String, config: Config, settings: Settings) { // Create the daemon to set the gov - match daemon_init(settings, config) { - Ok(d) => match d.lock().unwrap().set_govs(value) { - Ok(_) => {} - Err(e) => eprint!("Could not set gov, {:?}", e), - }, - Err(_) => eprint!("Could not run daemon in edit mode"), - } + let d = daemon_init(settings, config); + match d.lock().unwrap().set_govs(value) { + Ok(_) => {} + Err(e) => eprint!("Could not set gov, {:?}", e), + }; } } diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 00000000..cee63b51 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,20 @@ +pub mod args; +pub mod config; +pub mod cpu; +pub mod csv; +pub mod daemon; +pub mod display; +pub mod error; +pub mod gov; +pub mod graph; +pub mod interactive; +pub mod interface; +pub mod logger; +pub mod network; +pub mod power; +pub mod proc; +pub mod settings; +pub mod setup; +pub mod sysfs; +pub mod system; +pub mod thermal; diff --git a/src/logger.rs b/src/logger.rs index 26be9d03..6b8a3363 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -1,12 +1,24 @@ -extern crate chrono; +//! This file contains a logging system for the Auto Clock Speed (ACS) project. +//! +//! It allows the program to log messages with different severity levels (error, warning, log) and display them in a human-readable format. +//! +//! The log messages contain a timestamp, a severity level and the message. The logs are stored in a vector and are serializable and deserializable. The logs can also be displayed in a human-readable format. +extern crate time; +use efcl::{color, Color}; +use serde::{Deserialize, Serialize}; use std::fmt; use std::time::SystemTime; +use time::{format_description, OffsetDateTime}; -use chrono::prelude::DateTime; -use chrono::Utc; -use colored::Colorize; - +#[derive(Debug, Eq, PartialEq, Serialize, Deserialize)] +/// The Severity enum is used to represent the different levels of severity of a log message. It has three possible values: +/// +/// - `Error` represents an error message that indicates that something went wrong. +/// - `Warning` represents a warning message that indicates that something unexpected happened but the program can still continue to run. +/// - `Log` represents a log message that contains information about the program execution. +/// +/// This enum is used in the log function of the Logger struct to specify the severity level of the log message when creating a new log. It also used in the fmt function of the Log struct, where it is matched to colorize the output based on the severity level of the log message. pub enum Severity { Error, Warning, @@ -17,6 +29,7 @@ pub trait Interface { fn log(&mut self, msg: &str, sev: Severity); } +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct Log { pub message: String, pub severity: Severity, @@ -26,12 +39,26 @@ pub struct Log { impl fmt::Display for Log { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let severity = match &self.severity { - Severity::Error => "error:".bold().red(), - Severity::Warning => "warn:".bold().yellow(), - Severity::Log => "notice:".bold().blue(), + Severity::Error => color!(Color::RED, "error:"), + Severity::Warning => color!(Color::YELLOW, "warn:"), + Severity::Log => color!(Color::BLUE, "notice:"), }; - let time = DateTime::::from(self.timestamp).format("%Y-%m-%d %H:%M:%S"); + let date_time_fmt = + format_description::parse("[year]-[month]-[day] [hour]:[minute]:[second]") + .expect("Invalid time format."); + + let mut time = OffsetDateTime::from(self.timestamp) + .format(&date_time_fmt) + .unwrap(); + + if OffsetDateTime::now_local().is_ok() { + time = OffsetDateTime::now_local() + .expect("IndeterminateOffset") + .format(&date_time_fmt) + .unwrap(); + } + write!(f, "{} {} -> {}", severity, time, self.message) } } diff --git a/src/network.rs b/src/network.rs index ac447f2e..13ea2420 100644 --- a/src/network.rs +++ b/src/network.rs @@ -1,3 +1,8 @@ +#![forbid(unsafe_code)] +use serde::{Deserialize, Serialize}; + +use crate::logger::Log; + use super::daemon::Daemon; use super::logger; use super::logger::Interface; @@ -14,7 +19,7 @@ pub mod hook; pub mod listen; pub mod send; -#[derive(PartialEq, Eq, Debug)] +#[derive(PartialEq, Eq, Debug, Serialize, Deserialize)] pub enum Packet { Hello(String), HelloResponse(String, u32), @@ -24,6 +29,9 @@ pub enum Packet { DaemonEnableResponse(bool), DaemonStatusRequest(), DaemonStatusResponse(bool), + DaemonLogRequest(), + DaemonLogResponse(Vec), + DaemonLogEvent(Log), Unknown, } @@ -49,57 +57,16 @@ impl From for PacketParseError { } pub fn parse_packet(packet: &str) -> Result { - let mut packet_split = packet.split('|'); - let packet_type = packet_split.next().ok_or(PacketParseError)?; - match packet_type { - "0" => Ok(Packet::Hello( - packet_split.next().ok_or(PacketParseError)?.to_string(), - )), - "1" => Ok(Packet::HelloResponse( - packet_split.next().ok_or(PacketParseError)?.to_string(), - packet_split - .next() - .ok_or(PacketParseError)? - .parse::()?, - )), - "2" => Ok(Packet::DaemonDisableRequest()), - "3" => Ok(Packet::DaemonDisableResponse( - packet_split - .next() - .ok_or(PacketParseError)? - .parse::()?, - )), - "4" => Ok(Packet::DaemonEnableRequest()), - "5" => Ok(Packet::DaemonEnableResponse( - packet_split - .next() - .ok_or(PacketParseError)? - .parse::()?, - )), - "6" => Ok(Packet::DaemonStatusRequest()), - "7" => Ok(Packet::DaemonStatusResponse( - packet_split - .next() - .ok_or(PacketParseError)? - .parse::()?, - )), - _ => Err(PacketParseError), - } + serde_json::from_str(packet).map_err(|_| PacketParseError) } impl Display for Packet { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Packet::Hello(data) => writeln!(f, "0|{}", data), - Packet::HelloResponse(data, version) => writeln!(f, "1|{}|{}", data, version), - Packet::DaemonDisableRequest() => writeln!(f, "2"), - Packet::DaemonDisableResponse(data) => writeln!(f, "3|{}", data), - Packet::DaemonEnableRequest() => writeln!(f, "4"), - Packet::DaemonEnableResponse(data) => writeln!(f, "5|{}", data), - Packet::DaemonStatusRequest() => writeln!(f, "6"), - Packet::DaemonStatusResponse(data) => writeln!(f, "7|{}", data), - Packet::Unknown => writeln!(f), - } + writeln!( + f, + "{}", + serde_json::to_string(self).unwrap_or_else(|_| "?".to_string()) + ) } } @@ -107,15 +74,3 @@ fn log_to_daemon(daemon: &Arc>, message: &str, severity: logger::S let mut daemon = daemon.lock().unwrap(); daemon.logger.log(message, severity); } - -#[cfg(test)] -mod tests { - use crate::network::{parse_packet, Packet}; - - #[test] - fn parse_packet_test() { - assert!(parse_packet("0|test").unwrap() == Packet::Hello("test".to_string())); - assert!(parse_packet("1|test|5").unwrap() == Packet::HelloResponse("test".to_string(), 5)); - assert!(parse_packet("0|test").unwrap() != Packet::HelloResponse("test".to_string(), 5)); - } -} diff --git a/src/network/hook.rs b/src/network/hook.rs index 9f0ddc7b..324f3e62 100644 --- a/src/network/hook.rs +++ b/src/network/hook.rs @@ -1,3 +1,4 @@ +#![forbid(unsafe_code)] use crate::network::{log_to_daemon, logger, Daemon, Packet}; use std::io::{BufRead, BufReader, Write}; use std::os::unix::net::UnixStream; diff --git a/src/network/listen.rs b/src/network/listen.rs index ac1b3c4d..9bfaf508 100644 --- a/src/network/listen.rs +++ b/src/network/listen.rs @@ -1,3 +1,4 @@ +#![forbid(unsafe_code)] use crate::logger; use crate::logger::Interface; use crate::network::log_to_daemon; @@ -147,7 +148,10 @@ pub fn handle_stream(stream: UnixStream, c_daemon_mutex: &Arc>) { let mut writer = BufWriter::new(&stream); write_packet!(writer, response); } - Packet::DaemonStatusResponse(_) => todo!(), + Packet::DaemonStatusResponse(_) => {} + Packet::DaemonLogRequest() => {} + Packet::DaemonLogResponse(_) => {} + Packet::DaemonLogEvent(_) => {} }; } }); diff --git a/src/network/send.rs b/src/network/send.rs index 8676baf2..5be30366 100644 --- a/src/network/send.rs +++ b/src/network/send.rs @@ -1,3 +1,4 @@ +#![forbid(unsafe_code)] use std::{ io::{BufRead, BufReader, Write}, os::unix::net::UnixStream, diff --git a/src/power.rs b/src/power.rs index 0e3a2ce1..bc80e304 100644 --- a/src/power.rs +++ b/src/power.rs @@ -1,13 +1,15 @@ +#![forbid(unsafe_code)] use std::fs; use std::path::Path; -use super::Error; +use crate::error::Error; pub mod battery; pub mod lid; /// Called once at the start of read_power_source -fn set_best_path() -> Option<&'static str> { +/// Discover the path to the AC power_supply +pub fn set_best_path() -> Option<&'static str> { // Only loaded once static POWER_SOURCE_PATH: [&str; 4] = [ "/sys/class/power_supply/AC/online", @@ -39,6 +41,9 @@ pub trait PowerRetriever { impl PowerRetriever for Power { fn new() -> Self { + // If a path for the AC power_supply is found + // store it as found_path so that it does not have to be found + // multiple times if let Some(path) = set_best_path() { Power { best_path: path, diff --git a/src/power/battery.rs b/src/power/battery.rs index 3326f9bd..4acbd96c 100644 --- a/src/power/battery.rs +++ b/src/power/battery.rs @@ -1,5 +1,6 @@ +#![forbid(unsafe_code)] +use crate::error::Error; use crate::sysfs; -use crate::Error; use std::any::Any; use std::fs::read_dir; use std::path::{Path, PathBuf}; diff --git a/src/power/lid.rs b/src/power/lid.rs index 9effdc1d..98a88f38 100644 --- a/src/power/lid.rs +++ b/src/power/lid.rs @@ -1,4 +1,5 @@ -use crate::Error; +#![forbid(unsafe_code)] +use crate::error::Error; use std::cmp::PartialEq; use std::fmt; use std::fs; @@ -63,14 +64,11 @@ impl LidRetriever for Lid { let lid_str = fs::read_to_string(self.best_path)?; - let state = if lid_str.contains("open") { - LidState::Open - } else if lid_str.contains("closed") { - LidState::Closed - } else { - LidState::Unknown - }; - Ok(state) + Ok(match lid_str.split_whitespace().last().unwrap() { + "open" => LidState::Open, + "closed" => LidState::Closed, + _ => LidState::Unknown, + }) } } diff --git a/src/proc.rs b/src/proc.rs new file mode 100644 index 00000000..469935bc --- /dev/null +++ b/src/proc.rs @@ -0,0 +1,69 @@ +#![forbid(unsafe_code)] +use std::fs::read_to_string; + +use crate::error::Error; + +/// Contains data about each cpu's timing read from the `/proc/stat` file +#[derive(Debug)] +pub struct ProcStat { + pub cpu_name: String, + pub cpu_sum: f32, + pub cpu_idle: f32, +} + +impl Default for ProcStat { + fn default() -> ProcStat { + ProcStat { + cpu_name: "cpu".to_string(), + cpu_sum: 0.0, + cpu_idle: 0.0, + } + } +} + +/// Reads the raw proc stat data from the `/proc/stat` file +pub fn read_proc_stat_file() -> Result { + let proc_stat_path: &str = "/proc/stat"; + let proc_stat_content = read_to_string(proc_stat_path)?; + Ok(proc_stat_content) +} + +/// Parse the `/proc/stat` into a list of `ProcStat` structs for each CPU core +pub fn parse_proc_file(proc: String) -> Vec { + let lines: Vec<_> = proc.lines().collect(); + let mut procs: Vec = Vec::::new(); + for l in lines { + if l.starts_with("cpu") { + let mut columns: Vec<_> = l.split(' ').collect(); + + // Remove first index if cpu starts with "cpu " because the two spaces count as a + // column + if l.starts_with("cpu ") { + columns.remove(0); + } + + let mut proc_struct: ProcStat = ProcStat { + cpu_name: columns[0].to_string(), + // fill in the rest of the values + ..Default::default() + }; + + for col in &columns { + let parse = col.parse::(); + if let Ok(num) = parse { + proc_struct.cpu_sum += num; + } + } + + let num = columns[4] + .parse::() + .expect("Should have parsed float from /proc/stat file."); + proc_struct.cpu_idle = num; + procs.push(proc_struct); + } else { + // Leave after lines are not prefixed with cpu + break; + } + } + procs +} diff --git a/src/settings.rs b/src/settings.rs index 391bb51a..584310b2 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -1,49 +1,64 @@ -use std::fmt; +#![forbid(unsafe_code)] +use super::graph::GraphType; +use std::default::Default; -#[derive(PartialEq, Eq, Clone)] -pub enum GraphType { - Hidden, - Frequency, - Usage, - Temperature, - Unknown, +pub trait DefaultTesting { + fn default_testing() -> Settings; } -impl fmt::Display for GraphType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - GraphType::Hidden => write!(f, "hidden"), - GraphType::Frequency => write!(f, "frequency"), - GraphType::Usage => write!(f, "usage"), - GraphType::Temperature => write!(f, "temperature"), - GraphType::Unknown => write!(f, "unknown"), - } - } -} - -/// Parse from graph_type parameter which type of graph will be displayed -pub fn get_graph_type(graph_type: &str) -> GraphType { - match graph_type.to_lowercase().as_str() { - "hidden" => GraphType::Hidden, - "freq" => GraphType::Frequency, - "usage" => GraphType::Usage, - "temp" => GraphType::Temperature, - _ => GraphType::Unknown, - } -} - -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Settings { pub verbose: bool, pub delay: u64, pub delay_battery: u64, pub edit: bool, pub hook: bool, - pub no_animation: bool, + pub animation: bool, pub graph: GraphType, pub commit: bool, pub testing: bool, pub csv_file: String, pub log_csv: bool, pub log_size_cutoff: i32, + pub show_settings: bool, +} + +impl Default for Settings { + fn default() -> Settings { + Settings { + verbose: true, + delay: 1000, + delay_battery: 1000, + edit: false, + hook: false, + animation: true, + graph: GraphType::default(), + commit: false, + testing: false, + csv_file: String::default(), + log_csv: false, + log_size_cutoff: 0, + show_settings: false, + } + } +} + +impl DefaultTesting for Settings { + fn default_testing() -> Settings { + Settings { + verbose: true, + delay: 1, + delay_battery: 2, + edit: false, + hook: false, + animation: true, + graph: GraphType::Hidden, + commit: false, + testing: true, + csv_file: String::default(), + log_csv: false, + log_size_cutoff: 0, + show_settings: false, + } + } } diff --git a/src/setup.rs b/src/setup.rs index 61e3f166..d4f75b91 100644 --- a/src/setup.rs +++ b/src/setup.rs @@ -1,5 +1,8 @@ +#![forbid(unsafe_code)] +use super::config::config_dir_exists; use super::system::{inside_docker, inside_wsl}; use super::warn_user; +use std::{thread, time}; pub fn inside_wsl_message() -> String { String::from( @@ -21,3 +24,10 @@ pub fn setup() { warn_user!(inside_docker_message()); } } + +pub fn check_config_dir_exists() { + if !config_dir_exists() { + warn_user!("Config directory '/etc/acs' does not exist!"); + thread::sleep(time::Duration::from_millis(5000)); + } +} diff --git a/src/sysfs.rs b/src/sysfs.rs index 91fe10f0..9f0d7287 100644 --- a/src/sysfs.rs +++ b/src/sysfs.rs @@ -1,4 +1,5 @@ -use crate::Error; +#![forbid(unsafe_code)] +use crate::error::Error; use globset::Glob; use std::fs; use std::path::{Path, PathBuf}; diff --git a/src/system.rs b/src/system.rs index 6be1b095..92140764 100644 --- a/src/system.rs +++ b/src/system.rs @@ -1,3 +1,4 @@ +#![forbid(unsafe_code)] use cached::proc_macro::once; use std::fs::{self, read_dir}; use std::path::Path; @@ -5,12 +6,19 @@ use std::string::String; use std::{thread, time}; use crate::cpu::Speed; -use crate::debug; +use crate::proc::{parse_proc_file, read_proc_stat_file, ProcStat}; +use log::debug; -use super::cpu::CPU; -use super::Error; +use crate::cpu::CPU; +use crate::error::Error; /// Find the average frequency of all cores +/// +/// ``` +/// let cpus: &[CPU] = &[CPU::default(), CPU::default()]; +/// let avg = check_cpu_freq(cpus); +/// assert_eq!(avg, 0.0); +/// ``` pub fn check_cpu_freq(cpus: &[CPU]) -> f32 { let freqs: Vec = cpus.iter().map(|x| x.cur_freq).collect(); let sum: i32 = Iterator::sum(freqs.iter()); @@ -31,6 +39,13 @@ pub fn check_cpu_temperature(cpus: &[CPU]) -> f32 { sum as f32 / usage.len() as f32 } +/// Get the max temp from the cpus +/// +/// ``` +/// let cpus: &[CPU] = &[CPU::random(), CPU::random()]; +/// let max = get_highest_temp(cpus); +/// assert_ne!(max, 0); +/// ``` pub fn get_highest_temp(cpus: &[CPU]) -> i32 { let mut temp_max: i32 = 0; for cpu in cpus { @@ -58,10 +73,14 @@ pub fn inside_wsl() -> bool { false } +/// Return the /proc/cpuinfo file as a string fn open_cpu_info() -> Result { Ok(fs::read_to_string("/proc/cpuinfo")?) } +/// Get the name of the cpu +/// +/// For instance, my cpu's name is 'Intel(R) Core(TM) i5-7600K CPU @ 3.80GHz' fn get_name_from_cpu_info(cpu_info: String) -> Result { // Find all lines that begin with cpu MHz let find_cpu_mhz = cpu_info @@ -76,76 +95,23 @@ fn get_name_from_cpu_info(cpu_info: String) -> Result { .ok_or(Error::Unknown) } +/// Output the name of the cpu pub fn check_cpu_name() -> Result { let cpu_info: String = open_cpu_info()?; let name: String = get_name_from_cpu_info(cpu_info)?; Ok(name) } -pub fn read_proc_stat_file() -> Result { - let proc_stat_path: &str = "/proc/stat"; - let proc_stat_content = fs::read_to_string(proc_stat_path)?; - Ok(proc_stat_content) -} - -#[derive(Debug)] -pub struct ProcStat { - pub cpu_name: String, - pub cpu_sum: f32, - pub cpu_idle: f32, -} - -impl Default for ProcStat { - fn default() -> ProcStat { - ProcStat { - cpu_name: "cpu".to_string(), - cpu_sum: 0.0, - cpu_idle: 0.0, - } - } -} - -pub fn parse_proc_file(proc: String) -> Result, Error> { - let lines: Vec<_> = proc.lines().collect(); - let mut procs: Vec = Vec::::new(); - for l in lines { - if l.starts_with("cpu") { - let mut columns: Vec<_> = l.split(' ').collect(); - - // Remove first index if cpu starts with "cpu " because the two spaces count as a - // column - if l.starts_with("cpu ") { - columns.remove(0); - } - let mut proc_struct: ProcStat = ProcStat::default(); - proc_struct.cpu_name = columns[0].to_string(); - for col in &columns { - let parse = col.parse::(); - if let Ok(num) = parse { - proc_struct.cpu_sum += num; - } - } - - if let Ok(num) = columns[4].parse::() { - proc_struct.cpu_idle = num; - } - procs.push(proc_struct); - } else { - // Leave after lines are not prefixed with cpu - break; - } - } - Ok(procs) -} +pub fn get_cpu_percent(delay: Option) -> String { + let mut proc = read_proc_stat_file().expect("/proc/stat file should exist."); + let avg_timing: &ProcStat = &parse_proc_file(proc)[0]; -pub fn get_cpu_percent() -> String { - let mut proc = read_proc_stat_file().unwrap(); - let avg_timing: &ProcStat = &parse_proc_file(proc).unwrap()[0]; + let millis = if let Some(d) = delay { d * 1000 } else { 1000 }; - thread::sleep(time::Duration::from_millis(1000)); + thread::sleep(time::Duration::from_millis(millis)); proc = read_proc_stat_file().unwrap(); - let avg_timing_2: &ProcStat = &parse_proc_file(proc).unwrap()[0]; + let avg_timing_2: &ProcStat = &parse_proc_file(proc)[0]; format!( "{}", @@ -449,7 +415,7 @@ mod tests { #[test] fn test_parse_proc_stat_file() { - let cpu_percent = get_cpu_percent().parse::().unwrap(); + let cpu_percent = get_cpu_percent(None).parse::().unwrap(); assert_eq!(type_of(cpu_percent), type_of(0.0_f32)); assert!(cpu_percent > 0.0 && cpu_percent < 100.0); } diff --git a/src/terminal.rs b/src/terminal.rs deleted file mode 100644 index 654e57a1..00000000 --- a/src/terminal.rs +++ /dev/null @@ -1,15 +0,0 @@ -use nix::libc::{c_short, c_ushort, ioctl, STDOUT_FILENO, TIOCGWINSZ}; -use std::mem; - -pub struct TermSize { - pub row: c_short, - pub col: c_ushort, -} - -pub fn terminal_width() -> usize { - unsafe { - let mut size: TermSize = mem::zeroed(); - ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut size as *mut _); - size.col as usize - } -} diff --git a/src/thermal.rs b/src/thermal.rs index 9834b6a3..dfbd218a 100644 --- a/src/thermal.rs +++ b/src/thermal.rs @@ -1,6 +1,7 @@ +#![forbid(unsafe_code)] use super::system::{read_int, read_str}; use crate::error::Error; -use colored::Colorize; +use efcl::{color, Color}; use std::fmt::Display; use std::fmt::Formatter; use std::fs::read_dir; @@ -36,12 +37,12 @@ impl Display for ThermalZone { f, "{} {}{} {}", if self.enabled { - self.name.green() + color!(Color::GREEN, &self.name) } else { - self.name.red() + color!(Color::RED, &self.name) }, - (self.temp / 1000).to_string().yellow(), - "C°".yellow(), + color!(Color::YELLOW, (self.temp / 1000).to_string().as_str()), + color!(Color::YELLOW, "C°"), self.path ) } @@ -56,12 +57,12 @@ pub fn read_thermal_zones() -> Result, Error> { continue; } - let mut zone = ThermalZone::default(); - - zone.temp = read_int(&[&path_string, "/temp"].concat())?; - zone.name = read_str(&[&path_string, "/type"].concat())?; - zone.enabled = read_str(&[&path_string, "/mode"].concat())? == "enabled"; - zone.path = path_string; + let zone = ThermalZone { + temp: read_int(&[&path_string, "/temp"].concat())?, + name: read_str(&[&path_string, "/type"].concat())?, + enabled: read_str(&[&path_string, "/mode"].concat())? == "enabled", + path: path_string, + }; zones.push(zone); }