Repository: uutils/procps
Pull request #361 (2025-03-22 15:00:37)

w: implement idle_time and elapsed time formatting
This is a basic implementation of the display of each users' idle time, as well as a dedicated time formatting function `format_time_elapsed` for this feature, as my first PR to the `uutils` project.

~~The code's logic is largely based on the original source of procps~~ We'll, no, as that is considered license violation. I mean just the logic is similar, but the code is rather another implementation.

Krysztal112233: Nah... Out project licensed under MIT and the member who want to contributing **_CAN'T SEE_** the GPL licensed code:

> Generally, we try to follow what GNU is doing in terms of options and behavior. It is recommended to look at the GNU coreutils manual (on the web, or locally using info <utility>). It is more in depth than the man pages and provides a good description of available features and their implementation details. But remember, you cannot look at the GNU source code!

from our https://github.com/uutils/coreutils/blob/main/CONTRIBUTING.md#writing-code
Krysztal112233: And very thanks for your contributing, but we need to discuss those code will merge into our code base or not

Could you please give us some help?

@sylvestre @cakebaker 
sylvestre: please don't look at the other implementation. Licenses aren't compatible.
However, here, as you didn't copy how the code is done or its structure, I think we are good
aisuneko: > please don't look at the other implementation. Licenses aren't compatible.

Sorry about that. I didn't notice that the licenses are incompatible... I'll pay extra attention to that in future contributions.
(Though IMHO: if we are to "follow what GNU is doing in terms of options and behavior", and in particular, *to pass GNU tests*, then I think looking at the source code is inevitable to some point (that is to better understand how it works/study it's output because we need to follow it's behavior, not to directly copy it from C to Rust)


sylvestre: Looking at test and code are different things.

In general, if you need to look at code, look at the BSD implementation.
for example:
https://github.com/apple-oss-distributions/shell_cmds/blob/main/w/w.c

aisuneko: > Looking at test and code are different things.

Then what is our stance on the tests and the scripts/code that might appear in these tests? E.g. Are we allowed to port and run the tests in our project?

> In general, if you need to look at code, look at the BSD implementation. for example: https://github.com/apple-oss-distributions/shell_cmds/blob/main/w/w.c

Thanks for the explanation.
Krysztal112233: > Then what is our stance on the tests and the scripts/code that might appear in these tests? E.g. Are we allowed to port and run the tests directly in our project?

The test suite will only check that the inputs, outputs and behaviors are as expected, it only provides the usage of util, not the original logic of the util implemented and licensed by GNU and GPL, so it is possible to see the test suite's code
Krysztal112233: And don't forget to fix the CI failures, that's a great job :)
aisuneko: > > Then what is our stance on the tests and the scripts/code that might appear in these tests? E.g. Are we allowed to port and run the tests directly in our project?
> 
> The test suite will only check that the inputs, outputs and behaviors are as expected, it only provides the usage of util, not provide the original logic of the util implemented and licensed by GNU and GPL, so it is possible to check the test suite's code

Thanks for clarifying. I might work toward porting the tests to the rest of the uutils projects (as I'm also interested in contributing to uutils for this year's GSoC), so do let me know if possible license infringements exist.

> And don't forget to fix the CI failures, that's a great job :)

I suppose that's due to my current implementation is for Linux only which causes the Windows and macOS runners to fail. I don't always have Windows or macOS machines available, so suggestions on ways of porting my code to these two platforms are appreciated ;)

Krysztal112233: Hum you can see the logs of failed CI, the logs will provided all the things you need to fix CI failure
Krysztal112233: Cool, the last step you have to do:

```rust
 error: function `fetch_idle_time` is never used
  --> src/uu/w/src/w.rs:98:4
   |
98 | fn fetch_idle_time(_tty: String) -> Result<Duration, std::io::Error> {
   |    ^^^^^^^^^^^^^^^
   |
   = note: `-D dead-code` implied by `-D warnings`
   = help: to override `-D warnings` add `#[allow(dead_code)]`
```

Patch:
diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml
index d1775f1..4ee25a8 100644
--- a/.github/workflows/code-quality.yml
+++ b/.github/workflows/code-quality.yml
@@ -80,7 +80,7 @@ jobs:
           components: clippy
       - uses: Swatinem/rust-cache@v2
       - name: Run sccache-cache
-        uses: mozilla-actions/sccache-action@v0.0.8
+        uses: mozilla-actions/sccache-action@v0.0.9
       - if: ${{ contains(matrix.job.os, 'ubuntu') }}
         run: |
           sudo apt-get update -y
diff --git a/Cargo.lock b/Cargo.lock
index 613f483..66355cc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -11,6 +11,12 @@ dependencies = [
  "memchr",
 ]
 
+[[package]]
+name = "allocator-api2"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
+
 [[package]]
 name = "android-tzdata"
 version = "0.1.1"
@@ -104,6 +110,21 @@ version = "2.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a3c8f83209414aacf0eeae3cf730b18d6981697fba62f200fcfb92b9f082acba"
 
+[[package]]
+name = "cassowary"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
+
+[[package]]
+name = "castaway"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5"
+dependencies = [
+ "rustversion",
+]
+
 [[package]]
 name = "cc"
 version = "1.0.92"
@@ -157,18 +178,18 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.5.32"
+version = "4.5.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6088f3ae8c3608d19260cd7445411865a485688711b78b5be70d78cd96136f83"
+checksum = "e958897981290da2a852763fe9cdb89cd36977a5d729023127095fa94d95e2ff"
 dependencies = [
  "clap_builder",
 ]
 
 [[package]]
 name = "clap_builder"
-version = "4.5.32"
+version = "4.5.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22a7ef7f676155edfb82daa97f99441f3ebf4a58d5e32f295a56259f1b6facc8"
+checksum = "83b0f35019843db2160b5bb19ae09b4e6411ac33fc6a712003c33e03090e2489"
 dependencies = [
  "anstream",
  "anstyle",
@@ -208,6 +229,20 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
 
+[[package]]
+name = "compact_str"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b79c4069c6cad78e2e0cdfcbd26275770669fb39fd308a752dc110e83b9af32"
+dependencies = [
+ "castaway",
+ "cfg-if",
+ "itoa",
+ "rustversion",
+ "ryu",
+ "static_assertions",
+]
+
 [[package]]
 name = "core-foundation-sys"
 version = "0.8.7"
@@ -215,30 +250,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
 
 [[package]]
-name = "crossbeam-deque"
-version = "0.8.5"
+name = "crossterm"
+version = "0.28.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
+checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6"
 dependencies = [
- "crossbeam-epoch",
- "crossbeam-utils",
+ "bitflags",
+ "crossterm_winapi",
+ "mio",
+ "parking_lot",
+ "rustix 0.38.40",
+ "signal-hook",
+ "signal-hook-mio",
+ "winapi",
 ]
 
 [[package]]
-name = "crossbeam-epoch"
-version = "0.9.18"
+name = "crossterm_winapi"
+version = "0.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
+checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
 dependencies = [
- "crossbeam-utils",
+ "winapi",
 ]
 
-[[package]]
-name = "crossbeam-utils"
-version = "0.8.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
-
 [[package]]
 name = "csv"
 version = "1.3.0"
@@ -260,6 +295,41 @@ dependencies = [
  "memchr",
 ]
 
+[[package]]
+name = "darling"
+version = "0.20.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.20.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.20.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
+dependencies = [
+ "darling_core",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "deranged"
 version = "0.3.11"
@@ -320,6 +390,12 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
 
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
 [[package]]
 name = "errno"
 version = "0.3.10"
@@ -336,6 +412,18 @@ version = "2.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6"
 
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "foldhash"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
+
 [[package]]
 name = "getrandom"
 version = "0.2.14"
@@ -365,6 +453,23 @@ version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
 
+[[package]]
+name = "hashbrown"
+version = "0.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
+dependencies = [
+ "allocator-api2",
+ "equivalent",
+ "foldhash",
+]
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
 [[package]]
 name = "hermit-abi"
 version = "0.3.9"
@@ -394,6 +499,32 @@ dependencies = [
  "cc",
 ]
 
+[[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
+[[package]]
+name = "indoc"
+version = "2.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
+
+[[package]]
+name = "instability"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac48900be4ab1c0dd6f1c2553d86ef371eda69c52b97ffd22af3e4f0a1771eb8"
+dependencies = [
+ "darling",
+ "indoc",
+ "pretty_assertions",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "is-terminal"
 version = "0.4.12"
@@ -405,6 +536,15 @@ dependencies = [
  "windows-sys 0.52.0",
 ]
 
+[[package]]
+name = "itertools"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
+dependencies = [
+ "either",
+]
+
 [[package]]
 name = "itoa"
 version = "1.0.11"
@@ -454,18 +594,49 @@ version = "0.9.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6db9c683daf087dc577b7506e9695b3d556a9f3849903fa28186283afd6809e9"
 
+[[package]]
+name = "lock_api"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
 [[package]]
 name = "log"
 version = "0.4.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
 
+[[package]]
+name = "lru"
+version = "0.12.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
+dependencies = [
+ "hashbrown",
+]
+
 [[package]]
 name = "memchr"
 version = "2.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
 
+[[package]]
+name = "mio"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
+dependencies = [
+ "libc",
+ "log",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+ "windows-sys 0.52.0",
+]
+
 [[package]]
 name = "nix"
 version = "0.29.0"
@@ -517,6 +688,15 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
 
+[[package]]
+name = "objc2-core-foundation"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "daeaf60f25471d26948a1c2f840e3f7d86f4109e3af4e8e4b5cd70c39690d925"
+dependencies = [
+ "bitflags",
+]
+
 [[package]]
 name = "once_cell"
 version = "1.19.0"
@@ -529,7 +709,30 @@ version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7a6229bad892b46b0dcfaaeb18ad0d2e56400f5aaea05b768bde96e73676cf75"
 dependencies = [
- "unicode-width 0.1.11",
+ "unicode-width 0.1.14",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-targets 0.52.6",
 ]
 
 [[package]]
@@ -541,6 +744,12 @@ dependencies = [
  "regex",
 ]
 
+[[package]]
+name = "paste"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
+
 [[package]]
 name = "phf"
 version = "0.11.3"
@@ -618,7 +827,7 @@ dependencies = [
  "is-terminal",
  "lazy_static",
  "term",
- "unicode-width 0.1.11",
+ "unicode-width 0.1.14",
 ]
 
 [[package]]
@@ -659,6 +868,7 @@ dependencies = [
  "uu_slabtop",
  "uu_snice",
  "uu_sysctl",
+ "uu_tload",
  "uu_top",
  "uu_w",
  "uu_watch",
@@ -722,23 +932,33 @@ dependencies = [
 ]
 
 [[package]]
-name = "rayon"
-version = "1.10.0"
+name = "ratatui"
+version = "0.29.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
+checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b"
 dependencies = [
- "either",
- "rayon-core",
+ "bitflags",
+ "cassowary",
+ "compact_str",
+ "crossterm",
+ "indoc",
+ "instability",
+ "itertools",
+ "lru",
+ "paste",
+ "strum",
+ "unicode-segmentation",
+ "unicode-truncate",
+ "unicode-width 0.2.0",
 ]
 
 [[package]]
-name = "rayon-core"
-version = "1.12.1"
+name = "redox_syscall"
+version = "0.5.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
+checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1"
 dependencies = [
- "crossbeam-deque",
- "crossbeam-utils",
+ "bitflags",
 ]
 
 [[package]]
@@ -843,6 +1063,12 @@ dependencies = [
  "winapi-util",
 ]
 
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
 [[package]]
 name = "serde"
 version = "1.0.197"
@@ -863,12 +1089,48 @@ dependencies = [
  "syn",
 ]
 
+[[package]]
+name = "signal-hook"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
+dependencies = [
+ "libc",
+ "signal-hook-registry",
+]
+
+[[package]]
+name = "signal-hook-mio"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd"
+dependencies = [
+ "libc",
+ "mio",
+ "signal-hook",
+]
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
+dependencies = [
+ "libc",
+]
+
 [[package]]
 name = "siphasher"
 version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
 
+[[package]]
+name = "smallvec"
+version = "1.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
+
 [[package]]
 name = "smawk"
 version = "0.3.2"
@@ -885,12 +1147,40 @@ dependencies = [
  "windows-sys 0.52.0",
 ]
 
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
 [[package]]
 name = "strsim"
 version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
 
+[[package]]
+name = "strum"
+version = "0.26.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
+dependencies = [
+ "strum_macros",
+]
+
+[[package]]
+name = "strum_macros"
+version = "0.26.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn",
+]
+
 [[package]]
 name = "syn"
 version = "2.0.87"
@@ -904,15 +1194,14 @@ dependencies = [
 
 [[package]]
 name = "sysinfo"
-version = "0.33.1"
+version = "0.34.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fc858248ea01b66f19d8e8a6d55f41deaf91e9d495246fd01368d99935c6c01"
+checksum = "927fa32067cbb22b8a91987d84c0ff94c7441ccf3f767165a58d77a656d6267c"
 dependencies = [
- "core-foundation-sys",
  "libc",
  "memchr",
  "ntapi",
- "rayon",
+ "objc2-core-foundation",
  "windows 0.57.0",
 ]
 
@@ -1047,11 +1336,28 @@ version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f"
 
+[[package]]
+name = "unicode-segmentation"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493"
+
+[[package]]
+name = "unicode-truncate"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf"
+dependencies = [
+ "itertools",
+ "unicode-segmentation",
+ "unicode-width 0.1.14",
+]
+
 [[package]]
 name = "unicode-width"
-version = "0.1.11"
+version = "0.1.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
+checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
 
 [[package]]
 name = "unicode-width"
@@ -1204,6 +1510,16 @@ dependencies = [
  "walkdir",
 ]
 
+[[package]]
+name = "uu_tload"
+version = "0.0.1"
+dependencies = [
+ "clap",
+ "crossterm",
+ "ratatui",
+ "uucore",
+]
+
 [[package]]
 name = "uu_top"
 version = "0.0.1"
diff --git a/Cargo.toml b/Cargo.toml
index af100e5..d3a8ea5 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -30,13 +30,14 @@ feat_common_core = [
     "pgrep",
     "pidof",
     "pidwait",
+    "pkill",
     "pmap",
     "ps",
     "pwdx",
     "slabtop",
     "snice",
-    "pkill",
     "sysctl",
+    "tload",
     "top",
     "w",
     "watch",
@@ -48,14 +49,16 @@ chrono = { version = "0.4.38", default-features = false, features = ["clock"] }
 clap = { version = "4.5.4", features = ["wrap_help", "cargo"] }
 clap_complete = "4.5.2"
 clap_mangen = "0.2.20"
+crossterm = "0.28.1"
 libc = "0.2.154"
 nix = { version = "0.29", default-features = false, features = ["process"] }
 phf = "0.11.2"
 phf_codegen = "0.11.2"
 prettytable-rs = "0.10.0"
 rand = { version = "0.9.0", features = ["small_rng"] }
+ratatui = "0.29.0"
 regex = "1.10.4"
-sysinfo = "0.33.0"
+sysinfo = "0.34.0"
 tempfile = "3.10.1"
 textwrap = { version = "0.16.1", features = ["terminal_size"] }
 thiserror = "2.0.4"
@@ -80,13 +83,14 @@ free = { optional = true, version = "0.0.1", package = "uu_free", path = "src/uu
 pgrep = { optional = true, version = "0.0.1", package = "uu_pgrep", path = "src/uu/pgrep" }
 pidof = { optional = true, version = "0.0.1", package = "uu_pidof", path = "src/uu/pidof" }
 pidwait = { optional = true, version = "0.0.1", package = "uu_pidwait", path = "src/uu/pidwait" }
+pkill = { optional = true, version = "0.0.1", package = "uu_pkill", path = "src/uu/pkill" }
 pmap = { optional = true, version = "0.0.1", package = "uu_pmap", path = "src/uu/pmap" }
 ps = { optional = true, version = "0.0.1", package = "uu_ps", path = "src/uu/ps" }
 pwdx = { optional = true, version = "0.0.1", package = "uu_pwdx", path = "src/uu/pwdx" }
 slabtop = { optional = true, version = "0.0.1", package = "uu_slabtop", path = "src/uu/slabtop" }
 snice = { optional = true, version = "0.0.1", package = "uu_snice", path = "src/uu/snice" }
-pkill = { optional = true, version = "0.0.1", package = "uu_pkill", path = "src/uu/pkill" }
 sysctl = { optional = true, version = "0.0.1", package = "uu_sysctl", path = "src/uu/sysctl" }
+tload = { optional = true, version = "0.0.1", package = "uu_tload", path = "src/uu/tload" }
 top = { optional = true, version = "0.0.1", package = "uu_top", path = "src/uu/top" }
 w = { optional = true, version = "0.0.1", package = "uu_w", path = "src/uu/w" }
 watch = { optional = true, version = "0.0.1", package = "uu_watch", path = "src/uu/watch" }
diff --git a/README.md b/README.md
index 220fcbd..9a33ad2 100644
--- a/README.md
+++ b/README.md
@@ -23,6 +23,7 @@ Ongoing:
 * `slabtop`: Displays detailed kernel slab cache information in real time.
 * `snice`: Changes the scheduling priority of a running process.
 * `sysctl`: Read or write kernel parameters at run-time.
+* `tload`: Prints a graphical representation of system load average to the terminal.
 * `top`: Displays real-time information about system processes.
 * `w`: Shows who is logged on and what they are doing.
 * `watch`: Executes a program periodically, showing output fullscreen.
@@ -30,14 +31,12 @@ Ongoing:
 TODO:
 * `hugetop`: Report hugepage usage of processes and the system as a whole.
 * `skill`: Sends a signal to processes based on criteria like user, terminal, etc.
-* `tload`: Prints a graphical representation of system load average to the terminal.
 * `vmstat`: Reports information about processes, memory, paging, block IO, traps, and CPU activity.
 
 Elsewhere:
 
  * `kill` is already implemented in https://github.com/uutils/coreutils
- * `uptime`: Shows how long the system has been running, including load average.
-   is already implemented in https://github.com/uutils/coreutils
+ * `uptime`: Shows how long the system has been running, including load average. It is already implemented in https://github.com/uutils/coreutils
 
 ## Installation
 
diff --git a/src/uu/pidof/pidof.md b/src/uu/pidof/pidof.md
index 97dd16c..76119f9 100644
--- a/src/uu/pidof/pidof.md
+++ b/src/uu/pidof/pidof.md
@@ -1,7 +1,7 @@
 # pidof
 
 ```
-pidof [-s] [-c] [-n] [-x] [-z] [-o omitpid[,omitpid...]]  [-o omitpid[,omitpid...]...]  [-d sep] program [program...]
+pidof [options] [program [...]]
 ```
 
 Find the process ID of a running program
diff --git a/src/uu/pidof/src/pidof.rs b/src/uu/pidof/src/pidof.rs
index c9ecade..6515298 100644
--- a/src/uu/pidof/src/pidof.rs
+++ b/src/uu/pidof/src/pidof.rs
@@ -45,20 +45,22 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
     Ok(())
 }
 
-fn get_executable_name(process: &mut ProcessInformation) -> String {
+fn match_process_name(
+    process: &mut ProcessInformation,
+    name_to_match: &str,
+    with_workers: bool,
+) -> bool {
     let binding = process.cmdline.split(' ').collect::<Vec<_>>();
     let mut path = binding.first().unwrap().to_string();
 
     if path.is_empty() {
+        if !with_workers {
+            return false;
+        }
         path.clone_from(&process.status()["Name"]);
     };
 
-    PathBuf::from(path)
-        .file_name()
-        .unwrap()
-        .to_str()
-        .unwrap()
-        .to_string()
+    PathBuf::from(path).file_name().unwrap().to_str().unwrap() == name_to_match
 }
 
 fn collect_matched_pids(matches: &ArgMatches) -> Vec<usize> {
@@ -67,6 +69,7 @@ fn collect_matched_pids(matches: &ArgMatches) -> Vec<usize> {
         .unwrap()
         .cloned()
         .collect();
+    let with_workers = matches.get_flag("with-workers");
 
     let collected = walk_process().collect::<Vec<_>>();
     let arg_omit_pid = matches
@@ -80,7 +83,7 @@ fn collect_matched_pids(matches: &ArgMatches) -> Vec<usize> {
         .flat_map(|program| {
             let mut processed = Vec::new();
             for mut process in collected.clone() {
-                let contains = program == get_executable_name(&mut process);
+                let contains = match_process_name(&mut process, &program, with_workers);
                 let should_omit = arg_omit_pid.contains(&process.pid);
 
                 if contains && !should_omit {
@@ -174,6 +177,13 @@ pub fn uu_app() -> Command {
                 .help("Show thread ids instead of process ids")
                 .action(ArgAction::SetTrue),
         )
+        .arg(
+            Arg::new("with-workers")
+                .short('w')
+                .long("with-workers")
+                .help("Show kernel worker threads as well")
+                .action(ArgAction::SetTrue),
+        )
     // .arg(
     //     Arg::new("x")
     //         .short('x')
diff --git a/src/uu/pmap/src/maps_format_parser.rs b/src/uu/pmap/src/maps_format_parser.rs
index aee8d64..273f208 100644
--- a/src/uu/pmap/src/maps_format_parser.rs
+++ b/src/uu/pmap/src/maps_format_parser.rs
@@ -6,20 +6,20 @@
 use std::fmt;
 use std::io::{Error, ErrorKind};
 
-// Represents a parsed single line from /proc/<PID>/maps for the default and device formats. It
-// omits the inode information because it's not used by those formats.
-#[derive(Debug, PartialEq)]
+// Represents a parsed single line from /proc/<PID>/maps.
+#[derive(Debug, Clone, Default, PartialEq)]
 pub struct MapLine {
     pub address: String,
     pub size_in_kb: u64,
     pub perms: Perms,
     pub offset: String,
     pub device: String,
+    pub inode: u64,
     pub mapping: String,
 }
 
 // Represents a set of permissions from the "perms" column of /proc/<PID>/maps.
-#[derive(Clone, Copy, Debug, PartialEq)]
+#[derive(Clone, Copy, Debug, Default, PartialEq)]
 pub struct Perms {
     pub readable: bool,
     pub writable: bool,
@@ -84,8 +84,12 @@ pub fn parse_map_line(line: &str) -> Result<MapLine, Error> {
         .ok_or_else(|| Error::from(ErrorKind::InvalidData))?;
     let device = parse_device(device)?;
 
-    // skip the "inode" column
-    let mapping: String = rest.splitn(2, ' ').skip(1).collect();
+    let (inode, mapping) = rest
+        .split_once(' ')
+        .ok_or_else(|| Error::from(ErrorKind::InvalidData))?;
+    let inode = inode
+        .parse::<u64>()
+        .map_err(|_| Error::from(ErrorKind::InvalidData))?;
     let mapping = mapping.trim_ascii_start();
     let mapping = parse_mapping(mapping);
 
@@ -95,6 +99,7 @@ pub fn parse_map_line(line: &str) -> Result<MapLine, Error> {
         perms,
         offset,
         device,
+        inode,
         mapping,
     })
 }
@@ -146,6 +151,7 @@ mod test {
         perms: Perms,
         offset: &str,
         device: &str,
+        inode: u64,
         mapping: &str,
     ) -> MapLine {
         MapLine {
@@ -154,6 +160,7 @@ mod test {
             perms,
             offset: offset.to_string(),
             device: device.to_string(),
+            inode,
             mapping: mapping.to_string(),
         }
     }
@@ -169,31 +176,31 @@ mod test {
     fn test_parse_map_line() {
         let data = [
             (
-                create_map_line("000062442eb9e000", 16, Perms::from("r--p"), "0000000000000000", "008:00008", "konsole"),
+                create_map_line("000062442eb9e000", 16, Perms::from("r--p"), "0000000000000000", "008:00008", 10813151, "konsole"),
                 "62442eb9e000-62442eba2000 r--p 00000000 08:08 10813151                   /usr/bin/konsole"
             ),
             (
-                create_map_line("000071af50000000", 132, Perms::from("rw-p"), "0000000000000000", "000:00000", "  [ anon ]"),
+                create_map_line("000071af50000000", 132, Perms::from("rw-p"), "0000000000000000", "000:00000", 0, "  [ anon ]"),
                 "71af50000000-71af50021000 rw-p 00000000 00:00 0 "
             ),
             (
-                create_map_line("00007ffc3f8df000", 132, Perms::from("rw-p"), "0000000000000000", "000:00000", "  [ stack ]"),
+                create_map_line("00007ffc3f8df000", 132, Perms::from("rw-p"), "0000000000000000", "000:00000", 0, "  [ stack ]"),
                 "7ffc3f8df000-7ffc3f900000 rw-p 00000000 00:00 0                          [stack]"
             ),
             (
-                create_map_line("000071af8c9e6000", 16, Perms::from("rw-s"), "0000000105830000", "000:00010", "  [ anon ]"),
+                create_map_line("000071af8c9e6000", 16, Perms::from("rw-s"), "0000000105830000", "000:00010", 1075, "  [ anon ]"),
                 "71af8c9e6000-71af8c9ea000 rw-s 105830000 00:10 1075                      anon_inode:i915.gem"
             ),
             (
-                create_map_line("000071af6cf0c000", 3560, Perms::from("rw-s"), "0000000000000000", "000:00001", "memfd:wayland-shm (deleted)"),
+                create_map_line("000071af6cf0c000", 3560, Perms::from("rw-s"), "0000000000000000", "000:00001", 256481, "memfd:wayland-shm (deleted)"),
                 "71af6cf0c000-71af6d286000 rw-s 00000000 00:01 256481                     /memfd:wayland-shm (deleted)"
             ),
             (
-                create_map_line("ffffffffff600000", 4, Perms::from("--xp"), "0000000000000000", "000:00000", "  [ anon ]"),
+                create_map_line("ffffffffff600000", 4, Perms::from("--xp"), "0000000000000000", "000:00000", 0, "  [ anon ]"),
                 "ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]"
             ),
             (
-                create_map_line("00005e8187da8000", 24, Perms::from("r--p"), "0000000000000000", "008:00008", "hello   world"),
+                create_map_line("00005e8187da8000", 24, Perms::from("r--p"), "0000000000000000", "008:00008", 9524160, "hello   world"),
                 "5e8187da8000-5e8187dae000 r--p 00000000 08:08 9524160                    /usr/bin/hello   world"
             ),
         ];
diff --git a/src/uu/pmap/src/pmap.rs b/src/uu/pmap/src/pmap.rs
index baa24fc..cc5443c 100644
--- a/src/uu/pmap/src/pmap.rs
+++ b/src/uu/pmap/src/pmap.rs
@@ -5,6 +5,7 @@
 
 use clap::{crate_version, Arg, ArgAction, Command};
 use maps_format_parser::{parse_map_line, MapLine};
+use smaps_format_parser::{parse_smap_entries, SmapEntry};
 use std::env;
 use std::fs;
 use std::io::Error;
@@ -12,6 +13,7 @@ use uucore::error::{set_exit_code, UResult};
 use uucore::{format_usage, help_about, help_usage};
 
 mod maps_format_parser;
+mod smaps_format_parser;
 
 const ABOUT: &str = help_about!("pmap.md");
 const USAGE: &str = help_usage!("pmap.md");
@@ -49,7 +51,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
             }
         }
 
-        if matches.get_flag(options::DEVICE) {
+        if matches.get_flag(options::EXTENDED) {
+            output_extended_format(pid)
+                .map_err(|_| set_exit_code(1))
+                .ok();
+        } else if matches.get_flag(options::DEVICE) {
             output_device_format(pid).map_err(|_| set_exit_code(1)).ok();
         } else {
             output_default_format(pid)
@@ -90,6 +96,21 @@ where
     Ok(())
 }
 
+fn process_smaps<F>(pid: &str, mut process_entry: F) -> Result<(), Error>
+where
+    F: FnMut(&SmapEntry),
+{
+    let path = format!("/proc/{pid}/smaps");
+    let contents = fs::read_to_string(path)?;
+    let smap_entries = parse_smap_entries(&contents)?;
+
+    for entry in smap_entries {
+        process_entry(&entry);
+    }
+
+    Ok(())
+}
+
 fn output_default_format(pid: &str) -> Result<(), Error> {
     let mut total = 0;
 
@@ -106,6 +127,34 @@ fn output_default_format(pid: &str) -> Result<(), Error> {
     Ok(())
 }
 
+fn output_extended_format(pid: &str) -> Result<(), Error> {
+    let mut total_mapped = 0;
+    let mut total_rss = 0;
+    let mut total_dirty = 0;
+
+    println!("Address           Kbytes     RSS   Dirty Mode  Mapping");
+
+    process_smaps(pid, |smap_entry| {
+        println!(
+            "{} {:>7} {:>7} {:>7} {} {}",
+            smap_entry.map_line.address,
+            smap_entry.map_line.size_in_kb,
+            smap_entry.rss_in_kb,
+            smap_entry.shared_dirty_in_kb + smap_entry.private_dirty_in_kb,
+            smap_entry.map_line.perms,
+            smap_entry.map_line.mapping
+        );
+        total_mapped += smap_entry.map_line.size_in_kb;
+        total_rss += smap_entry.rss_in_kb;
+        total_dirty += smap_entry.shared_dirty_in_kb + smap_entry.private_dirty_in_kb;
+    })?;
+
+    println!("---------------- ------- ------- ------- ");
+    println!("total kB         {total_mapped:>7} {total_rss:>7} {total_dirty:>7}");
+
+    Ok(())
+}
+
 fn output_device_format(pid: &str) -> Result<(), Error> {
     let mut total_mapped = 0;
     let mut total_writeable_private = 0;
diff --git a/src/uu/pmap/src/smaps_format_parser.rs b/src/uu/pmap/src/smaps_format_parser.rs
new file mode 100644
index 0000000..ae8e6ea
--- /dev/null
+++ b/src/uu/pmap/src/smaps_format_parser.rs
@@ -0,0 +1,553 @@
+// This file is part of the uutils procps package.
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+use crate::maps_format_parser::{parse_map_line, MapLine};
+use std::io::{Error, ErrorKind};
+
+// Represents a parsed single entry from /proc/<PID>/smaps for the extended formats.
+#[derive(Debug, Clone, Default, PartialEq)]
+pub struct SmapEntry {
+    pub map_line: MapLine,
+    pub kernel_page_size_in_kb: u64,
+    pub mmu_page_size_in_kb: u64,
+    pub rss_in_kb: u64,
+    pub pss_in_kb: u64,
+    pub pss_dirty_in_kb: u64,
+    pub shared_clean_in_kb: u64,
+    pub shared_dirty_in_kb: u64,
+    pub private_clean_in_kb: u64,
+    pub private_dirty_in_kb: u64,
+    pub referenced_in_kb: u64,
+    pub anonymous_in_kb: u64,
+    pub ksm_in_kb: u64,
+    pub lazy_free_in_kb: u64,
+    pub anon_huge_pages_in_kb: u64,
+    pub shmem_pmd_mapped_in_kb: u64,
+    pub file_pmd_mapped_in_kb: u64,
+    pub shared_hugetlb_in_kb: u64,
+    pub private_hugetlb_in_kb: u64,
+    pub swap_in_kb: u64,
+    pub swap_pss_in_kb: u64,
+    pub locked_in_kb: u64,
+    pub thp_eligible: u64,
+    pub vmflags: String,
+}
+
+// Parses entries from /proc/<PID>/smaps. See
+// https://www.kernel.org/doc/html/latest/filesystems/proc.html for details about the expected
+// format.
+//
+// # Errors
+//
+// Will return an `Error` if the format is incorrect.
+pub fn parse_smap_entries(contents: &str) -> Result<Vec<SmapEntry>, Error> {
+    let mut smap_entries = Vec::new();
+    let mut smap_entry = SmapEntry::default();
+
+    for (i, line) in contents.lines().enumerate() {
+        let map_line = parse_map_line(line);
+        if let Ok(map_line) = map_line {
+            if i > 0 {
+                smap_entries.push(smap_entry.clone());
+                smap_entry = SmapEntry::default();
+            }
+            smap_entry.map_line = map_line;
+        } else {
+            let (key, val) = line
+                .split_once(':')
+                .ok_or_else(|| Error::from(ErrorKind::InvalidData))?;
+            let val = val.trim();
+
+            if key == "VmFlags" {
+                smap_entry.vmflags = val.into();
+            } else {
+                let val = val.strip_suffix(" kB").unwrap_or(val);
+                let val = get_smap_item_value(val)?;
+                match key {
+                    "Size" => {
+                        if smap_entry.map_line.size_in_kb != val {
+                            return Err(Error::from(ErrorKind::InvalidData));
+                        }
+                    }
+                    "KernelPageSize" => smap_entry.kernel_page_size_in_kb = val,
+                    "MMUPageSize" => smap_entry.mmu_page_size_in_kb = val,
+                    "Rss" => smap_entry.rss_in_kb = val,
+                    "Pss" => smap_entry.pss_in_kb = val,
+                    "Pss_Dirty" => smap_entry.pss_dirty_in_kb = val,
+                    "Shared_Clean" => smap_entry.shared_clean_in_kb = val,
+                    "Shared_Dirty" => smap_entry.shared_dirty_in_kb = val,
+                    "Private_Clean" => smap_entry.private_clean_in_kb = val,
+                    "Private_Dirty" => smap_entry.private_dirty_in_kb = val,
+                    "Referenced" => smap_entry.referenced_in_kb = val,
+                    "Anonymous" => smap_entry.anonymous_in_kb = val,
+                    "KSM" => smap_entry.ksm_in_kb = val,
+                    "LazyFree" => smap_entry.lazy_free_in_kb = val,
+                    "AnonHugePages" => smap_entry.anon_huge_pages_in_kb = val,
+                    "ShmemPmdMapped" => smap_entry.shmem_pmd_mapped_in_kb = val,
+                    "FilePmdMapped" => smap_entry.file_pmd_mapped_in_kb = val,
+                    "Shared_Hugetlb" => smap_entry.shared_hugetlb_in_kb = val,
+                    "Private_Hugetlb" => smap_entry.private_hugetlb_in_kb = val,
+                    "Swap" => smap_entry.swap_in_kb = val,
+                    "SwapPss" => smap_entry.swap_pss_in_kb = val,
+                    "Locked" => smap_entry.locked_in_kb = val,
+                    "THPeligible" => smap_entry.thp_eligible = val,
+                    _ => (),
+                }
+            }
+        }
+    }
+
+    if !contents.is_empty() {
+        smap_entries.push(smap_entry);
+    }
+
+    Ok(smap_entries)
+}
+
+fn get_smap_item_value(val: &str) -> Result<u64, Error> {
+    val.parse::<u64>()
+        .map_err(|_| Error::from(ErrorKind::InvalidData))
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use crate::maps_format_parser::Perms;
+
+    fn create_smap_entry(
+        address: &str,
+        perms: Perms,
+        offset: &str,
+        device: &str,
+        inode: u64,
+        mapping: &str,
+        size_in_kb: u64,
+        kernel_page_size_in_kb: u64,
+        mmu_page_size_in_kb: u64,
+        rss_in_kb: u64,
+        pss_in_kb: u64,
+        pss_dirty_in_kb: u64,
+        shared_clean_in_kb: u64,
+        shared_dirty_in_kb: u64,
+        private_clean_in_kb: u64,
+        private_dirty_in_kb: u64,
+        referenced_in_kb: u64,
+        anonymous_in_kb: u64,
+        ksm_in_kb: u64,
+        lazy_free_in_kb: u64,
+        anon_huge_pages_in_kb: u64,
+        shmem_pmd_mapped_in_kb: u64,
+        file_pmd_mapped_in_kb: u64,
+        shared_hugetlb_in_kb: u64,
+        private_hugetlb_in_kb: u64,
+        swap_in_kb: u64,
+        swap_pss_in_kb: u64,
+        locked_in_kb: u64,
+        thp_eligible: u64,
+        vmflags: &str,
+    ) -> SmapEntry {
+        SmapEntry {
+            map_line: MapLine {
+                address: address.to_string(),
+                size_in_kb,
+                perms,
+                offset: offset.to_string(),
+                device: device.to_string(),
+                inode,
+                mapping: mapping.to_string(),
+            },
+            kernel_page_size_in_kb,
+            mmu_page_size_in_kb,
+            rss_in_kb,
+            pss_in_kb,
+            pss_dirty_in_kb,
+            shared_clean_in_kb,
+            shared_dirty_in_kb,
+            private_clean_in_kb,
+            private_dirty_in_kb,
+            referenced_in_kb,
+            anonymous_in_kb,
+            ksm_in_kb,
+            lazy_free_in_kb,
+            anon_huge_pages_in_kb,
+            shmem_pmd_mapped_in_kb,
+            file_pmd_mapped_in_kb,
+            shared_hugetlb_in_kb,
+            private_hugetlb_in_kb,
+            swap_in_kb,
+            swap_pss_in_kb,
+            locked_in_kb,
+            thp_eligible,
+            vmflags: vmflags.to_string(),
+        }
+    }
+
+    #[test]
+    fn test_parse_smap_entries() {
+        let data = [
+            (
+                vec![create_smap_entry(
+                    "0000560880413000", Perms::from("r--p"), "0000000000000000", "008:00008", 10813151, "konsole",
+                    180, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+                    22, "rd mr mw me dw sd")],
+                concat!(
+                    "560880413000-560880440000 r--p 00000000 08:08 10813151                   /usr/bin/konsole\n",
+                    "Size:                180 kB\n",
+                    "KernelPageSize:        1 kB\n",
+                    "MMUPageSize:           2 kB\n",
+                    "Rss:                   3 kB\n",
+                    "Pss:                   4 kB\n",
+                    "Pss_Dirty:             5 kB\n",
+                    "Shared_Clean:          6 kB\n",
+                    "Shared_Dirty:          7 kB\n",
+                    "Private_Clean:         8 kB\n",
+                    "Private_Dirty:         9 kB\n",
+                    "Referenced:           10 kB\n",
+                    "Anonymous:            11 kB\n",
+                    "KSM:                  12 kB\n",
+                    "LazyFree:             13 kB\n",
+                    "AnonHugePages:        14 kB\n",
+                    "ShmemPmdMapped:       15 kB\n",
+                    "FilePmdMapped:        16 kB\n",
+                    "Shared_Hugetlb:       17 kB\n",
+                    "Private_Hugetlb:      18 kB\n",
+                    "Swap:                 19 kB\n",
+                    "SwapPss:              20 kB\n",
+                    "Locked:               21 kB\n",
+                    "THPeligible:           22\n",
+                    "SomeUnknownFieldKB:   23 kB\n",
+                    "SomeUnknownField:      24\n",
+                    "VmFlags: rd mr mw me dw sd \n")
+            ),
+            (
+                vec![create_smap_entry(
+                    "000071af50000000", Perms::from("rw-p"), "0000000000000000", "000:00000", 0, "  [ anon ]",
+                    132, 4, 4, 128, 9, 9, 128, 0, 0, 0, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                    0, "rd mr mw me sd")],
+                concat!(
+                    "71af50000000-71af50021000 rw-p 00000000 00:00 0 \n",
+                    "Size:                132 kB\n",
+                    "KernelPageSize:        4 kB\n",
+                    "MMUPageSize:           4 kB\n",
+                    "Rss:                 128 kB\n",
+                    "Pss:                   9 kB\n",
+                    "Pss_Dirty:             9 kB\n",
+                    "Shared_Clean:        128 kB\n",
+                    "Shared_Dirty:          0 kB\n",
+                    "Private_Clean:         0 kB\n",
+                    "Private_Dirty:         0 kB\n",
+                    "Referenced:          128 kB\n",
+                    "Anonymous:             0 kB\n",
+                    "KSM:                   0 kB\n",
+                    "LazyFree:              0 kB\n",
+                    "AnonHugePages:         0 kB\n",
+                    "ShmemPmdMapped:        0 kB\n",
+                    "FilePmdMapped:         0 kB\n",
+                    "Shared_Hugetlb:        0 kB\n",
+                    "Private_Hugetlb:       0 kB\n",
+                    "Swap:                  0 kB\n",
+                    "SwapPss:               0 kB\n",
+                    "Locked:                0 kB\n",
+                    "THPeligible:            0\n",
+                    "VmFlags: rd mr mw me sd \n")
+            ),
+            (
+                vec![create_smap_entry(
+                    "00007ffc3f8df000", Perms::from("rw-p"), "0000000000000000", "000:00000", 0, "  [ stack ]",
+                    132, 4, 4, 108, 108, 108, 0, 0, 0, 108, 108, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                    0, "rd wr mr mw me gd ac")],
+                concat!(
+                    "7ffc3f8df000-7ffc3f900000 rw-p 00000000 00:00 0                          [stack]\n",
+                    "Size:                132 kB\n",
+                    "KernelPageSize:        4 kB\n",
+                    "MMUPageSize:           4 kB\n",
+                    "Rss:                 108 kB\n",
+                    "Pss:                 108 kB\n",
+                    "Pss_Dirty:           108 kB\n",
+                    "Shared_Clean:          0 kB\n",
+                    "Shared_Dirty:          0 kB\n",
+                    "Private_Clean:         0 kB\n",
+                    "Private_Dirty:       108 kB\n",
+                    "Referenced:          108 kB\n",
+                    "Anonymous:           108 kB\n",
+                    "KSM:                   0 kB\n",
+                    "LazyFree:              0 kB\n",
+                    "AnonHugePages:         0 kB\n",
+                    "ShmemPmdMapped:        0 kB\n",
+                    "FilePmdMapped:         0 kB\n",
+                    "Shared_Hugetlb:        0 kB\n",
+                    "Private_Hugetlb:       0 kB\n",
+                    "Swap:                  0 kB\n",
+                    "SwapPss:               0 kB\n",
+                    "Locked:                0 kB\n",
+                    "THPeligible:            0\n",
+                    "VmFlags: rd wr mr mw me gd ac\n")
+            ),
+            (
+                vec![create_smap_entry(
+                    "000071af8c9e6000", Perms::from("rw-s"), "0000000105830000", "000:00010", 1075, "  [ anon ]",
+                    16, 4, 4, 16, 16, 16, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                    0, "rd wr mr mw me ac sd")],
+                concat!(
+                    "71af8c9e6000-71af8c9ea000 rw-s 105830000 00:10 1075                      anon_inode:i915.gem\n",
+                    "Size:                 16 kB\n",
+                    "KernelPageSize:        4 kB\n",
+                    "MMUPageSize:           4 kB\n",
+                    "Rss:                  16 kB\n",
+                    "Pss:                  16 kB\n",
+                    "Pss_Dirty:            16 kB\n",
+                    "Shared_Clean:          0 kB\n",
+                    "Shared_Dirty:          0 kB\n",
+                    "Private_Clean:         0 kB\n",
+                    "Private_Dirty:        16 kB\n",
+                    "Referenced:           16 kB\n",
+                    "Anonymous:            16 kB\n",
+                    "KSM:                   0 kB\n",
+                    "LazyFree:              0 kB\n",
+                    "AnonHugePages:         0 kB\n",
+                    "ShmemPmdMapped:        0 kB\n",
+                    "FilePmdMapped:         0 kB\n",
+                    "Shared_Hugetlb:        0 kB\n",
+                    "Private_Hugetlb:       0 kB\n",
+                    "Swap:                  0 kB\n",
+                    "SwapPss:               0 kB\n",
+                    "Locked:                0 kB\n",
+                    "THPeligible:            0\n",
+                    "VmFlags: rd wr mr mw me ac sd\n")
+            ),
+            (
+                vec![create_smap_entry(
+                    "000071af6cf0c000", Perms::from("rw-s"), "0000000000000000", "000:00001", 256481, "memfd:wayland-shm (deleted)",
+                    3560, 4, 4, 532, 108, 0, 524, 0, 8, 0, 532, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                    0, "rd mr mw me sd")],
+                concat!(
+                    "71af6cf0c000-71af6d286000 rw-s 00000000 00:01 256481                     /memfd:wayland-shm (deleted)\n",
+                    "Size:               3560 kB\n",
+                    "KernelPageSize:        4 kB\n",
+                    "MMUPageSize:           4 kB\n",
+                    "Rss:                 532 kB\n",
+                    "Pss:                 108 kB\n",
+                    "Pss_Dirty:             0 kB\n",
+                    "Shared_Clean:        524 kB\n",
+                    "Shared_Dirty:          0 kB\n",
+                    "Private_Clean:         8 kB\n",
+                    "Private_Dirty:         0 kB\n",
+                    "Referenced:          532 kB\n",
+                    "Anonymous:             0 kB\n",
+                    "KSM:                   0 kB\n",
+                    "LazyFree:              0 kB\n",
+                    "AnonHugePages:         0 kB\n",
+                    "ShmemPmdMapped:        0 kB\n",
+                    "FilePmdMapped:         0 kB\n",
+                    "Shared_Hugetlb:        0 kB\n",
+                    "Private_Hugetlb:       0 kB\n",
+                    "Swap:                  0 kB\n",
+                    "SwapPss:               0 kB\n",
+                    "Locked:                0 kB\n",
+                    "THPeligible:            0\n",
+                    "VmFlags: rd mr mw me sd \n")
+            ),
+            (
+                vec![create_smap_entry(
+                    "ffffffffff600000", Perms::from("--xp"), "0000000000000000", "000:00000", 0, "  [ anon ]",
+                    4, 4, 4, 4, 4, 4, 0, 0, 0, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                    0, "rd wr mr mw me ac sd")],
+                concat!(
+                    "ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]\n",
+                    "Size:                  4 kB\n",
+                    "KernelPageSize:        4 kB\n",
+                    "MMUPageSize:           4 kB\n",
+                    "Rss:                   4 kB\n",
+                    "Pss:                   4 kB\n",
+                    "Pss_Dirty:             4 kB\n",
+                    "Shared_Clean:          0 kB\n",
+                    "Shared_Dirty:          0 kB\n",
+                    "Private_Clean:         0 kB\n",
+                    "Private_Dirty:         4 kB\n",
+                    "Referenced:            4 kB\n",
+                    "Anonymous:             4 kB\n",
+                    "KSM:                   0 kB\n",
+                    "LazyFree:              0 kB\n",
+                    "AnonHugePages:         0 kB\n",
+                    "ShmemPmdMapped:        0 kB\n",
+                    "FilePmdMapped:         0 kB\n",
+                    "Shared_Hugetlb:        0 kB\n",
+                    "Private_Hugetlb:       0 kB\n",
+                    "Swap:                  0 kB\n",
+                    "SwapPss:               0 kB\n",
+                    "Locked:                0 kB\n",
+                    "THPeligible:            0\n",
+                    "VmFlags: rd wr mr mw me ac sd\n")
+            ),
+            (
+                vec![create_smap_entry(
+                    "00005e8187da8000", Perms::from("r--p"), "0000000000000000", "008:00008", 9524160, "hello   world",
+                    24, 4, 4, 24, 0, 0, 24, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                    0, "rd ex mr mw me sd")],
+                concat!(
+                    "5e8187da8000-5e8187dae000 r--p 00000000 08:08 9524160                    /usr/bin/hello   world\n",
+                    "Size:                 24 kB\n",
+                    "KernelPageSize:        4 kB\n",
+                    "MMUPageSize:           4 kB\n",
+                    "Rss:                  24 kB\n",
+                    "Pss:                   0 kB\n",
+                    "Pss_Dirty:             0 kB\n",
+                    "Shared_Clean:         24 kB\n",
+                    "Shared_Dirty:          0 kB\n",
+                    "Private_Clean:         0 kB\n",
+                    "Private_Dirty:         0 kB\n",
+                    "Referenced:           24 kB\n",
+                    "Anonymous:             0 kB\n",
+                    "KSM:                   0 kB\n",
+                    "LazyFree:              0 kB\n",
+                    "AnonHugePages:         0 kB\n",
+                    "ShmemPmdMapped:        0 kB\n",
+                    "FilePmdMapped:         0 kB\n",
+                    "Shared_Hugetlb:        0 kB\n",
+                    "Private_Hugetlb:       0 kB\n",
+                    "Swap:                  0 kB\n",
+                    "SwapPss:               0 kB\n",
+                    "Locked:                0 kB\n",
+                    "THPeligible:            0\n",
+                    "VmFlags: rd ex mr mw me sd\n")
+            ),
+            (
+                vec![
+                    create_smap_entry(
+                        "000071af8c9e6000", Perms::from("rw-s"), "0000000105830000", "000:00010", 1075, "  [ anon ]",
+                        16, 4, 4, 16, 16, 16, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                        0, "rd wr mr mw me ac sd"),
+                    create_smap_entry(
+                        "000071af6cf0c000", Perms::from("rw-s"), "0000000000000000", "000:00001", 256481, "memfd:wayland-shm (deleted)",
+                        3560, 4, 4, 532, 108, 0, 524, 0, 8, 0, 532, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                        0, "rd mr mw me sd"),
+                ],
+                concat!(
+                    "71af8c9e6000-71af8c9ea000 rw-s 105830000 00:10 1075                      anon_inode:i915.gem\n",
+                    "Size:                 16 kB\n",
+                    "KernelPageSize:        4 kB\n",
+                    "MMUPageSize:           4 kB\n",
+                    "Rss:                  16 kB\n",
+                    "Pss:                  16 kB\n",
+                    "Pss_Dirty:            16 kB\n",
+                    "Shared_Clean:          0 kB\n",
+                    "Shared_Dirty:          0 kB\n",
+                    "Private_Clean:         0 kB\n",
+                    "Private_Dirty:        16 kB\n",
+                    "Referenced:           16 kB\n",
+                    "Anonymous:            16 kB\n",
+                    "KSM:                   0 kB\n",
+                    "LazyFree:              0 kB\n",
+                    "AnonHugePages:         0 kB\n",
+                    "ShmemPmdMapped:        0 kB\n",
+                    "FilePmdMapped:         0 kB\n",
+                    "Shared_Hugetlb:        0 kB\n",
+                    "Private_Hugetlb:       0 kB\n",
+                    "Swap:                  0 kB\n",
+                    "SwapPss:               0 kB\n",
+                    "Locked:                0 kB\n",
+                    "THPeligible:            0\n",
+                    "VmFlags: rd wr mr mw me ac sd\n",
+                    "71af6cf0c000-71af6d286000 rw-s 00000000 00:01 256481                     /memfd:wayland-shm (deleted)\n",
+                    "Size:               3560 kB\n",
+                    "KernelPageSize:        4 kB\n",
+                    "MMUPageSize:           4 kB\n",
+                    "Rss:                 532 kB\n",
+                    "Pss:                 108 kB\n",
+                    "Pss_Dirty:             0 kB\n",
+                    "Shared_Clean:        524 kB\n",
+                    "Shared_Dirty:          0 kB\n",
+                    "Private_Clean:         8 kB\n",
+                    "Private_Dirty:         0 kB\n",
+                    "Referenced:          532 kB\n",
+                    "Anonymous:             0 kB\n",
+                    "KSM:                   0 kB\n",
+                    "LazyFree:              0 kB\n",
+                    "AnonHugePages:         0 kB\n",
+                    "ShmemPmdMapped:        0 kB\n",
+                    "FilePmdMapped:         0 kB\n",
+                    "Shared_Hugetlb:        0 kB\n",
+                    "Private_Hugetlb:       0 kB\n",
+                    "Swap:                  0 kB\n",
+                    "SwapPss:               0 kB\n",
+                    "Locked:                0 kB\n",
+                    "THPeligible:            0\n",
+                    "VmFlags: rd mr mw me sd \n")
+            ),
+            (
+                vec![
+                    create_smap_entry(
+                        "000071af8c9e6000", Perms::from("rw-s"), "0000000105830000", "000:00010", 1075, "  [ anon ]",
+                        16, 4, 4, 16, 16, 16, 0, 0, 0, 16, 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                        0, "rd wr mr mw me ac sd"),
+                    create_smap_entry(
+                        "0000560880413000", Perms::from("r--p"), "0000000000000000", "008:00008", 10813151, "konsole",
+                        180, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                        0, ""),
+                    create_smap_entry(
+                        "000071af6cf0c000", Perms::from("rw-s"), "0000000000000000", "000:00001", 256481, "memfd:wayland-shm (deleted)",
+                        3560, 4, 4, 532, 108, 0, 524, 0, 8, 0, 532, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                        0, "rd mr mw me sd"),
+                ],
+                concat!(
+                    "71af8c9e6000-71af8c9ea000 rw-s 105830000 00:10 1075                      anon_inode:i915.gem\n",
+                    "Size:                 16 kB\n",
+                    "KernelPageSize:        4 kB\n",
+                    "MMUPageSize:           4 kB\n",
+                    "Rss:                  16 kB\n",
+                    "Pss:                  16 kB\n",
+                    "Pss_Dirty:            16 kB\n",
+                    "Shared_Clean:          0 kB\n",
+                    "Shared_Dirty:          0 kB\n",
+                    "Private_Clean:         0 kB\n",
+                    "Private_Dirty:        16 kB\n",
+                    "Referenced:           16 kB\n",
+                    "Anonymous:            16 kB\n",
+                    "KSM:                   0 kB\n",
+                    "LazyFree:              0 kB\n",
+                    "AnonHugePages:         0 kB\n",
+                    "ShmemPmdMapped:        0 kB\n",
+                    "FilePmdMapped:         0 kB\n",
+                    "Shared_Hugetlb:        0 kB\n",
+                    "Private_Hugetlb:       0 kB\n",
+                    "Swap:                  0 kB\n",
+                    "SwapPss:               0 kB\n",
+                    "Locked:                0 kB\n",
+                    "THPeligible:            0\n",
+                    "VmFlags: rd wr mr mw me ac sd\n",
+                    "560880413000-560880440000 r--p 00000000 08:08 10813151                   /usr/bin/konsole\n",
+                    "71af6cf0c000-71af6d286000 rw-s 00000000 00:01 256481                     /memfd:wayland-shm (deleted)\n",
+                    "Size:               3560 kB\n",
+                    "KernelPageSize:        4 kB\n",
+                    "MMUPageSize:           4 kB\n",
+                    "Rss:                 532 kB\n",
+                    "Pss:                 108 kB\n",
+                    "Pss_Dirty:             0 kB\n",
+                    "Shared_Clean:        524 kB\n",
+                    "Shared_Dirty:          0 kB\n",
+                    "Private_Clean:         8 kB\n",
+                    "Private_Dirty:         0 kB\n",
+                    "Referenced:          532 kB\n",
+                    "Anonymous:             0 kB\n",
+                    "KSM:                   0 kB\n",
+                    "LazyFree:              0 kB\n",
+                    "AnonHugePages:         0 kB\n",
+                    "ShmemPmdMapped:        0 kB\n",
+                    "FilePmdMapped:         0 kB\n",
+                    "Shared_Hugetlb:        0 kB\n",
+                    "Private_Hugetlb:       0 kB\n",
+                    "Swap:                  0 kB\n",
+                    "SwapPss:               0 kB\n",
+                    "Locked:                0 kB\n",
+                    "THPeligible:            0\n",
+                    "VmFlags: rd mr mw me sd \n")
+            ),
+        ];
+
+        for (expected_smap_entries, entries) in data {
+            assert_eq!(expected_smap_entries, parse_smap_entries(entries).unwrap());
+        }
+    }
+}
diff --git a/src/uu/sysctl/src/sysctl.rs b/src/uu/sysctl/src/sysctl.rs
index 78aceb6..1041d2b 100644
--- a/src/uu/sysctl/src/sysctl.rs
+++ b/src/uu/sysctl/src/sysctl.rs
@@ -64,14 +64,10 @@ mod linux {
         var_or_assignment: &str,
         quiet: bool,
     ) -> Result<Option<(String, String)>, Box<UIoError>> {
-        let mut splitted = var_or_assignment.splitn(2, '=');
-        let var = normalize_var(
-            splitted
-                .next()
-                .expect("Split always returns at least 1 value"),
-        );
-
-        if let Some(value_to_set) = splitted.next() {
+        let mut split = var_or_assignment.splitn(2, '=');
+        let var = normalize_var(split.next().expect("Split always returns at least 1 value"));
+
+        if let Some(value_to_set) = split.next() {
             set_sysctl(&var, value_to_set)
                 .map_err(|e| e.map_err_context(|| format!("error writing key '{}'", var)))?;
             if quiet {
diff --git a/src/uu/tload/Cargo.toml b/src/uu/tload/Cargo.toml
new file mode 100644
index 0000000..a1b584a
--- /dev/null
+++ b/src/uu/tload/Cargo.toml
@@ -0,0 +1,25 @@
+[package]
+name = "uu_tload"
+version = "0.0.1"
+edition = "2021"
+authors = ["uutils developers"]
+license = "MIT"
+description = "tload ~ (uutils) graphic representation of system load average"
+
+homepage = "https://github.com/uutils/procps"
+repository = "https://github.com/uutils/procps/tree/main/src/uu/tload"
+keywords = ["acl", "uutils", "cross-platform", "cli", "utility"]
+categories = ["command-line-utilities"]
+
+[dependencies]
+clap = { workspace = true }
+crossterm = { workspace = true }
+ratatui = { workspace = true }
+uucore = { workspace = true }
+
+[lib]
+path = "src/tload.rs"
+
+[[bin]]
+name = "tload"
+path = "src/main.rs"
diff --git a/src/uu/tload/src/main.rs b/src/uu/tload/src/main.rs
new file mode 100644
index 0000000..5c5c627
--- /dev/null
+++ b/src/uu/tload/src/main.rs
@@ -0,0 +1,1 @@
+uucore::bin!(uu_tload);
diff --git a/src/uu/tload/src/tload.rs b/src/uu/tload/src/tload.rs
new file mode 100644
index 0000000..bd80530
--- /dev/null
+++ b/src/uu/tload/src/tload.rs
@@ -0,0 +1,172 @@
+// This file is part of the uutils procps package.
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+use std::collections::VecDeque;
+use std::sync::{Arc, RwLock};
+use std::thread::{self, sleep};
+use std::time::Duration;
+
+use clap::{arg, crate_version, value_parser, ArgAction, ArgMatches, Command};
+use crossterm::event::{self, KeyCode, KeyEvent, KeyModifiers};
+use tui::{LegacyTui, ModernTui};
+use uucore::{error::UResult, format_usage, help_about, help_usage};
+
+const ABOUT: &str = help_about!("tload.md");
+const USAGE: &str = help_usage!("tload.md");
+
+mod tui;
+
+#[derive(Debug, Default, Clone)]
+struct SystemLoadAvg {
+    pub(crate) last_1: f32,
+    pub(crate) last_5: f32,
+    pub(crate) last_10: f32,
+}
+
+impl SystemLoadAvg {
+    #[cfg(target_os = "linux")]
+    fn new() -> UResult<SystemLoadAvg> {
+        use std::fs;
+        use uucore::error::USimpleError;
+
+        let result = fs::read_to_string("/proc/loadavg")?;
+        let split = result.split(" ").collect::<Vec<_>>();
+
+        // Helper function to keep code clean
+        fn f(s: &str) -> UResult<f32> {
+            s.parse::<f32>()
+                .map_err(|e| USimpleError::new(1, e.to_string()))
+        }
+
+        Ok(SystemLoadAvg {
+            last_1: f(split[0])?,
+            last_5: f(split[1])?,
+            last_10: f(split[2])?,
+        })
+    }
+
+    #[cfg(not(target_os = "linux"))]
+    fn new() -> UResult<SystemLoadAvg> {
+        Ok(SystemLoadAvg::default())
+    }
+}
+
+#[allow(unused)]
+#[derive(Debug)]
+struct Settings {
+    delay: u64,
+    scale: usize, // Not used
+
+    is_modern: bool, // For modern display
+}
+
+impl Settings {
+    fn new(matches: &ArgMatches) -> Settings {
+        Settings {
+            delay: matches.get_one("delay").cloned().unwrap(),
+            scale: matches.get_one("scale").cloned().unwrap(),
+            is_modern: matches.get_flag("modern"),
+        }
+    }
+}
+
+#[uucore::main]
+pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+    let matches = uu_app().try_get_matches_from(args)?;
+    let settings = Settings::new(&matches);
+
+    let mut terminal = ratatui::init();
+
+    let data = {
+        // Why 10240?
+        //
+        // Emm, maybe there will be some terminal can display more than 10000 char?
+        let data = Arc::new(RwLock::new(VecDeque::with_capacity(10240)));
+        data.write()
+            .unwrap()
+            .push_back(SystemLoadAvg::new().unwrap());
+        data
+    };
+    let cloned_data = data.clone();
+    thread::spawn(move || loop {
+        sleep(Duration::from_secs(settings.delay));
+
+        let mut data = cloned_data.write().unwrap();
+        if data.iter().len() >= 10240 {
+            // Keep this VecDeque smaller than 10240
+            data.pop_front();
+        }
+        data.push_back(SystemLoadAvg::new().unwrap());
+    });
+
+    loop {
+        // Now only accept `Ctrl+C` for compatibility with the original implementation
+        //
+        // Use `event::poll` for non-blocking event reading
+        if let Ok(true) = event::poll(Duration::from_millis(10)) {
+            // If event available, break this loop
+            if let Ok(event::Event::Key(KeyEvent {
+                code: KeyCode::Char('c'),
+                modifiers: KeyModifiers::CONTROL,
+                ..
+            })) = event::read()
+            {
+                // compatibility with the original implementation
+                uucore::error::set_exit_code(130);
+                break;
+            }
+        }
+
+        terminal.draw(|frame| {
+            let data = &data.read().unwrap();
+            let data = data.iter().cloned().collect::<Vec<_>>();
+            frame.render_widget(
+                if settings.is_modern {
+                    ModernTui::new(&data)
+                } else {
+                    LegacyTui::new(&data)
+                },
+                frame.area(),
+            );
+        })?;
+
+        std::thread::sleep(Duration::from_millis(10));
+    }
+
+    ratatui::restore();
+    Ok(())
+}
+
+#[allow(clippy::cognitive_complexity)]
+pub fn uu_app() -> Command {
+    Command::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .override_usage(format_usage(USAGE))
+        .infer_long_args(true)
+        .args([
+            arg!(-d --delay     <secs>  "update delay in seconds")
+                .value_parser(value_parser!(u64))
+                .default_value("5")
+                .hide_default_value(true),
+            arg!(-m --modern            "modern look").action(ArgAction::SetTrue),
+            // TODO: Implement this arg
+            arg!(-s --scale <num>       "vertical scale")
+                .value_parser(value_parser!(usize))
+                .default_value("5")
+                .hide_default_value(true),
+        ])
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    // It's just a test to make sure if can parsing correctly.
+    #[test]
+    fn test_system_load_avg() {
+        let _ = SystemLoadAvg::new().expect("SystemLoadAvg::new");
+    }
+}
diff --git a/src/uu/tload/src/tui.rs b/src/uu/tload/src/tui.rs
new file mode 100644
index 0000000..62ebdc3
--- /dev/null
+++ b/src/uu/tload/src/tui.rs
@@ -0,0 +1,119 @@
+// This file is part of the uutils procps package.
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+use ratatui::{
+    buffer::Buffer,
+    layout::{Constraint, Direction, Layout, Rect},
+    style::{Style, Stylize},
+    symbols::Marker,
+    text::{Line, Text},
+    widgets::{Axis, Block, Borders, Chart, Dataset, GraphType, Paragraph, Widget},
+};
+
+use crate::SystemLoadAvg;
+
+pub(crate) struct ModernTui<'a>(&'a [SystemLoadAvg]);
+
+impl ModernTui<'_> {
+    fn render_header(&self, area: Rect, buf: &mut Buffer) {
+        let text = Text::from(vec![
+            Line::from(format!(
+                "Last 1 min load:   {:>5}",
+                self.0.last().unwrap().last_1
+            )),
+            Line::from(format!(
+                "Last 5 min load:   {:>5}",
+                self.0.last().unwrap().last_5
+            )),
+            Line::from(format!(
+                "Last 10 min load:  {:>5}",
+                self.0.last().unwrap().last_10
+            )),
+        ]);
+
+        Paragraph::new(text)
+            .style(Style::default().bold().italic())
+            .block(
+                Block::new()
+                    .borders(Borders::ALL)
+                    .title("System load history"),
+            )
+            .render(area, buf);
+    }
+
+    fn render_chart(&self, area: Rect, buf: &mut Buffer) {
+        let result = &self.0[self.0.len().saturating_sub(area.width.into())..]
+            .iter()
+            .enumerate()
+            .map(|(index, load)| (index as f64, load.last_1 as f64))
+            .collect::<Vec<_>>();
+
+        let data = Dataset::default()
+            .graph_type(GraphType::Line)
+            .marker(Marker::Braille)
+            .data(result);
+
+        let x_axis = {
+            let start = Line::from("0");
+            let middle = Line::from((area.width / 2).to_string());
+            let end = Line::from(area.width.to_string());
+            Axis::default()
+                .title("Time(per delay)")
+                .bounds([0.0, area.width.into()])
+                .labels(vec![start, middle, end])
+        };
+
+        // Why this tweak?
+        //
+        // Sometime the chart cannot display all the line because of max height are equals the max
+        // load of system in the history, so I add 0.2*{max_load} to the height of chart make it
+        // display beautiful
+        let y_axis_upper_bound = result.iter().map(|it| it.1).reduce(f64::max).unwrap_or(0.0);
+        let y_axis_upper_bound = y_axis_upper_bound + y_axis_upper_bound * 0.2;
+        let label = {
+            let min = "0.0".to_owned();
+            let mid = format!("{:.1}", y_axis_upper_bound / 2.0);
+            let max = format!("{:.1}", y_axis_upper_bound);
+            vec![min, mid, max]
+        };
+        let y_axis = Axis::default()
+            .bounds([0.0, y_axis_upper_bound])
+            .labels(label)
+            .title("System Load");
+
+        Chart::new(vec![data])
+            .x_axis(x_axis)
+            .y_axis(y_axis)
+            .render(area, buf);
+    }
+}
+
+impl ModernTui<'_> {
+    pub(crate) fn new(input: &[SystemLoadAvg]) -> ModernTui<'_> {
+        ModernTui(input)
+    }
+}
+
+impl Widget for ModernTui<'_> {
+    fn render(self, area: ratatui::prelude::Rect, buf: &mut ratatui::prelude::Buffer)
+    where
+        Self: Sized,
+    {
+        let layout = Layout::new(
+            Direction::Vertical,
+            [Constraint::Length(5), Constraint::Min(0)],
+        )
+        .split(area);
+
+        let header = layout[0];
+        let chart = layout[1];
+
+        self.render_header(header, buf);
+        self.render_chart(chart, buf);
+    }
+}
+
+// TODO: Implemented LegacyTui
+pub(crate) type LegacyTui<'a> = ModernTui<'a>;
diff --git a/src/uu/tload/tload.md b/src/uu/tload/tload.md
new file mode 100644
index 0000000..eea64d2
--- /dev/null
+++ b/src/uu/tload/tload.md
@@ -0,0 +1,7 @@
+# tload
+
+```
+tload [options] [tty]
+```
+
+tload prints a graph of the current system load average to the specified tty (or the tty of the tload process if none is specified).
diff --git a/src/uu/w/src/w.rs b/src/uu/w/src/w.rs
index 6ba4d55..f1d803f 100644
--- a/src/uu/w/src/w.rs
+++ b/src/uu/w/src/w.rs
@@ -9,9 +9,9 @@ use clap::crate_version;
 use clap::{Arg, ArgAction, Command};
 #[cfg(target_os = "linux")]
 use libc::{sysconf, _SC_CLK_TCK};
-use std::process;
 #[cfg(target_os = "linux")]
-use std::{collections::HashMap, fs, path::Path};
+use std::{collections::HashMap, fs, path::Path, time::SystemTime};
+use std::{process, time::Duration};
 #[cfg(target_os = "linux")]
 use uucore::utmpx::Utmpx;
 use uucore::{error::UResult, format_usage, help_about, help_usage};
@@ -23,7 +23,7 @@ struct UserInfo {
     user: String,
     terminal: String,
     login_time: String,
-    idle_time: String,
+    idle_time: Duration, // for better compatibility with old-style outputs
     jcpu: String,
     pcpu: String,
     command: String,
@@ -83,6 +83,51 @@ fn fetch_pcpu_time(pid: i32) -> Result<f64, std::io::Error> {
     Ok((utime + stime) / get_clock_tick() as f64)
 }
 
+#[cfg(target_os = "linux")]
+fn fetch_idle_time(tty: String) -> Result<Duration, std::io::Error> {
+    let path = Path::new("/dev/").join(tty);
+    let stat = fs::metadata(path)?;
+    if let Ok(time) = stat.accessed() {
+        Ok(SystemTime::now().duration_since(time).unwrap_or_default())
+    } else {
+        Ok(Duration::ZERO)
+    }
+}
+
+#[cfg(not(target_os = "linux"))]
+fn _fetch_idle_time(_tty: String) -> Result<Duration, std::io::Error> {
+    Ok(Duration::ZERO)
+}
+
+fn format_time_elapsed(time: Duration, old_style: bool) -> Result<String, chrono::OutOfRangeError> {
+    let t = chrono::Duration::from_std(time)?;
+    if t.num_days() >= 2 {
+        Ok(format!("{}days", t.num_days()))
+    } else if t.num_hours() >= 1 {
+        Ok(format!(
+            "{}:{:02}{}",
+            t.num_hours(),
+            t.num_minutes() % 60,
+            if old_style { "" } else { "m" }
+        ))
+    } else if t.num_minutes() >= 1 {
+        Ok(format!(
+            "{}:{:02}{}",
+            t.num_minutes() % 60,
+            t.num_seconds() % 60,
+            if old_style { "m" } else { "" }
+        ))
+    } else if old_style {
+        Ok(String::new())
+    } else {
+        Ok(format!(
+            "{}.{:02}s",
+            t.num_seconds() % 60,
+            (t.num_milliseconds() % 1000) / 10
+        ))
+    }
+}
+
 #[cfg(target_os = "linux")]
 fn format_time(time: String) -> Result<String, chrono::format::ParseError> {
     let mut t: String = time;
@@ -127,7 +172,7 @@ fn fetch_user_info() -> Result<Vec<UserInfo>, std::io::Error> {
                 user: entry.user(),
                 terminal: entry.tty_device(),
                 login_time: format_time(entry.login_time().to_string()).unwrap_or_default(),
-                idle_time: "TODO".into(), // Placeholder, needs actual implementation
+                idle_time: fetch_idle_time(entry.tty_device())?,
                 jcpu: format!("{:.2}", jcpu),
                 pcpu: fetch_pcpu_time(entry.pid()).unwrap_or_default().to_string(),
                 command: fetch_cmdline(entry.pid()).unwrap_or_default(),
@@ -150,6 +195,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
 
     let no_header = matches.get_flag("no-header");
     let short = matches.get_flag("short");
+    let old_style = matches.get_flag("old-style");
 
     match fetch_user_info() {
         Ok(user_info) => {
@@ -167,7 +213,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
                 if short {
                     println!(
                         "{:<9}{:<9}{:<7}{:<}",
-                        user.user, user.terminal, user.idle_time, user.command
+                        user.user,
+                        user.terminal,
+                        format_time_elapsed(user.idle_time, old_style).unwrap_or_default(),
+                        user.command
                     );
                 } else {
                     println!(
@@ -175,7 +224,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
                         user.user,
                         user.terminal,
                         user.login_time,
-                        user.idle_time,
+                        format_time_elapsed(user.idle_time, old_style).unwrap_or_default(),
                         user.jcpu,
                         user.pcpu,
                         user.command
@@ -260,9 +309,10 @@ pub fn uu_app() -> Command {
 #[cfg(target_os = "linux")]
 mod tests {
     use crate::{
-        fetch_cmdline, fetch_pcpu_time, fetch_terminal_number, format_time, get_clock_tick,
+        fetch_cmdline, fetch_pcpu_time, fetch_terminal_number, format_time, format_time_elapsed,
+        get_clock_tick,
     };
-    use std::{fs, path::Path, process};
+    use std::{fs, path::Path, process, time::Duration};
 
     #[test]
     fn test_format_time() {
@@ -283,6 +333,19 @@ mod tests {
         )
     }
 
+    #[test]
+    fn test_format_time_elapsed() {
+        let td = Duration::new(60 * 60 * 18 + 60 * 18, 0);
+        assert_eq!(
+            format_time_elapsed(td, false).unwrap(),
+            String::from("18:18m")
+        );
+        assert_eq!(
+            format_time_elapsed(td, true).unwrap(),
+            String::from("18:18")
+        );
+    }
+
     #[test]
     // Get PID of current process and use that for cmdline testing
     fn test_fetch_cmdline() {


Test patch:
diff --git a/tests/by-util/test_pidof.rs b/tests/by-util/test_pidof.rs
index 2234fd5..08f319b 100644
--- a/tests/by-util/test_pidof.rs
+++ b/tests/by-util/test_pidof.rs
@@ -24,8 +24,9 @@ fn test_find_init() {
 
 #[test]
 #[cfg(target_os = "linux")]
-fn test_find_kthreadd() {
-    new_ucmd!().arg("kthreadd").succeeds();
+fn test_find_kthreadd_only_with_w_flag() {
+    new_ucmd!().arg("kthreadd").fails();
+    new_ucmd!().arg("-w").arg("kthreadd").succeeds();
 }
 
 #[test]
@@ -37,7 +38,12 @@ fn test_no_pid_found() {
 #[test]
 #[cfg(target_os = "linux")]
 fn test_quiet() {
-    new_ucmd!().arg("kthreadd").arg("-q").succeeds().no_output();
+    new_ucmd!()
+        .arg("kthreadd")
+        .arg("-q")
+        .arg("-w")
+        .succeeds()
+        .no_output();
 }
 
 #[test]
@@ -45,7 +51,7 @@ fn test_quiet() {
 fn test_single_shot() {
     for arg in ["-s", "--single-shot"] {
         let binding = new_ucmd!()
-            .args(&[arg, "kthreadd", "kthreadd", "kthreadd"])
+            .args(&[arg, "-w", "kthreadd", "kthreadd", "kthreadd"])
             .succeeds();
         let output = binding.stdout_str().trim_end();
 
@@ -63,7 +69,7 @@ fn test_single_shot() {
 #[cfg(target_os = "linux")]
 fn test_omit_pid() {
     for arg in ["-o=1000", "--omit-pid=1000"] {
-        new_ucmd!().arg(arg).arg("kthreadd").succeeds();
+        new_ucmd!().arg(arg).arg("-w").arg("kthreadd").succeeds();
     }
 }
 
@@ -76,7 +82,7 @@ fn test_separator() {
 
     for arg in ["-S", "-d", "--separator"] {
         new_ucmd!()
-            .args(&[arg, "separator", "kthreadd", "kthreadd"])
+            .args(&[arg, "separator", "-w", "kthreadd", "kthreadd"])
             .succeeds()
             .stdout_matches(re);
     }
diff --git a/tests/by-util/test_pmap.rs b/tests/by-util/test_pmap.rs
index 7d0ec60..5c196a0 100644
--- a/tests/by-util/test_pmap.rs
+++ b/tests/by-util/test_pmap.rs
@@ -73,6 +73,22 @@ fn test_non_existing_pid() {
         .no_output();
 }
 
+#[test]
+#[cfg(target_os = "linux")]
+fn test_extended() {
+    let pid = process::id();
+
+    for arg in ["-x", "--extended"] {
+        let result = new_ucmd!()
+            .arg(arg)
+            .arg(pid.to_string())
+            .succeeds()
+            .stdout_move_str();
+
+        assert_extended_format(pid, &result);
+    }
+}
+
 #[test]
 #[cfg(target_os = "linux")]
 fn test_device() {
@@ -117,6 +133,47 @@ fn assert_format(pid: u32, s: &str) {
     assert!(re.is_match(last_line));
 }
 
+// Ensure `s` has the following extended format (--extended):
+//
+// 1234:   /some/path
+// Address           Kbytes     RSS   Dirty Mode  Mapping
+// 000073eb5f4c7000       8       4       0 rw--- ld-linux-x86-64.so.2
+// 00007ffd588fc000     132       3      13 rw---   [ stack ]
+// ffffffffff600000       4       0       1 --x--   [ anon ]
+// ...
+// ---------------- ------- ------- ------- (one intentional trailing space)
+// total kB             144       7      14
+#[cfg(target_os = "linux")]
+fn assert_extended_format(pid: u32, s: &str) {
+    let lines: Vec<_> = s.lines().collect();
+    let line_count = lines.len();
+
+    let re = Regex::new(&format!("^{pid}:   .+[^ ]$")).unwrap();
+    assert!(re.is_match(lines[0]));
+
+    let expected_header = "Address           Kbytes     RSS   Dirty Mode  Mapping";
+    assert_eq!(expected_header, lines[1]);
+
+    let re = Regex::new(
+        r"^[0-9a-f]{16} +[1-9][0-9]* +\d+ +\d+ (-|r)(-|w)(-|x)(-|s)- (  \[ (anon|stack) \]|[a-zA-Z0-9._-]+)$",
+    )
+    .unwrap();
+
+    for line in lines.iter().take(line_count - 2).skip(2) {
+        assert!(re.is_match(line), "failing line: {line}");
+    }
+
+    let expected_separator = "---------------- ------- ------- ------- ";
+    assert_eq!(expected_separator, lines[line_count - 2]);
+
+    let re = Regex::new(r"^total kB +[1-9][0-9]* +\d+ +\d+$").unwrap();
+    assert!(
+        re.is_match(lines[line_count - 1]),
+        "failing line: {}",
+        lines[line_count - 1]
+    );
+}
+
 // Ensure `s` has the following device format (--device):
 //
 // 1234:   /some/path
diff --git a/tests/by-util/test_tload.rs b/tests/by-util/test_tload.rs
new file mode 100644
index 0000000..85ca6f4
--- /dev/null
+++ b/tests/by-util/test_tload.rs
@@ -0,0 +1,11 @@
+// This file is part of the uutils procps package.
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+use crate::common::util::TestScenario;
+
+#[test]
+fn test_invalid_arg() {
+    new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
+}
diff --git a/tests/tests.rs b/tests/tests.rs
index 2749cba..62f7e81 100644
--- a/tests/tests.rs
+++ b/tests/tests.rs
@@ -60,3 +60,7 @@ mod test_pkill;
 #[cfg(feature = "sysctl")]
 #[path = "by-util/test_sysctl.rs"]
 mod test_sysctl;
+
+#[cfg(feature = "tload")]
+#[path = "by-util/test_tload.rs"]
+mod test_tload;