cpuload.nim 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  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. type
  19. ThreadPoolAdvice* = enum
  20. doNothing,
  21. doCreateThread, # create additional thread for throughput
  22. doShutdownThread # too many threads are busy, shutdown one
  23. ThreadPoolState* = object
  24. when defined(windows):
  25. prevSysKernel, prevSysUser, prevProcKernel, prevProcUser: FILETIME
  26. calls*: int
  27. proc advice*(s: var ThreadPoolState): ThreadPoolAdvice =
  28. when defined(windows):
  29. var
  30. sysIdle, sysKernel, sysUser,
  31. procCreation, procExit, procKernel, procUser: FILETIME
  32. if getSystemTimes(sysIdle, sysKernel, sysUser) == 0 or
  33. getProcessTimes(Handle(-1), procCreation, procExit,
  34. procKernel, procUser) == 0:
  35. return doNothing
  36. if s.calls > 0:
  37. let
  38. sysKernelDiff = sysKernel - s.prevSysKernel
  39. sysUserDiff = sysUser - s.prevSysUser
  40. procKernelDiff = procKernel - s.prevProcKernel
  41. procUserDiff = procUser - s.prevProcUser
  42. sysTotal = sysKernelDiff + sysUserDiff
  43. procTotal = procKernelDiff + procUserDiff
  44. # total CPU usage < 85% --> create a new worker thread.
  45. # Measurements show that 100% and often even 90% is not reached even
  46. # if all my cores are busy.
  47. if sysTotal == 0 or procTotal.float / sysTotal.float < 0.85:
  48. result = doCreateThread
  49. s.prevSysKernel = sysKernel
  50. s.prevSysUser = sysUser
  51. s.prevProcKernel = procKernel
  52. s.prevProcUser = procUser
  53. elif defined(linux):
  54. proc fscanf(c: File, frmt: cstring) {.varargs, importc,
  55. header: "<stdio.h>".}
  56. var f: File
  57. if f.open("/proc/loadavg"):
  58. var b: float
  59. var busy, total: int
  60. fscanf(f,"%lf %lf %lf %ld/%ld",
  61. addr b, addr b, addr b, addr busy, addr total)
  62. f.close()
  63. let cpus = countProcessors()
  64. if busy-1 < cpus:
  65. result = doCreateThread
  66. elif busy-1 >= cpus*2:
  67. result = doShutdownThread
  68. else:
  69. result = doNothing
  70. else:
  71. result = doNothing
  72. else:
  73. # XXX implement this for other OSes
  74. result = doNothing
  75. inc s.calls
  76. when not defined(testing) and isMainModule and not defined(nimdoc):
  77. import random
  78. proc busyLoop() =
  79. while true:
  80. discard random(80)
  81. os.sleep(100)
  82. spawn busyLoop()
  83. spawn busyLoop()
  84. spawn busyLoop()
  85. spawn busyLoop()
  86. var s: ThreadPoolState
  87. for i in 1 .. 70:
  88. echo advice(s)
  89. os.sleep(1000)