ps.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. 'use strict'
  2. const os = require('os')
  3. const bin = require('./bin')
  4. const history = require('./history')
  5. const PLATFORM = os.platform()
  6. function parseTime (timestr, centisec) {
  7. let time = 0
  8. const tpart = timestr.split(/-|:|\./)
  9. let i = tpart.length - 1
  10. if (i >= 0 && centisec && PLATFORM === 'darwin') {
  11. time += parseInt(tpart[i--], 10) * 10
  12. }
  13. if (i >= 0) { // Seconds
  14. time += parseInt(tpart[i--], 10) * 1000
  15. }
  16. if (i >= 0) { // Minutes
  17. time += parseInt(tpart[i--], 10) * 60000
  18. }
  19. if (i >= 0) { // Hours
  20. time += parseInt(tpart[i--], 10) * 3600000
  21. }
  22. if (i >= 0) { // Days
  23. time += parseInt(tpart[i--], 10) * 86400000
  24. }
  25. return time
  26. }
  27. /**
  28. * Get pid informations through ps command.
  29. * @param {Number[]} pids
  30. * @param {Object} options
  31. * @param {Function} done(err, stat)
  32. */
  33. function ps (pids, options, done) {
  34. const pArg = pids.join(',')
  35. let args = ['-o', 'etime,pid,ppid,pcpu,rss,time', '-p', pArg]
  36. if (PLATFORM === 'aix') {
  37. args = ['-o', 'etime,pid,ppid,pcpu,rssize,time', '-p', pArg]
  38. }
  39. bin('ps', args, function (err, stdout, code) {
  40. if (err) {
  41. if (PLATFORM === 'os390' && /no matching processes found/.test(err)) {
  42. err = new Error('No matching pid found')
  43. err.code = 'ENOENT'
  44. }
  45. return done(err)
  46. }
  47. if (code === 1) {
  48. const error = new Error('No matching pid found')
  49. error.code = 'ENOENT'
  50. return done(error)
  51. }
  52. if (code !== 0) {
  53. return done(new Error('pidusage ps command exited with code ' + code))
  54. }
  55. const date = Date.now()
  56. // Example of stdout on *nix.
  57. // ELAPSED: format is [[dd-]hh:]mm:ss
  58. // RSS: is counted as blocks of 1024 bytes
  59. // TIME: format is [[dd-]hh:]mm:ss
  60. // %CPU: goes from 0 to vcore * 100
  61. //
  62. // Refs: http://www.manpages.info/linux/ps.1.html
  63. // NB: The columns are returned in the order given inside the -o option
  64. //
  65. // ELAPSED PID PPID %CPU RSS TIME
  66. // 2-40:50:53 430 1 3.0 5145 1-02:03:04
  67. // 40:50:53 432 430 0.0 2364 1-01:02:03
  68. // 01:50:50 727 1 10.0 348932 14:27
  69. // 00:20 7166 1 0.1 3756 0:00
  70. // Example of stdout on Darwin
  71. // ELAPSED: format is [[dd-]hh:]mm:ss
  72. // RSS: is counted as blocks of 1024 bytes
  73. // TIME: format is [[dd-]hh:]mm:ss.cc (cc are centiseconds)
  74. // %CPU: goes from 0 to vcore * 100
  75. //
  76. // Refs: https://ss64.com/osx/ps.html
  77. // NB: The columns are returned in the order given inside the -o option
  78. //
  79. // ELAPSED PID PPID %CPU RSS TIME
  80. // 2-40:50:53 430 1 3.0 5145 1-02:03:04.07
  81. // 40:50:53 432 430 0.0 2364 1-01:02:03.10
  82. // 01:50:50 727 1 10.0 348932 14:27.26
  83. // 00:20 7166 1 0.1 3756 0:00.02
  84. stdout = stdout.split(os.EOL)
  85. const statistics = {}
  86. for (let i = 1; i < stdout.length; i++) {
  87. const line = stdout[i].trim().split(/\s+/)
  88. if (!line || line.length !== 6) {
  89. continue
  90. }
  91. const pid = parseInt(line[1], 10)
  92. let hst = history.get(pid, options.maxage)
  93. if (hst === undefined) hst = {}
  94. const ppid = parseInt(line[2], 10)
  95. const memory = parseInt(line[4], 10) * 1024
  96. const etime = parseTime(line[0])
  97. const ctime = parseTime(line[5], true)
  98. const total = (ctime - (hst.ctime || 0))
  99. // time elapsed between calls in seconds
  100. const seconds = Math.abs(hst.elapsed !== undefined ? etime - hst.elapsed : etime)
  101. const cpu = seconds > 0 ? (total / seconds) * 100 : 0
  102. statistics[pid] = {
  103. cpu: cpu,
  104. memory: memory,
  105. ppid: ppid,
  106. pid: pid,
  107. ctime: ctime,
  108. elapsed: etime,
  109. timestamp: date
  110. }
  111. history.set(pid, statistics[pid], options.maxage)
  112. }
  113. done(null, statistics)
  114. })
  115. }
  116. module.exports = ps