sysinfo icon indicating copy to clipboard operation
sysinfo copied to clipboard

incorrect virtual memory?

Open fdncred opened this issue 4 years ago • 24 comments

https://github.com/GuillaumeGomez/sysinfo/blob/639f6afc6dc8808572853b721fa634eefd06b489/src/windows/process.rs#L782

I'm guessing that this code may not be right because in nushell it's showing that i have terabytes of virtual memory, which i don't have. nushell needs the number in bytes so we're doing something like this process.virtual_memory() * 1000 to get bytes.

Do you think nushell is reporting it the wrong way or is it being calculated the wrong way in sysinfo?

fdncred avatar Feb 04 '21 15:02 fdncred

The doc says that virtual_memory returns the size in KB as you can see here. So it depends what size nushell wants to display.

GuillaumeGomez avatar Feb 04 '21 15:02 GuillaumeGomez

Thanks.

fdncred avatar Feb 04 '21 15:02 fdncred

Well, the initial question remains: if they intend to display bytes and not kilobytes and you still have terabytes, then there is a problem in sysinfo. If you could maybe confirm? :)

GuillaumeGomez avatar Feb 04 '21 16:02 GuillaumeGomez

This is where we're tracking this issue. Your example program seems to be reporting differently than we're reporting in nushell. I'm not sure why yet. I'll try to get back to you on this.

https://github.com/nushell/nushell/issues/3003

I really don't get why it's not working because this is all we're doing.

dict.insert_untagged(
            "virtual",
            UntaggedValue::filesize(process.virtual_memory() * 1000),
        );

fdncred avatar Feb 04 '21 16:02 fdncred

@GuillaumeGomez I've gone through this a bit in our code. If you see below, it looks like we're following the model as you used in your example application. You can see where I inserted some eprintln! statements to see if our formatting is doing anything odd somewhere later. Unfortunately, it appears that process.virutal_memory() is outputting wrong information in nushell. Do you see anything odd in the code snippet below?

pub async fn ps(tag: Tag, long: bool) -> Result<Vec<Value>, ShellError> {
    let mut sys = System::new_all();
    sys.refresh_all();
    let duration = std::time::Duration::from_millis(500);
    std::thread::sleep(duration);
    sys.refresh_all();

    let mut output = vec![];

    let result = sys.get_processes();

    for (pid, process) in result.iter() {
        let mut dict = TaggedDictBuilder::new(&tag);
        dict.insert_untagged("pid", UntaggedValue::int(*pid));
        dict.insert_untagged("name", UntaggedValue::string(process.name()));
        eprintln!("myname {}", process.name());
        dict.insert_untagged(
            "status",
            UntaggedValue::string(format!("{:?}", process.status())),
        );
        dict.insert_untagged(
            "cpu",
            UntaggedValue::decimal_from_float(process.cpu_usage() as f64, tag.span),
        );
        dict.insert_untagged("mem", UntaggedValue::filesize(process.memory() * 1000));
        eprintln!("mymem {}", process.memory());
        dict.insert_untagged("virtual", UntaggedValue::filesize(process.virtual_memory()));
        eprintln!("myvm {}", process.virtual_memory());
...

I also tried sys.get_process(pid) and it had the same results. I was trying to do sys.refresh_process(pid) but I was getting compiler errors.

fdncred avatar Feb 04 '21 21:02 fdncred

No, your code looks correct as far as I can tell. The issue must be coming from sysinfo. Can you maybe add some debug in sysinfo in order to track where the issue is coming from? I can't seem to replicate it on my laptop so I'll have to rely on you to find it (sorry...).

GuillaumeGomez avatar Feb 04 '21 21:02 GuillaumeGomez

Probably. What do you want me to add? When I run your example app, it works correctly.

fdncred avatar Feb 04 '21 21:02 fdncred

Simply some println! around to track the virtual memory value in order to check where it goes wrong.

GuillaumeGomez avatar Feb 04 '21 21:02 GuillaumeGomez

@GuillaumeGomez Could this be the problem?

https://github.com/GuillaumeGomez/sysinfo/blob/6db49a8042fe80d57b84572d23cf64551e29cbb1/src/windows/system.rs#L258

I'm wondering if that code above should be PrivateUsage instead of VirtualSize

https://github.com/GuillaumeGomez/sysinfo/blob/6db49a8042fe80d57b84572d23cf64551e29cbb1/src/windows/process.rs#L782

fdncred avatar Feb 04 '21 22:02 fdncred

PrivateUsage prints the correct memory. VirtualSize is not correct. I'm not sure why. According to Microsoft The VirtualSize member contains the current size, in bytes, of virtual memory used by the process. so it seems right but the value is wrong.

fdncred avatar Feb 04 '21 22:02 fdncred

I never paid attention but it seems you're right. How weird... When you change to PrivateUsage everywhere, does it look better?

GuillaumeGomez avatar Feb 05 '21 08:02 GuillaumeGomez

This seems to be working much better.

    let mut sys = System::new_all();
    let mut output = vec![];
    let result: Vec<usize> = sys.get_processes().keys().cloned().collect::<Vec<usize>>();

    for pid in result {
        sys.refresh_process(pid);
        if let Some(process) = sys.get_process(pid) {
            let mut dict = TaggedDictBuilder::new(&tag);
...
            dict.insert_untagged("mem", UntaggedValue::filesize(process.memory() * 1000));
            dict.insert_untagged(
                "virtual",
                UntaggedValue::filesize(process.virtual_memory() * 1000),
            );

sys.refresh_process(pid) eventually calls the function with PrivateUsage.

I just wish sysinfo wouldn't get the information in KB. Maybe Microsoft is doing that. I can't remember now.

fdncred avatar Feb 05 '21 13:02 fdncred

I think the information is returned in KB in linux, so all other systems kinda need to return the same "level".

GuillaumeGomez avatar Feb 05 '21 13:02 GuillaumeGomez

Do you mind sending a PR for this fix? Since you found where the problem was coming from... ;)

GuillaumeGomez avatar Feb 05 '21 13:02 GuillaumeGomez

I don't think there is anything to PR because the route I took was essentially not to do this:

let result = sys.get_processes();

    for (pid, process) in result.iter() {

because once you do that, you can't call sys.refresh_process(pid). <-- This function works to update the memory correctly on Windows. Any other way is not working.

And a worse note - I just saw that now the memory numbers on Linux may be artificially large. Ugh.

fdncred avatar Feb 05 '21 13:02 fdncred

What the hell... There are a lot of things that need to be fixed apparently.

GuillaumeGomez avatar Feb 05 '21 13:02 GuillaumeGomez

I was going to try and look at it in WSL2 and see if anything jumps out.

fdncred avatar Feb 05 '21 14:02 fdncred

Thanks, that'd be really appreciated. But I still think that if any path/route leads to invalid data, then there is something to fix. Can you provide a small test code so I can run it locally on my windows and try to fix it please?

GuillaumeGomez avatar Feb 05 '21 14:02 GuillaumeGomez

Something is going on in linux as well I think. mem looks ok but virutal not so much.

ps -l | where pid == 51
╭───┬─────┬──────┬────────┬────────┬────────────┬───────────────────┬────────┬───────────────┬─────────╮
│ # │ pid │ name │ status │ cpu    │ mem        │ virtual           │ parent │ exe           │ command │
├───┼─────┼──────┼────────┼────────┼────────────┼───────────────────┼────────┼───────────────┼─────────┤
│ 0 │  51 │ fish │ Sleep  │ 0.0000 │ 12,040,000 │ 5,838,651,392,000 │      9 │ /usr/bin/fish │ fish    │
╰───┴─────┴──────┴────────┴────────┴────────────┴───────────────────┴────────┴───────────────┴─────────╯

This is what virtual should be as per the man proc.

cat /proc/51/stat | cut -d" " -f23
1,459,662,848

5.8TB vs 1.4GB

fdncred avatar Feb 05 '21 15:02 fdncred

This is the small test code from above, tweaked a bit, that shows how it works in Windows.

    let mut sys = System::new_all();
    let mut output = vec![];
    let result: Vec<usize> = sys.get_processes().keys().cloned().collect::<Vec<usize>>();

    for pid in result {
        sys.refresh_process(pid);
        if let Some(process) = sys.get_process(pid) {
           println!("name {}", process.name());
           println!("mem {}", process.memory() * 1000);
           println!("virtual {}", process.virtual_memory() * 1000);
        }
    }

fdncred avatar Feb 05 '21 15:02 fdncred

I think I may see the problem in Linux.

https://github.com/GuillaumeGomez/sysinfo/blob/a3099e08735f752009a6ac7a9f709fba4c855344/src/linux/system.rs#L655

According to man proc

              (23) vsize  %lu
                     Virtual memory size in bytes.

It's reporting in bytes and then sysinfo is multiplying page_size_kb.

fdncred avatar Feb 05 '21 15:02 fdncred

Great catch! Interested into sending a PR for this one at least?

GuillaumeGomez avatar Feb 05 '21 16:02 GuillaumeGomez

#430

fdncred avatar Feb 05 '21 16:02 fdncred

I'll reopen since the issue still exists on windows (based on your comments).

GuillaumeGomez avatar Feb 05 '21 20:02 GuillaumeGomez