wmic.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. 'use strict'
  2. const os = require('os')
  3. const bin = require('./bin')
  4. const history = require('./history')
  5. function parseDate (datestr) {
  6. const year = datestr.substring(0, 4)
  7. const month = datestr.substring(4, 6)
  8. const day = datestr.substring(6, 8)
  9. const hour = datestr.substring(8, 10)
  10. const minutes = datestr.substring(10, 12)
  11. const seconds = datestr.substring(12, 14)
  12. const useconds = datestr.substring(15, 21)
  13. const sign = datestr.substring(21, 22)
  14. const tmz = parseInt(datestr.substring(22, 25), 10)
  15. const tmzh = Math.floor(tmz / 60)
  16. const tmzm = tmz % 60
  17. return new Date(
  18. year + '-' + month + '-' + day + 'T' + hour +
  19. ':' + minutes + ':' + seconds +
  20. '.' + useconds +
  21. sign + (tmzh > 9 ? tmzh : '0' + tmzh) + '' + (tmzm > 9 ? tmzm : '0' + tmzm)
  22. )
  23. }
  24. /**
  25. * Get pid informations through wmic command.
  26. * @param {Number[]} pids
  27. * @param {Object} options
  28. * @param {Function} done(err, stat)
  29. */
  30. function wmic (pids, options, done) {
  31. let whereClause = 'ProcessId=' + pids[0]
  32. for (let i = 1; i < pids.length; i++) {
  33. whereClause += ' or ' + 'ProcessId=' + pids[i]
  34. }
  35. const args = [
  36. 'PROCESS',
  37. 'where',
  38. '"' + whereClause + '"',
  39. 'get',
  40. 'CreationDate,KernelModeTime,ParentProcessId,ProcessId,UserModeTime,WorkingSetSize'
  41. ]
  42. bin('wmic', args, { windowsHide: true, windowsVerbatimArguments: true }, function (err, stdout, code) {
  43. if (err) {
  44. if (err.message.indexOf('No Instance(s) Available.') !== -1) {
  45. const error = new Error('No matching pid found')
  46. error.code = 'ENOENT'
  47. return done(error)
  48. }
  49. return done(err)
  50. }
  51. if (code !== 0) {
  52. return done(new Error('pidusage wmic command exited with code ' + code))
  53. }
  54. const date = Date.now()
  55. // Note: On Windows the returned value includes fractions of a second.
  56. // Use Math.floor() to get whole seconds.
  57. // Fallback on current date when uptime is not allowed (see https://github.com/soyuka/pidusage/pull/130)
  58. const uptime = Math.floor(os.uptime() || (date / 1000))
  59. // Example of stdout on Windows 10
  60. // CreationDate: is in the format yyyymmddHHMMSS.mmmmmmsUUU
  61. // KernelModeTime: is in units of 100 ns
  62. // UserModeTime: is in units of 100 ns
  63. // WorkingSetSize: is in bytes
  64. //
  65. // Refs: https://superuser.com/a/937401/470946
  66. // Refs: https://msdn.microsoft.com/en-us/library/aa394372(v=vs.85).aspx
  67. // NB: The columns are returned in lexicographical order
  68. //
  69. // CreationDate KernelModeTime ParentProcessId ProcessId UserModeTime WorkingSetSize
  70. // 20150329221650.080654+060 153750000 0 777 8556250000 110821376
  71. stdout = stdout.split(os.EOL)
  72. let again = false
  73. const statistics = {}
  74. for (let i = 1; i < stdout.length; i++) {
  75. const line = stdout[i].trim().split(/\s+/)
  76. if (!line || line.length !== 6) {
  77. continue
  78. }
  79. const creation = parseDate(line[0])
  80. const ppid = parseInt(line[2], 10)
  81. const pid = parseInt(line[3], 10)
  82. const kerneltime = Math.round(parseInt(line[1], 10) / 10000)
  83. const usertime = Math.round(parseInt(line[4], 10) / 10000)
  84. const memory = parseInt(line[5], 10)
  85. let hst = history.get(pid, options.maxage)
  86. if (hst === undefined) {
  87. again = true
  88. hst = { ctime: kerneltime + usertime, uptime: uptime }
  89. }
  90. // process usage since last call
  91. const total = (kerneltime + usertime - hst.ctime) / 1000
  92. // time elapsed between calls in seconds
  93. const seconds = uptime - hst.uptime
  94. const cpu = seconds > 0 ? (total / seconds) * 100 : 0
  95. history.set(pid, { ctime: usertime + kerneltime, uptime: uptime }, options.maxage)
  96. statistics[pid] = {
  97. cpu: cpu,
  98. memory: memory,
  99. ppid: ppid,
  100. pid: pid,
  101. ctime: usertime + kerneltime,
  102. elapsed: date - creation.getTime(),
  103. timestamp: date
  104. }
  105. }
  106. if (again) {
  107. return wmic(pids, options, function (err, stats) {
  108. if (err) return done(err)
  109. done(null, Object.assign(statistics, stats))
  110. })
  111. }
  112. done(null, statistics)
  113. })
  114. }
  115. module.exports = wmic