cpuload.nim 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## This module implements a helper for a thread pool to determine whether
  10. ## creating a thread is a good idea.
  11. ##
  12. ## Unstable API.
  13. when defined(windows):
  14. import winlean, os, strutils, math
  15. proc `-`(a, b: FILETIME): int64 = a.rdFileTime - b.rdFileTime
  16. elif defined(linux):
  17. from cpuinfo import countProcessors
  18. when defined(nimPreviewSlimSystem):
  19. import std/syncio
  20. type
  21. ThreadPoolAdvice* = enum
  22. doNothing,
  23. doCreateThread, # create additional thread for throughput
  24. doShutdownThread # too many threads are busy, shutdown one
  25. ThreadPoolState* = object
  26. when defined(windows):
  27. prevSysKernel, prevSysUser, prevProcKernel, prevProcUser: FILETIME
  28. calls*: int
  29. proc advice*(s: var ThreadPoolState): ThreadPoolAdvice =
  30. when defined(windows):
  31. var
  32. sysIdle, sysKernel, sysUser,
  33. procCreation, procExit, procKernel, procUser: FILETIME
  34. if getSystemTimes(sysIdle, sysKernel, sysUser) == 0 or
  35. getProcessTimes(Handle(-1), procCreation, procExit,
  36. procKernel, procUser) == 0:
  37. return doNothing
  38. if s.calls > 0:
  39. let
  40. sysKernelDiff = sysKernel - s.prevSysKernel
  41. sysUserDiff = sysUser - s.prevSysUser
  42. procKernelDiff = procKernel - s.prevProcKernel
  43. procUserDiff = procUser - s.prevProcUser
  44. sysTotal = sysKernelDiff + sysUserDiff
  45. procTotal = procKernelDiff + procUserDiff
  46. # total CPU usage < 85% --> create a new worker thread.
  47. # Measurements show that 100% and often even 90% is not reached even
  48. # if all my cores are busy.
  49. if sysTotal == 0 or procTotal.float / sysTotal.float < 0.85:
  50. result = doCreateThread
  51. s.prevSysKernel = sysKernel
  52. s.prevSysUser = sysUser
  53. s.prevProcKernel = procKernel
  54. s.prevProcUser = procUser
  55. elif defined(linux):
  56. proc fscanf(c: File, frmt: cstring) {.varargs, importc,
  57. header: "<stdio.h>".}
  58. var f: File
  59. if f.open("/proc/loadavg"):
  60. var b: float
  61. var busy, total: int
  62. fscanf(f,"%lf %lf %lf %ld/%ld",
  63. addr b, addr b, addr b, addr busy, addr total)
  64. f.close()
  65. let cpus = countProcessors()
  66. if busy-1 < cpus:
  67. result = doCreateThread
  68. elif busy-1 >= cpus*2:
  69. result = doShutdownThread
  70. else:
  71. result = doNothing
  72. else:
  73. result = doNothing
  74. else:
  75. # XXX implement this for other OSes
  76. result = doNothing
  77. inc s.calls
  78. when not defined(testing) and isMainModule and not defined(nimdoc):
  79. import random
  80. proc busyLoop() =
  81. while true:
  82. discard rand(80)
  83. os.sleep(100)
  84. spawn busyLoop()
  85. spawn busyLoop()
  86. spawn busyLoop()
  87. spawn busyLoop()
  88. var s: ThreadPoolState
  89. for i in 1 .. 70:
  90. echo advice(s)
  91. os.sleep(1000)