Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Windows] emulate UNIX os.getloadavg() #1484

Closed
giampaolo opened this issue Apr 9, 2019 · 10 comments
Closed

[Windows] emulate UNIX os.getloadavg() #1484

giampaolo opened this issue Apr 9, 2019 · 10 comments

Comments

@giampaolo
Copy link
Owner

giampaolo commented Apr 9, 2019

I'm not sure I understand whether we can really emulate the UNIX counterpart, but this looks interesting:
https://bugs.python.org/issue34060
python/cpython@e16467a
https://github.com/python/cpython/blob/master/Lib/test/libregrtest/win_utils.py

Part of the confusion is that I currently don't really understand how getloadavg() should be interpreted (need to read some literature) . My hope is to land something like this:

def getloadvg():
     if POSIX:
        return os.getloadavg()
    else:
        return _windows_impl()

...but returning 1 value (on Windows, average since last call) vs. 3 values (on UNIX, representing the average of last 1, 5, 15 minutes) maybe suggests these are 2 different things so we should call it differently?

@giampaolo giampaolo self-assigned this Apr 9, 2019
@giampaolo giampaolo changed the title [Windows] emulate os.getloadavg() [Windows] emulate UNIX os.getloadavg() Apr 9, 2019
@giampaolo
Copy link
Owner Author

CC-ing @ammaraskar just in case he wants to provide advice/direction.

@ammaraskar
Copy link
Contributor

ammaraskar commented Apr 9, 2019

Hey, it's entirely possible to do the 3 values.

The best literature to read would definitely be: https://en.wikipedia.org/wiki/Load_(computing)#Unix-style_load_calculation which explains really well how the value is calculated.

Essentially its the weighted moving average of the number of processes in the run queue of the OS over 1 minute, 5 minutes and 15 minutes.

You can find Linux's load average calculation here: https://github.com/torvalds/linux/blob/345671ea0f9258f410eb057b9ced9cefbbe5dc78/include/linux/sched/loadavg.h#L18-L38 which is what is emulated in https://github.com/python/cpython/blob/master/Lib/test/libregrtest/win_utils.py#L97

As the Linux comment eludes, the constants can be calculated by:
1 / exp(sampling interval in seconds / window size in seconds)

for example, in CPython we only care about the 1 minute window and we sample every 5 seconds, so the constant comes from:
1 / exp(5 / 60) = 0.92004441462

You can calculate out the constants for the other windows (5 minutes and 15 minutes) and track those separately as well like Linux does in order to fully emulate it: https://github.com/torvalds/linux/blob/345671ea0f9258f410eb057b9ced9cefbbe5dc78/kernel/sched/loadavg.c#L356-L358

Hope this helps and lemme know if you have any other questions.

@ammaraskar
Copy link
Contributor

ammaraskar commented Apr 9, 2019

Oh also, I should say the calculations are the easy part. Getting the actual number of processes in the run queue for windows is an absolute pain and we ended up running the command:

typeperf "\System\Processor Queue Length" -si 5

in order to grab the value. There's some win32 apis that can achieve the same thing but are way more involved in the C side.

@giampaolo
Copy link
Owner Author

giampaolo commented Apr 10, 2019

Thanks for the info @ammaraskar. It appears this could theoretically be good for inclusion but I suspect that running typeperf in a subprocess would be problem as it'd be returned by Process(os.getpid()).children()) and killed by reap_children() on each unit-test run. I suppose there's no way other than using a subprocess or thread (see "using native Win APIs")?

There's some win32 apis that can achieve the same thing but are way more involved in the C side.

Do you know which ones?

@ammaraskar
Copy link
Contributor

You can find the C based implementation I did for CPython here python/cpython@master...ammaraskar:windows_load

Internally, this windows API spins up a thread to do the sampling.

@giampaolo
Copy link
Owner Author

Sweet, thanks. I'll take a look at that and I will probably ping you later on with some questions. =)

@giampaolo
Copy link
Owner Author

Some questions:

  1. other than LOADAVG_FACTOR_1F 0.9200444146293232478931553241 do you know the magic number for 5F and 15F intervals?
  2. should I register 3 different callbacks (RegisterWaitForSingleObject), 1 for each value?
  3. I copy/pasted your code in a branch (worked immediately):

@ammaraskar
Copy link
Contributor

  1. The constants would be:

1 minute: 0.92004441462932324789315532405371723167318753495997420170
5 minutes: 0.659240630200443746254760411013414882365778498066511225174
15 minutes: 0.286504796860190100324885426647837602793150792328251047088

  1. Nah, just one callback will do, only thing that changes is the constant for the calculation

  2. Sure! I would love to contribute! Just gimme a few hours to get caught up with the project.

@giampaolo
Copy link
Owner Author

giampaolo commented Apr 10, 2019

Cool, thanks. To quickly set you up:

@giampaolo
Copy link
Owner Author

...last: you may want to change the Python path in make.bat:
https://github.com/giampaolo/psutil/blob/master/make.bat#L22-L28

ammaraskar added a commit to ammaraskar/psutil that referenced this issue Apr 11, 2019
giampaolo pushed a commit that referenced this issue Apr 11, 2019
nlevitt added a commit to nlevitt/psutil that referenced this issue May 6, 2019
* origin/master:
  Fix giampaolo#1276: [AIX] use getargs to get process cmdline (giampaolo#1500) (patch by @wiggin15)
  Fix Process.ionice example using wrong keyword arg (giampaolo#1504)
  fix history syntax
  remove catching IOError; let the test fail and adjust it later
  Fix cpu freq (giampaolo#1496)
  pre release
  fix giampaolo#1493: [Linux] cpu_freq(): handle the case where /sys/devices/system/cpu/cpufreq/ exists but is empty.
  Revert "Fix cpu_freq (giampaolo#1493)" (giampaolo#1495)
  Fix cpu_freq (giampaolo#1493)
  Update cpu_freq to return 0 for max/min if not available (giampaolo#1487)
  give CREDITS to @agnewee for giampaolo#1491
  SunOS / net_if_addrs(): free() ifap struct on error (giampaolo#1491)
  fix giampaolo#1486: add wraps() decorator around wrap_exceptions
  refactor/move some utilities into _common.py
  update doc
  update HISTORY
  Implement getloadavg on Windows. Fixes giampaolo#604 and giampaolo#1484 (giampaolo#1485) (patch by Ammar Askar)
  give credits to @amanusk for giampaolo#1472
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants