cpuload.nim 2.8 KB

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