Skip to content

🐛 0.10.x introduced sysinfo crate result in very slow speed under Linux #839

@ttys3

Description

@ttys3

brief description

0.10.x introduced sysinfo crate result in very slow speed under Linux.

a simple delta diff cost about 300ms (with 16 logic core cpu)

Append:

just test on another Linux computer, 6 core CPU

a simple delta diff cost about 100ms (with 6 logic core cpu)

so for each core, get_cpu_frequency() call cost about 15ms, if you CPU core is less than 10, this problem is not easy to found, because you are not very obvious to feel the delay gap.

for any >= 0.10.x version, the more (logic) CPU cores you have, the more slower you get

this issue is also mentioned in #841 (comment)

I also tried delta-0.9.2-x86_64-unknown-linux-gnu (https://github.com/dandavison/delta/releases/download/0.9.2/delta-0.9.2-x86_64-unknown-linux-gnu.tar.gz)

which works without slowdown problem on my machine.

the problem seems to be get_cpu_frequency() call in sysinfo crate

my patched version resolved the slowdown problem: https://github.com/ttys3/delta/releases/tag/0.11.2

related commit: ttys3@8f5a835

ttys3/sysinfo@53cf3dd

since this need to patch the sysinfo crate, it is hard to make a normal PR -_-


my investigation

here's my env:

------------
OS: Arch Linux x86_64
Kernel: 5.15.6-arch2-1
Shell: zsh 5.8
Resolution: 3840x2160
Terminal: tmux
CPU: Intel i9-9900 (16) @ 5.000GHz
GPU: NVIDIA GeForce GTX 1060 3GB
Memory: 6747MiB / 32038MiB


my git config related to delta:

[pager]
    #delta
    log = delta --color-only | less -RFX
    show = delta --color-only | less -RFX
    diff = delta --color-only | less -RFX

1. test with git diff

with delta 0.11.1, do time git diff Cargo.toml cost about 0.5s each time (repeated 3 times):

❯ delta --version
delta 0.11.1

git diff Cargo.toml  0.08s user 0.02s system 18% cpu 0.534 total
git diff Cargo.toml  0.07s user 0.04s system 23% cpu 0.505 total
git diff Cargo.toml  0.07s user 0.05s system 20% cpu 0.580 total

with delta 0.11.2, do time git diff Cargo.toml cost about 0.3s each time (repeated 3 times):

❯ delta --version
delta 0.11.2

git diff Cargo.toml  0.05s user 0.00s system 18% cpu 0.311 total
git diff Cargo.toml  0.05s user 0.01s system 18% cpu 0.307 total
git diff Cargo.toml  0.04s user 0.02s system 18% cpu 0.305 total

2. without git, run delta directly

time delta Cargo.toml.old Cargo.toml

delta 0.11.1

delta Cargo.toml.old Cargo.toml  0.06s user 0.06s system 20% cpu 0.600 total
delta Cargo.toml.old Cargo.toml  0.06s user 0.06s system 21% cpu 0.567 total
delta Cargo.toml.old Cargo.toml  0.07s user 0.06s system 21% cpu 0.571 total

delta 0.11.2

delta Cargo.toml.old Cargo.toml  0.06s user 0.00s system 18% cpu 0.322 total
delta Cargo.toml.old Cargo.toml  0.06s user 0.01s system 20% cpu 0.311 total
delta Cargo.toml.old Cargo.toml  0.05s user 0.01s system 20% cpu 0.293 total

the result keep the same. so it does not related to git.


the normal speed should be near 0.001s, just like this (for example time diff Cargo.toml.old Cargo.toml):

diff --color Cargo.toml.old Cargo.toml  0.00s user 0.00s system 82% cpu 0.001 total
diff --color Cargo.toml.old Cargo.toml  0.00s user 0.00s system 85% cpu 0.001 total
diff --color Cargo.toml.old Cargo.toml  0.00s user 0.00s system 83% cpu 0.001 total

I have found the root cause.

it is delta::utils::process::determine_calling_process

2021-12-08_23-12_1

expand the tower top:

2021-12-08_23-13

so the reason is clear:

delta::utils::process::determine_calling_process
|
V
sysinfo::linux::system::System::refresh_processors
|
v
sysinfo::linux::processor::get_cpu_frequency

oh NO NO NO NO, it try to detect the cpu frequency !!!!

just disable the call, the speed is up:

delta/target/release/delta 0.05s user 0.00s system 101% cpu 0.051 total
delta/target/release/delta 0.05s user 0.01s system 101% cpu 0.051 total
delta/target/release/delta 0.04s user 0.01s system 101% cpu 0.051 total
diff --git a/src/utils/process.rs b/src/utils/process.rs
index 827e44d..ac3a43e 100644
--- a/src/utils/process.rs
+++ b/src/utils/process.rs
@@ -39,7 +39,8 @@ lazy_static! {
 }
 
 fn determine_calling_process() -> Option<CallingProcess> {
-    calling_process_cmdline(ProcInfo::new(), describe_calling_process)
+    None
+    // calling_process_cmdline(ProcInfo::new(), describe_calling_process)
 }
 
 // Return value of `extract_args(args: &[String]) -> ProcessArgs<T>` function which is

the reason is:

delta src/utils/process.rs

info: sysinfo::System::new(),

impl ProcInfo {
    fn new() -> Self {
        ProcInfo {
            info: sysinfo::System::new(),
        }
    }
}

and sysinfo::System::new() is:

    fn new() -> Self {
        Self::new_with_specifics(RefreshKind::new())
    }

new_with_specifics will always try to refresh_processors:

by default, !refreshes.cpu() result in !false , so it is true:

fn new_with_specifics(refreshes: RefreshKind) -> System {
       // ...
        if !refreshes.cpu() {
            s.refresh_processors(None); // We need the processors to be filled.
        }
        s.refresh_specifics(refreshes);
 // ...
}

there seems no way to forbbide refresh_processors call.

if we change the new to sysinfo::System::new_with_specifics(sysinfo::RefreshKind::new().with_cpu())

the first s.refresh_processors(None); will not get called.

but in s.refresh_specifics(refreshes);, it get called again.


Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions