Repository: soyuka/pidusage
Branch: main
Commit: 36383b8d70c2
Files: 32
Total size: 62.8 KB
Directory structure:
gitextract_s94v4rqx/
├── .github/
│ └── workflows/
│ ├── alpine.yml
│ ├── lint.yml
│ ├── macos.yml
│ ├── test.yml
│ └── windows.yml
├── .gitignore
├── CHANGELOG.md
├── Dockerfile
├── LICENSE
├── README.md
├── examples/
│ ├── README.md
│ ├── server.js
│ └── stresstest.js
├── index.js
├── lib/
│ ├── bin.js
│ ├── gwmi.js
│ ├── helpers/
│ │ ├── cpu.js
│ │ └── parallel.js
│ ├── history.js
│ ├── procfile.js
│ ├── ps.js
│ ├── stats.js
│ └── wmic.js
├── package.json
└── test/
├── bench.js
├── fixtures/
│ └── _eventloop.js
├── gwmi.js
├── helpers/
│ └── _mocks.js
├── integration.js
├── procfile.js
├── ps.js
└── wmic.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/workflows/alpine.yml
================================================
name: test-alpine
on:
push:
branches: '*'
pull_request:
branches: '*'
jobs:
test:
runs-on: ubuntu-latest
name: Test alpine
steps:
- uses: actions/checkout@v2
- run: |
docker build . -t pidusage
docker run -v $(pwd):/var/pidusage pidusage:latest npm install
docker run -v $(pwd):/var/pidusage pidusage:latest npm test
================================================
FILE: .github/workflows/lint.yml
================================================
name: lint
on:
push:
branches: '*'
pull_request:
branches: '*'
jobs:
lint:
runs-on: ubuntu-latest
name: Lint
steps:
- name: Setup repo
uses: actions/checkout@v2
- name: Setup node
uses: actions/setup-node@v1
- name: Install dev dependencies
run: |
npm install --only=dev
- name: Run lint
run: npm run lint
================================================
FILE: .github/workflows/macos.yml
================================================
name: test-macos
on:
push:
branches: '*'
pull_request:
branches: '*'
jobs:
test:
runs-on: macos-latest
name: Test MacOS
steps:
- uses: actions/checkout@v2
- name: Setup node
uses: actions/setup-node@v2
- run: npm install
- run: npm test
================================================
FILE: .github/workflows/test.yml
================================================
name: linux
on:
push:
branches: '*'
pull_request:
branches: '*'
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node: [ '18', '20', '22', '23' ]
name: Test Node ${{ matrix.node }}
steps:
- uses: actions/checkout@v2
- name: Setup node
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node }}
- run: npm install
- run: npm test
coverage:
runs-on: ubuntu-latest
name: Test coverage
steps:
- uses: actions/checkout@v2
- name: Setup node
uses: actions/setup-node@v2
- run: npm install
- run: npm run coverage
- uses: codecov/codecov-action@v5
================================================
FILE: .github/workflows/windows.yml
================================================
name: test-windows
on:
push:
branches: '*'
pull_request:
branches: '*'
jobs:
test:
runs-on: windows-latest
name: Test Windows
steps:
- uses: actions/checkout@v2
- name: Setup node
uses: actions/setup-node@v2
- run: npm install
- run: npm test
================================================
FILE: .gitignore
================================================
node_modules
.nyc_output
coverage
================================================
FILE: CHANGELOG.md
================================================
### 4.0.1
- fix spawned wmic processes not exiting after wmic/gwmi detection in packaged apps, leading to infinite build up of "WMI Commandline Utility" processes and system instability
### 4.0.0
- fix wmic removed on Windows 11 and add gwmi support
- node >= 17
### 3.0.1
- removed dynamic requires to allow for bundling #154
- add ibm platform (os400) #158
### 3.0
- removes node 8 support
- add z/OS (os390) support
- environment variables to configure pidusage (`PIDUSAGE_USE_PS`, `PIDUSAGE_MAXAGE`, `PIDUSAGE_SILENT`)
- use a default Date when `uptime` returns `undefined`
### 2.0.17
- allow to manually clear the event loop when needed it'll clear itself after a given timeout (default to `60000ms` but you can specify it with the `maxage` option, [see this file](https://github.com/soyuka/pidusage/blob/master/test/fixtures/eventloop.js#L3)) [1740a4f](https://github.com/soyuka/pidusage/commit/2779e520d3414a8318c86279cf14bebae3264604)
- fix elapsed and timestamp calculations on linux [#80](https://github.com/soyuka/pidusage/issues/80) [e5e2b01](https://github.com/soyuka/pidusage/commit/081984a04bc97ad8abd82315f936861cce1df0d6)
### 2.0.16
- fix ps on darwin, centisenconds multiplier was wrong and was giving bad cpu usage values [bcda538](https://github.com/soyuka/pidusage/commit/bcda538b76498c6d4bcaa36520238990554929c5)
### 2.0.15
- Fix Buffer.alloc for node < 4.5
### 2.0.14
- Version unpublished because of a publish mistake from my part due to a npm error message that confused me. Explanation [in isse #71](https://github.com/soyuka/pidusage/issues/72#issuecomment-407572581)
### 2.0.12
- fix #69 with `ps` use elapsed instead of etime to avoid negative cpu values [0994268](https://github.com/soyuka/pidusage/commit/0994268c297e23efa3d9052f24cbacf2cbe31629)
- fix typo in aix `ps` command #68 [7d55518](https://github.com/soyuka/pidusage/commit/7d55518b7d5d5aae964e64ddd7b13ecec75463a1)
### 2.0.10
- aix is using ps (was changed by mistake), still no aix CI though
- add alpine to the test suite and make it use procfile
- Improve procfile performances by keeping the procfile open [da1c5fb](https://github.com/soyuka/pidusage/commit/da1c5fb2480bdf8f871476d79161dac7733b89f3)
### 2.0.8
- After further discussion cpu formula got reverted to the initial one [f990f72](https://github.com/soyuka/pidusage/commit/f990f72fd185e4ba0a87048e6e6c59f814a016cc)
### 2.0.7
- Cpu formula changed a bit because of multi thread issues see [issue #58](https://github.com/soyuka/pidusage/issues/58) [88972d8](https://github.com/soyuka/pidusage/commit/88972d8cd38d4137b70261a830af22283b69c57c)
### 2.0.6
- procfiles are back because of performance issues [85e20fa](https://github.com/soyuka/pidusage/commit/85e20fa30aa9ff01d87d3ba9be7fec7f805fc5fb)
### 2.0
- allow multiple pids
- remove `advanced` option
- don't use `/proc` (procfiles) anymore but use `ps` instead
- more tests
- API change no more `stat` method, module exports a single function
- no more `unmonitor` method, this is handed internally
- the default call now returns more data:
```
{
cpu: 10.0, // percentage (it may happen to be greater than 100%)
memory: 357306368, // bytes
ppid: 312, // PPID
pid: 727, // PID
ctime: 867000, // ms user + system time
elapsed: 6650000, // ms since the start of the process
timestamp: 864000000 // ms since epoch
}
```
### 1.2.0
Introduce `advanced` option to get time, and start
### 1.1.0
Windows: (wmic) goes back to the first version of wmic, naming `wmic process {pid} get workingsetsize,usermodetime,kernelmodetime`. CPU usage % is computed on the flight, per pid.
### 1.0.5
Windows: (wmic) Use raw data instead of formatted this should speed up wmic
### 0.1.0
API changes:
```
require('pidusage').stat(pid, fn)
```
instead of:
```
require('pidusage')(pid, fn)
```
Adds a `unmonitor` method to clear process history
================================================
FILE: Dockerfile
================================================
FROM node:alpine
RUN mkdir -p /var/pidusage
WORKDIR /var/pidusage
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2014 soyuka
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# pidusage
[](https://github.com/soyuka/pidusage/actions?query=workflow:lint+branch:main)
[](https://github.com/soyuka/pidusage/actions?query=workflow:test-macos+branch:main)
[](https://github.com/soyuka/pidusage/actions?query=workflow:linux+branch:main)
[](https://github.com/soyuka/pidusage/actions?query=workflow:test-windows+branch:main)
[](https://github.com/soyuka/pidusage/actions?query=workflow:test-alpine+branch:main)
[](https://codecov.io/gh/soyuka/pidusage)
[](https://www.npmjs.com/package/pidusage)
[](https://github.com/soyuka/pidusage/tree/master/license)
Cross-platform process cpu % and memory usage of a PID.
## Synopsis
Ideas from https://github.com/arunoda/node-usage but with no C-bindings.
Please note that if you need to check a Node.JS script process cpu and memory usage, you can use [`process.cpuUsage`][node:cpuUsage] and [`process.memoryUsage`][node:memUsage] since node v6.1.0. This script remain useful when you have no control over the remote script, or if the process is not a Node.JS process.
## Usage
```js
var pidusage = require('pidusage')
pidusage(process.pid, function (err, stats) {
console.log(stats)
// => {
// cpu: 10.0, // percentage (from 0 to 100*vcore)
// memory: 357306368, // bytes
// ppid: 312, // PPID
// pid: 727, // PID
// ctime: 867000, // ms user + system time
// elapsed: 6650000, // ms since the start of the process
// timestamp: 864000000 // ms since epoch
// }
cb()
})
// It supports also multiple pids
pidusage([727, 1234], function (err, stats) {
console.log(stats)
// => {
// 727: {
// cpu: 10.0, // percentage (from 0 to 100*vcore)
// memory: 357306368, // bytes
// ppid: 312, // PPID
// pid: 727, // PID
// ctime: 867000, // ms user + system time
// elapsed: 6650000, // ms since the start of the process
// timestamp: 864000000 // ms since epoch
// },
// 1234: {
// cpu: 0.1, // percentage (from 0 to 100*vcore)
// memory: 3846144, // bytes
// ppid: 727, // PPID
// pid: 1234, // PID
// ctime: 0, // ms user + system time
// elapsed: 20000, // ms since the start of the process
// timestamp: 864000000 // ms since epoch
// }
// }
})
// If no callback is given it returns a promise instead
const stats = await pidusage(process.pid)
console.log(stats)
// => {
// cpu: 10.0, // percentage (from 0 to 100*vcore)
// memory: 357306368, // bytes
// ppid: 312, // PPID
// pid: 727, // PID
// ctime: 867000, // ms user + system time
// elapsed: 6650000, // ms since the start of the process
// timestamp: 864000000 // ms since epoch
// }
// Avoid using setInterval as they could overlap with asynchronous processing
function compute(cb) {
pidusage(process.pid, function (err, stats) {
console.log(stats)
// => {
// cpu: 10.0, // percentage (from 0 to 100*vcore)
// memory: 357306368, // bytes
// ppid: 312, // PPID
// pid: 727, // PID
// ctime: 867000, // ms user + system time
// elapsed: 6650000, // ms since the start of the process
// timestamp: 864000000 // ms since epoch
// }
cb()
})
}
function interval(time) {
setTimeout(function() {
compute(function() {
interval(time)
})
}, time)
}
// Compute statistics every second:
interval(1000)
// Above example using async/await
const compute = async () => {
const stats = await pidusage(process.pid)
// do something
}
// Compute statistics every second:
const interval = async (time) => {
setTimeout(async () => {
await compute()
interval(time)
}, time)
}
interval(1000)
```
## Compatibility
| Property | Linux | FreeBSD | NetBSD | SunOS | macOS | Win | AIX | Alpine
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| `cpu` | ✅ | ❓ | ❓ | ❓ | ✅ | ℹ️ | ❓ | ✅ |
| `memory` | ✅ | ❓ | ❓ | ❓ | ✅ | ✅ | ❓ | ✅ |
| `pid` | ✅ | ❓ | ❓ | ❓ | ✅ | ✅ | ❓ | ✅ |
| `ctime` | ✅ | ❓ | ❓ | ❓ | ✅ | ✅ | ❓ | ✅ |
| `elapsed` | ✅ | ❓ | ❓ | ❓ | ✅ | ✅ | ❓ | ✅ |
| `timestamp` | ✅ | ❓ | ❓ | ❓ | ✅ | ✅ | ❓ | ✅ |
✅ = Working
ℹ️ = Not Accurate
❓ = Should Work
❌ = Not Working
Please if your platform is not supported or if you have reported wrong readings
[file an issue][new issue].
By default, pidusage will use `procfile` parsing on most unix systems. If you want to use `ps` instead use the `usePs` option:
```
pidusage(pid, {usePs: true})
```
## API
<a name="pidusage"></a>
### pidusage(pids, [options = {}], [callback]) ⇒ <code>[Promise.<Object>]</code>
Get pid informations.
**Kind**: global function
**Returns**: <code>Promise.<Object></code> - Only when the callback is not provided.
**Access**: public
| Param | Type | Description |
| --- | --- | --- |
| pids | <code>Number</code> \| <code>Array.<Number></code> \| <code>String</code> \| <code>Array.<String></code> | A pid or a list of pids. |
| [options] | <code>object</code> | Options object. See the table below. |
| [callback] | <code>function</code> | Called when the statistics are ready. If not provided a promise is returned instead. |
### options
Setting the options programatically will override environment variables
| Param | Type | Environment variable | Default | Description |
| --- | --- | --- | --- | --- |
| [usePs] | <code>boolean</code> | `PIDUSAGE_USE_PS`| `false` | When true uses `ps` instead of proc files to fetch process information |
| [maxage] | <code>number</code> | `PIDUSAGE_MAXAGE`| `60000` | Max age of a process on history. |
`PIDUSAGE_SILENT=1` can be used to remove every console message triggered by pidusage.
### pidusage.clear()
If needed this function can be used to delete all in-memory metrics and clear the event loop. This is not necessary before exiting as the interval we're registring does not hold up the event loop.
## Related
- [pidusage-tree][gh:pidusage-tree] -
Compute a pidusage tree
## Authors
- **Antoine Bluchet** - [soyuka][github:soyuka]
- **Simone Primarosa** - [simonepri][github:simonepri]
See also the list of [contributors][contributors] who participated in this project.
## License
This project is licensed under the MIT License - see the [LICENSE][license] file for details.
<!-- Links -->
[new issue]: https://github.com/soyuka/pidusage/issues/new
[license]: https://github.com/soyuka/pidusage/tree/master/LICENSE
[contributors]: https://github.com/soyuka/pidusage/contributors
[github:soyuka]: https://github.com/soyuka
[github:simonepri]: https://github.com/simonepri
[gh:pidusage-tree]: https://github.com/soyuka/pidusage-tree
[node:cpuUsage]: https://nodejs.org/api/process.html#process_process_cpuusage_previousvalue
[node:memUsage]: https://nodejs.org/api/process.html#process_process_memoryusage
================================================
FILE: examples/README.md
================================================
# Example section
## server.js
Used to be tested with an HTTP benchmark tool like this one: https://github.com/wg/wrk.
Start the server, run the tests on `localhost:8020`
## stresstest.js
Just start node stresstest.js (but be carefull though...)
================================================
FILE: examples/server.js
================================================
const http = require('http')
const pidusage = require('../')
http.createServer(function (req, res) {
res.writeHead(200)
res.end('hello world\n')
}).listen(8020)
const interval = setInterval(function () {
pidusage(process.pid, function (err, stat) {
if (err) {
throw err
}
console.log(stat)
})
}, 100)
process.on('exit', function () {
clearInterval(interval)
})
================================================
FILE: examples/stresstest.js
================================================
const pusage = require('../')
// stress test to compare with top or another tool
console.log('This is my PID: %s', process.pid)
// classic "drop somewhere"... yeah I'm a lazy guy
const formatBytes = function (bytes, precision) {
const kilobyte = 1024
const megabyte = kilobyte * 1024
const gigabyte = megabyte * 1024
const terabyte = gigabyte * 1024
if ((bytes >= 0) && (bytes < kilobyte)) {
return bytes + ' B '
} else if ((bytes >= kilobyte) && (bytes < megabyte)) {
return (bytes / kilobyte).toFixed(precision) + ' KB '
} else if ((bytes >= megabyte) && (bytes < gigabyte)) {
return (bytes / megabyte).toFixed(precision) + ' MB '
} else if ((bytes >= gigabyte) && (bytes < terabyte)) {
return (bytes / gigabyte).toFixed(precision) + ' GB '
} else if (bytes >= terabyte) {
return (bytes / terabyte).toFixed(precision) + ' TB '
} else {
return bytes + ' B '
}
}
let i = 0
const bigMemoryLeak = []
const stress = function (cb) {
let j = 500
const arr = []
while (j--) {
arr[j] = []
for (let k = 0; k < 1000; k++) {
arr[j][k] = { lorem: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum non odio venenatis, pretium ligula nec, fringilla ipsum. Sed a erat et sem blandit dignissim. Pellentesque sollicitudin felis eu mattis porta. Nullam nec nibh nisl. Phasellus convallis vulputate massa vitae fringilla. Etiam facilisis lectus in odio lacinia rutrum. Praesent facilisis vitae urna a suscipit. Aenean lacinia blandit lorem, et ullamcorper metus sagittis faucibus. Nam porta eros nisi, at adipiscing quam varius eu. Vivamus sed sem quis lorem varius posuere ut quis elit.' }
}
}
bigMemoryLeak.push(arr)
pusage(process.pid, function (err, stat) {
if (err) {
throw err
}
console.log('Pcpu: %s', stat.cpu)
console.log('Mem: %s', formatBytes(stat.memory))
if (i === 100) {
return cb(null, true)
} else if (stat.memory > 3e8) {
console.log("That's enough right?")
cb(null, true)
}
i++
return cb(null, false)
})
}
const interval = function () {
return setTimeout(function () {
stress(function (err, stop) {
if (err) {
throw err
}
if (stop) {
process.exit()
} else {
return interval()
}
})
}, 400)
}
setTimeout(function () {
interval()
}, 2000)
================================================
FILE: index.js
================================================
'use strict'
const stats = require('./lib/stats')
/**
* Get pid informations.
* @public
* @param {Number|Number[]|String|String[]} pids A pid or a list of pids.
* @param {Object} [options={}] Options object
* @param {Function} [callback=undefined] Called when the statistics are ready.
* If not provided a promise is returned instead.
* @returns {Promise.<Object>} Only when the callback is not provided.
*/
function pidusage (pids, options, callback) {
if (typeof options === 'function') {
callback = options
options = {}
}
if (options === undefined) {
options = {}
}
options = Object.assign({
usePs: /^true$/i.test(process.env.PIDUSAGE_USE_PS),
maxage: process.env.PIDUSAGE_MAXAGE
}, options)
if (typeof callback === 'function') {
stats(pids, options, callback)
return
}
return new Promise(function (resolve, reject) {
stats(pids, options, function (err, data) {
if (err) return reject(err)
resolve(data)
})
})
}
module.exports = pidusage
module.exports.clear = require('./lib/history').clear
================================================
FILE: lib/bin.js
================================================
'use strict'
const spawn = require('child_process').spawn
/**
* Spawn a binary and read its stdout.
* @param {String} cmd
* @param {String[]} args
* @param {Function} done(err, stdout)
*/
function run (cmd, args, options, done) {
if (typeof options === 'function') {
done = options
options = undefined
}
let executed = false
const ch = spawn(cmd, args, options)
let stdout = ''
let stderr = ''
ch.stdout.on('data', function (d) {
stdout += d.toString()
})
ch.stderr.on('data', function (d) {
stderr += d.toString()
})
ch.on('error', function (err) {
if (executed) return
executed = true
done(new Error(err))
})
ch.on('close', function (code, signal) {
if (executed) return
executed = true
if (stderr) {
return done(new Error(stderr))
}
done(null, stdout, code)
})
}
module.exports = run
================================================
FILE: lib/gwmi.js
================================================
'use strict'
const os = require('os')
const bin = require('./bin')
const history = require('./history')
function parseDate (datestr) {
const year = datestr.substring(0, 4)
const month = datestr.substring(4, 6)
const day = datestr.substring(6, 8)
const hour = datestr.substring(8, 10)
const minutes = datestr.substring(10, 12)
const seconds = datestr.substring(12, 14)
const useconds = datestr.substring(15, 21)
const sign = datestr.substring(21, 22)
const tmz = parseInt(datestr.substring(22, 25), 10)
const tmzh = Math.floor(tmz / 60)
const tmzm = tmz % 60
return new Date(
year + '-' + month + '-' + day + 'T' + hour +
':' + minutes + ':' + seconds +
'.' + useconds +
sign + (tmzh > 9 ? tmzh : '0' + tmzh) + '' + (tmzm > 9 ? tmzm : '0' + tmzm)
)
}
function gwmi (pids, options, done) {
let whereClause = 'ProcessId=' + pids[0]
for (let i = 1; i < pids.length; i++) {
whereClause += ' or ' + 'ProcessId=' + pids[i]
}
const property = 'CreationDate,KernelModeTime,ParentProcessId,ProcessId,UserModeTime,WorkingSetSize'
const args = ['win32_process', '-Filter', '\'' + whereClause + '\'', '| select ' + property, '| format-table']
bin('gwmi', args, { windowsHide: true, windowsVerbatimArguments: true, shell: 'powershell.exe' }, function (err, stdout, code) {
if (err) {
if (err.message.indexOf('No Instance(s) Available.') !== -1) {
const error = new Error('No matching pid found')
error.code = 'ENOENT'
return done(error)
}
return done(err)
}
if (code !== 0) {
return done(new Error('pidusage gwmi command exited with code ' + code))
}
const date = Date.now()
// Note: On Windows the returned value includes fractions of a second.
// Use Math.floor() to get whole seconds.
// Fallback on current date when uptime is not allowed (see https://github.com/soyuka/pidusage/pull/130)
const uptime = Math.floor(os.uptime() || (date / 1000))
// Example of stdout on Windows 10
// CreationDate: is in the format yyyymmddHHMMSS.mmmmmmsUUU
// KernelModeTime: is in units of 100 ns
// UserModeTime: is in units of 100 ns
// WorkingSetSize: is in bytes
//
// Refs: https://superuser.com/a/937401/470946
// Refs: https://msdn.microsoft.com/en-us/library/aa394372(v=vs.85).aspx
// NB: The columns are returned in lexicographical order
//
// Stdout Format
//
// Active code page: 936
//
// CreationDate KernelModeTime ParentProcessId ProcessId UserModeTime WorkingSetSize
// ------------ -------------- --------------- --------- ------------ --------------
// 20220220185531.619182+480 981406250 18940 2804 572656250 61841408
stdout = stdout.split(os.EOL).slice(1)
const index = stdout.findIndex(v => !!v)
stdout = stdout.slice(index + 2)
if (!stdout.length) {
const error = new Error('No matching pid found')
error.code = 'ENOENT'
return done(error)
}
let again = false
const statistics = {}
for (let i = 0; i < stdout.length; i++) {
const line = stdout[i].trim().split(/\s+/)
if (!line || line.length === 1) {
continue
}
const creation = parseDate(line[0])
const ppid = parseInt(line[2], 10)
const pid = parseInt(line[3], 10)
const kerneltime = Math.round(parseInt(line[1], 10) / 10000)
const usertime = Math.round(parseInt(line[4], 10) / 10000)
const memory = parseInt(line[5], 10)
let hst = history.get(pid, options.maxage)
if (hst === undefined) {
again = true
hst = { ctime: kerneltime + usertime, uptime: uptime }
}
// process usage since last call
const total = (kerneltime + usertime - hst.ctime) / 1000
// time elapsed between calls in seconds
const seconds = uptime - hst.uptime
const cpu = seconds > 0 ? (total / seconds) * 100 : 0
history.set(pid, { ctime: usertime + kerneltime, uptime: uptime }, options.maxage)
statistics[pid] = {
cpu: cpu,
memory: memory,
ppid: ppid,
pid: pid,
ctime: usertime + kerneltime,
elapsed: date - creation.getTime(),
timestamp: date
}
}
if (again) {
return gwmi(pids, options, function (err, stats) {
if (err) return done(err)
done(null, Object.assign(statistics, stats))
})
}
done(null, statistics)
})
}
module.exports = gwmi
================================================
FILE: lib/helpers/cpu.js
================================================
const os = require('os')
const fs = require('fs')
const exec = require('child_process').exec
const parallel = require('./parallel')
/**
* Gathers Clock, PageSize and system uptime through /proc/uptime
* This method is mocked in procfile tests
*/
function updateCpu (cpu, next) {
if (cpu !== null) {
getRealUptime(function (err, uptime) {
if (err) return next(err)
cpu.uptime = uptime
next(null, cpu)
})
return
}
parallel([
getClockAndPageSize,
getRealUptime
], function (err, data) {
if (err) return next(err)
cpu = {
clockTick: data[0].clockTick,
pageSize: data[0].pageSize,
uptime: data[1]
}
next(null, cpu)
})
}
module.exports = updateCpu
/**
* Fallback on os.uptime(), though /proc/uptime is more precise
*/
function getRealUptime (next) {
fs.readFile('/proc/uptime', 'utf8', function (err, uptime) {
if (err || uptime === undefined) {
if (!process.env.PIDUSAGE_SILENT) {
console.warn("[pidusage] We couldn't find uptime from /proc/uptime, using os.uptime() value")
}
return next(null, os.uptime() || (new Date() / 1000))
}
return next(null, parseFloat(uptime.split(' ')[0]))
})
}
function getClockAndPageSize (next) {
parallel([
function getClockTick (cb) {
getconf('CLK_TCK', { default: 100 }, cb)
},
function getPageSize (cb) {
getconf('PAGESIZE', { default: 4096 }, cb)
}
], function (err, data) {
if (err) return next(err)
next(null, { clockTick: data[0], pageSize: data[1] })
})
}
function getconf (keyword, options, next) {
if (typeof options === 'function') {
next = options
options = { default: '' }
}
exec('getconf ' + keyword, function (error, stdout, stderr) {
if (error !== null) {
if (!process.env.PIDUSAGE_SILENT) {
console.error('Error while calling "getconf ' + keyword + '"', error)
}
return next(null, options.default)
}
stdout = parseInt(stdout)
if (!isNaN(stdout)) {
return next(null, stdout)
}
return next(null, options.default)
})
}
================================================
FILE: lib/helpers/parallel.js
================================================
// execute an array of asynchronous functions in parallel
// @param {Array} fns - an array of functions
// @param {Function} done - callback(err, results)
function parallel (fns, options, done) {
if (typeof options === 'function') {
done = options
options = {}
}
let keys
if (!Array.isArray(fns)) { keys = Object.keys(fns) }
const length = keys ? keys.length : fns.length
let pending = length
const results = keys ? {} : []
function each (i, err, result) {
results[i] = result
if (--pending === 0 || (err && !options.graceful)) {
if (options.graceful && err && length > 1) {
err = null
}
done && done(err, results)
done = null
}
}
if (keys) {
keys.forEach(function (key) {
fns[key](function (err, res) {
each(key, err, res)
})
})
} else {
fns.forEach(function (fn, i) {
fn(function (err, res) {
each(i, err, res)
})
})
}
}
module.exports = parallel
================================================
FILE: lib/history.js
================================================
'use strict'
const DEFAULT_MAXAGE = 60000
const expiration = {}
const history = {}
const expireListeners = {}
let size = 0
let interval = null
function get (pid, maxage) {
if (maxage <= 0) {
return
}
if (history[pid] !== undefined) {
expiration[pid] = Date.now() + (maxage || DEFAULT_MAXAGE)
}
return history[pid]
}
function set (pid, object, maxage, onExpire) {
if (object === undefined || maxage <= 0) return
expiration[pid] = Date.now() + (maxage || DEFAULT_MAXAGE)
if (history[pid] === undefined) {
size++
sheduleInvalidator(maxage)
}
history[pid] = object
if (onExpire) {
expireListeners[pid] = onExpire
}
}
function sheduleInvalidator (maxage) {
if (size > 0) {
if (interval === null) {
interval = setInterval(runInvalidator, (maxage || DEFAULT_MAXAGE) / 2)
if (typeof interval.unref === 'function') {
interval.unref()
}
}
return
}
if (interval !== null) {
clearInterval(interval)
interval = null
}
}
function runInvalidator () {
const now = Date.now()
const pids = Object.keys(expiration)
for (let i = 0; i < pids.length; i++) {
const pid = pids[i]
if (expiration[pid] < now) {
size--
if (expireListeners[pid]) {
expireListeners[pid](history[pid])
}
delete history[pid]
delete expiration[pid]
delete expireListeners[pid]
}
}
sheduleInvalidator()
}
function deleteLoop (obj) { for (const i in obj) { delete obj[i] } }
function clear () {
if (interval !== null) {
clearInterval(interval)
interval = null
}
deleteLoop(history)
deleteLoop(expiration)
deleteLoop(expireListeners)
}
module.exports = {
get: get,
set: set,
clear: clear
}
================================================
FILE: lib/procfile.js
================================================
const fs = require('fs')
const path = require('path')
const updateCpu = require('./helpers/cpu')
const parallel = require('./helpers/parallel')
const history = require('./history')
let cpuInfo = null
const Buffer = require('safe-buffer').Buffer
const SIZE = 1024 // if the stat file is bigger then this I'll buy you a drink
function noop () {}
function open (path, history, cb) {
if (history.fd) { return cb(null, history.fd) }
fs.open(path, 'r', cb)
}
function close (history) {
if (history.fd) {
fs.close(history.fd, noop)
}
}
function readUntilEnd (fd, buf, cb) {
let firstRead = false
if (typeof buf === 'function') {
cb = buf
buf = Buffer.alloc(SIZE)
firstRead = true
}
fs.read(fd, buf, 0, SIZE, 0, function (err, bytesRead, buffer) {
if (err) {
cb(err)
return
}
const data = Buffer.concat([buf, buffer], firstRead ? bytesRead : buf.length + bytesRead)
if (bytesRead === SIZE) {
readUntilEnd(fd, data, cb)
return
}
cb(null, buf)
})
}
function readProcFile (pid, options, done) {
let hst = history.get(pid, options.maxage)
let again = false
if (hst === undefined) {
again = true
hst = {}
}
// Arguments to path.join must be strings
open(path.join('/proc', '' + pid, 'stat'), hst, function (err, fd) {
if (err) {
if (err.code === 'ENOENT') {
err.message = 'No matching pid found'
}
return done(err, null)
}
if (err) {
return done(err)
}
readUntilEnd(fd, function (err, buffer) {
if (err) {
return done(err)
}
let infos = buffer.toString('utf8')
const date = Date.now()
// https://github.com/arunoda/node-usage/commit/a6ca74ecb8dd452c3c00ed2bde93294d7bb75aa8
// preventing process space in name by removing values before last ) (pid (name) ...)
const index = infos.lastIndexOf(')')
infos = infos.substr(index + 2).split(' ')
// according to http://man7.org/linux/man-pages/man5/proc.5.html (index 0 based - 2)
// In kernels before Linux 2.6, start was expressed in jiffies. Since Linux 2.6, the value is expressed in clock ticks
const stat = {
ppid: parseInt(infos[1]),
utime: parseFloat(infos[11]) * 1000 / cpuInfo.clockTick,
stime: parseFloat(infos[12]) * 1000 / cpuInfo.clockTick,
cutime: parseFloat(infos[13]) * 1000 / cpuInfo.clockTick,
cstime: parseFloat(infos[14]) * 1000 / cpuInfo.clockTick,
start: parseFloat(infos[19]) * 1000 / cpuInfo.clockTick,
rss: parseFloat(infos[21]),
uptime: cpuInfo.uptime * 1000,
fd: fd
}
const memory = stat.rss * cpuInfo.pageSize
// https://stackoverflow.com/a/16736599/3921589
const childrens = options.childrens ? stat.cutime + stat.cstime : 0
// process usage since last call in seconds
const total = (stat.stime - (hst.stime || 0) + stat.utime - (hst.utime || 0) + childrens)
// time elapsed between calls in seconds
const seconds = Math.abs(hst.uptime !== undefined ? stat.uptime - hst.uptime : stat.start - stat.uptime)
const cpu = seconds > 0 ? (total / seconds) * 100 : 0
history.set(pid, stat, options.maxage, close)
if (again) {
return readProcFile(pid, options, done)
}
return done(null, {
cpu: cpu,
memory: memory,
ctime: stat.utime + stat.stime,
elapsed: stat.uptime - stat.start,
timestamp: date,
pid: pid,
ppid: stat.ppid
})
})
})
}
function procfile (pids, options, done) {
updateCpu(cpuInfo, function (err, result) {
if (err) return done(err)
cpuInfo = result
const fns = {}
pids.forEach(function (pid, i) {
fns[pid] = function (cb) {
readProcFile(pid, options, cb)
}
})
parallel(fns, { graceful: true }, done)
})
}
module.exports = procfile
================================================
FILE: lib/ps.js
================================================
'use strict'
const os = require('os')
const bin = require('./bin')
const history = require('./history')
const PLATFORM = os.platform()
function parseTime (timestr, centisec) {
let time = 0
const tpart = timestr.split(/-|:|\./)
let i = tpart.length - 1
if (i >= 0 && centisec && PLATFORM === 'darwin') {
time += parseInt(tpart[i--], 10) * 10
}
if (i >= 0) { // Seconds
time += parseInt(tpart[i--], 10) * 1000
}
if (i >= 0) { // Minutes
time += parseInt(tpart[i--], 10) * 60000
}
if (i >= 0) { // Hours
time += parseInt(tpart[i--], 10) * 3600000
}
if (i >= 0) { // Days
time += parseInt(tpart[i--], 10) * 86400000
}
return time
}
/**
* Get pid informations through ps command.
* @param {Number[]} pids
* @param {Object} options
* @param {Function} done(err, stat)
*/
function ps (pids, options, done) {
const pArg = pids.join(',')
let args = ['-o', 'etime,pid,ppid,pcpu,rss,time', '-p', pArg]
if (PLATFORM === 'aix' || PLATFORM === 'os400') {
args = ['-o', 'etime,pid,ppid,pcpu,rssize,time', '-p', pArg]
}
bin('ps', args, function (err, stdout, code) {
if (err) {
if (PLATFORM === 'os390' && /no matching processes found/.test(err)) {
err = new Error('No matching pid found')
err.code = 'ENOENT'
}
return done(err)
}
if (code === 1) {
const error = new Error('No matching pid found')
error.code = 'ENOENT'
return done(error)
}
if (code !== 0) {
return done(new Error('pidusage ps command exited with code ' + code))
}
const date = Date.now()
// Example of stdout on *nix.
// ELAPSED: format is [[dd-]hh:]mm:ss
// RSS: is counted as blocks of 1024 bytes
// TIME: format is [[dd-]hh:]mm:ss
// %CPU: goes from 0 to vcore * 100
//
// Refs: http://www.manpages.info/linux/ps.1.html
// NB: The columns are returned in the order given inside the -o option
//
// ELAPSED PID PPID %CPU RSS TIME
// 2-40:50:53 430 1 3.0 5145 1-02:03:04
// 40:50:53 432 430 0.0 2364 1-01:02:03
// 01:50:50 727 1 10.0 348932 14:27
// 00:20 7166 1 0.1 3756 0:00
// Example of stdout on Darwin
// ELAPSED: format is [[dd-]hh:]mm:ss
// RSS: is counted as blocks of 1024 bytes
// TIME: format is [[dd-]hh:]mm:ss.cc (cc are centiseconds)
// %CPU: goes from 0 to vcore * 100
//
// Refs: https://ss64.com/osx/ps.html
// NB: The columns are returned in the order given inside the -o option
//
// ELAPSED PID PPID %CPU RSS TIME
// 2-40:50:53 430 1 3.0 5145 1-02:03:04.07
// 40:50:53 432 430 0.0 2364 1-01:02:03.10
// 01:50:50 727 1 10.0 348932 14:27.26
// 00:20 7166 1 0.1 3756 0:00.02
stdout = stdout.split(os.EOL)
const statistics = {}
for (let i = 1; i < stdout.length; i++) {
const line = stdout[i].trim().split(/\s+/)
if (!line || line.length !== 6) {
continue
}
const pid = parseInt(line[1], 10)
let hst = history.get(pid, options.maxage)
if (hst === undefined) hst = {}
const ppid = parseInt(line[2], 10)
const memory = parseInt(line[4], 10) * 1024
const etime = parseTime(line[0])
const ctime = parseTime(line[5], true)
const total = (ctime - (hst.ctime || 0))
// time elapsed between calls in seconds
const seconds = Math.abs(hst.elapsed !== undefined ? etime - hst.elapsed : etime)
const cpu = seconds > 0 ? (total / seconds) * 100 : 0
statistics[pid] = {
cpu: cpu,
memory: memory,
ppid: ppid,
pid: pid,
ctime: ctime,
elapsed: etime,
timestamp: date
}
history.set(pid, statistics[pid], options.maxage)
}
done(null, statistics)
})
}
module.exports = ps
================================================
FILE: lib/stats.js
================================================
'use strict'
const fs = require('fs')
const os = require('os')
const spawn = require('child_process').spawn
const requireMap = {
ps: () => require('./ps'),
procfile: () => require('./procfile'),
wmic: () => require('./wmic'),
gwmi: () => require('./gwmi')
}
const platformToMethod = {
aix: 'ps',
os400: 'ps',
android: 'procfile',
alpine: 'procfile',
darwin: 'ps',
freebsd: 'ps',
os390: 'ps',
linux: 'procfile',
netbsd: 'procfile',
openbsd: 'ps',
sunos: 'ps',
win: 'wmic'
}
let platform = os.platform()
if (fs.existsSync('/etc/alpine-release')) {
platform = 'alpine'
}
if (platform.match(/^win/)) {
platform = 'win'
}
let stat
try {
stat = requireMap[platformToMethod[platform]]()
} catch (err) {}
/**
* @callback pidCallback
* @param {Error} err A possible error.
* @param {Object} statistics The object containing the statistics.
*/
/**
* Get pid informations.
* @public
* @param {Number|Number[]|String|String[]} pids A pid or a list of pids.
* @param {Object} [options={}] Options object
* @param {pidCallback} callback Called when the statistics are ready.
*/
function get (pids, options, callback) {
let fn = stat
if (platform !== 'win' && options.usePs === true) {
fn = requireMap.ps()
}
if (platform === 'win') {
// TODO: use https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/where to avoid try/catch
let child;
try {
child = spawn('wmic', function (err) {
if (err) throw new Error(err)
})
} catch (err) {
fn = requireMap.gwmi()
} finally {
if (child) {
child.kill()
}
}
}
if (fn === undefined) {
return callback(new Error(os.platform() + ' is not supported yet, please open an issue (https://github.com/soyuka/pidusage)'))
}
let single = false
if (!Array.isArray(pids)) {
single = true
pids = [pids]
}
if (pids.length === 0) {
return callback(new TypeError('You must provide at least one pid'))
}
for (let i = 0; i < pids.length; i++) {
pids[i] = parseInt(pids[i], 10)
if (isNaN(pids[i]) || pids[i] < 0) {
return callback(new TypeError('One of the pids provided is invalid'))
}
}
fn(pids, options, function (err, stats) {
if (err) {
return callback(err)
}
if (single) {
callback(null, stats[pids[0]])
} else {
callback(null, stats)
}
})
}
module.exports = get
================================================
FILE: lib/wmic.js
================================================
'use strict'
const os = require('os')
const bin = require('./bin')
const history = require('./history')
function parseDate (datestr) {
const year = datestr.substring(0, 4)
const month = datestr.substring(4, 6)
const day = datestr.substring(6, 8)
const hour = datestr.substring(8, 10)
const minutes = datestr.substring(10, 12)
const seconds = datestr.substring(12, 14)
const useconds = datestr.substring(15, 21)
const sign = datestr.substring(21, 22)
const tmz = parseInt(datestr.substring(22, 25), 10)
const tmzh = Math.floor(tmz / 60)
const tmzm = tmz % 60
return new Date(
year + '-' + month + '-' + day + 'T' + hour +
':' + minutes + ':' + seconds +
'.' + useconds +
sign + (tmzh > 9 ? tmzh : '0' + tmzh) + '' + (tmzm > 9 ? tmzm : '0' + tmzm)
)
}
/**
* Get pid informations through wmic command.
* @param {Number[]} pids
* @param {Object} options
* @param {Function} done(err, stat)
*/
function wmic (pids, options, done) {
let whereClause = 'ProcessId=' + pids[0]
for (let i = 1; i < pids.length; i++) {
whereClause += ' or ' + 'ProcessId=' + pids[i]
}
const args = [
'PROCESS',
'where',
'"' + whereClause + '"',
'get',
'CreationDate,KernelModeTime,ParentProcessId,ProcessId,UserModeTime,WorkingSetSize'
]
bin('wmic', args, { windowsHide: true, windowsVerbatimArguments: true }, function (err, stdout, code) {
if (err) {
if (err.message.indexOf('No Instance(s) Available.') !== -1) {
const error = new Error('No matching pid found')
error.code = 'ENOENT'
return done(error)
}
return done(err)
}
if (code !== 0) {
return done(new Error('pidusage wmic command exited with code ' + code))
}
const date = Date.now()
// Note: On Windows the returned value includes fractions of a second.
// Use Math.floor() to get whole seconds.
// Fallback on current date when uptime is not allowed (see https://github.com/soyuka/pidusage/pull/130)
const uptime = Math.floor(os.uptime() || (date / 1000))
// Example of stdout on Windows 10
// CreationDate: is in the format yyyymmddHHMMSS.mmmmmmsUUU
// KernelModeTime: is in units of 100 ns
// UserModeTime: is in units of 100 ns
// WorkingSetSize: is in bytes
//
// Refs: https://superuser.com/a/937401/470946
// Refs: https://msdn.microsoft.com/en-us/library/aa394372(v=vs.85).aspx
// NB: The columns are returned in lexicographical order
//
// CreationDate KernelModeTime ParentProcessId ProcessId UserModeTime WorkingSetSize
// 20150329221650.080654+060 153750000 0 777 8556250000 110821376
stdout = stdout.split(os.EOL)
let again = false
const statistics = {}
for (let i = 1; i < stdout.length; i++) {
const line = stdout[i].trim().split(/\s+/)
if (!line || line.length !== 6) {
continue
}
const creation = parseDate(line[0])
const ppid = parseInt(line[2], 10)
const pid = parseInt(line[3], 10)
const kerneltime = Math.round(parseInt(line[1], 10) / 10000)
const usertime = Math.round(parseInt(line[4], 10) / 10000)
const memory = parseInt(line[5], 10)
let hst = history.get(pid, options.maxage)
if (hst === undefined) {
again = true
hst = { ctime: kerneltime + usertime, uptime: uptime }
}
// process usage since last call
const total = (kerneltime + usertime - hst.ctime) / 1000
// time elapsed between calls in seconds
const seconds = uptime - hst.uptime
const cpu = seconds > 0 ? (total / seconds) * 100 : 0
history.set(pid, { ctime: usertime + kerneltime, uptime: uptime }, options.maxage)
statistics[pid] = {
cpu: cpu,
memory: memory,
ppid: ppid,
pid: pid,
ctime: usertime + kerneltime,
elapsed: date - creation.getTime(),
timestamp: date
}
}
if (again) {
return wmic(pids, options, function (err, stats) {
if (err) return done(err)
done(null, Object.assign(statistics, stats))
})
}
done(null, statistics)
})
}
module.exports = wmic
================================================
FILE: package.json
================================================
{
"name": "pidusage",
"version": "3.0.1",
"description": "Cross-platform process cpu % and memory usage of a PID",
"license": "MIT",
"homepage": "https://github.com/soyuka/pidusage",
"repository": "github:soyuka/pidusage",
"bugs": {
"url": "https://github.com/soyuka/pidusage/issues"
},
"author": "soyuka",
"contributors": [
"Simone Primarosa <simonepri@outlook.com> (https://simoneprimarosa.com)"
],
"main": "index.js",
"files": [
"lib",
"index.js"
],
"engines": {
"node": ">=18"
},
"scripts": {
"lint": "standard",
"test": "nyc ava -m \"!*benchmark*\"",
"coverage": "c8 ava",
"bench": "ava -m \"*benchmark*\""
},
"dependencies": {
"safe-buffer": "^5.2.1"
},
"devDependencies": {
"balanced-match": "^3.0.1",
"c8": "^10.1.3",
"ava": "^6.2.0",
"mockdate": "^2.0.5",
"mockery": "^2.1.0",
"nyc": "^15.1.0",
"pify": "^3.0.0",
"standard": "^16.0.4",
"string-to-stream": "^1.1.1",
"through": "^2.3.8",
"time-span": "^2.0.0"
},
"keywords": [
"pid",
"usage",
"ps",
"cpu",
"memory",
"proc"
],
"ava": {
"verbose": true,
"failWithoutAssertions": false
},
"nyc": {
"reporter": [
"lcovonly",
"text"
]
}
}
================================================
FILE: test/bench.js
================================================
const { spawn } = require('child_process')
const test = require('ava')
const tspan = require('time-span')
const m = require('..')
async function create (pidno) {
const code = `
console.log(process.pid);
setInterval(function(){}, 1000); // Does nothing, but prevents exit
`
let count = 0
const childs = []
return new Promise((resolve, reject) => {
for (let i = 0; i < pidno; i++) {
const child = spawn('node', ['-e', code], { windowsHide: true })
childs.push(child)
child.stdout.on('data', function (childs) {
if (++count === pidno) resolve(childs)
}.bind(this, childs))
child.stderr.on('data', function (data) {
reject(data.toString())
})
child.on('error', reject)
}
})
}
async function destroy (childs) {
childs.forEach(child => child.kill())
}
async function execute (childs, pidno, times, options = {}) {
const pids = childs.map(child => child.pid).slice(0, pidno)
const end = tspan()
try {
for (let i = 0; i < times; i++) {
await m(pids, options)
}
const time = end()
return Promise.resolve(time)
} catch (err) {
end()
return Promise.reject(err)
}
}
test.serial('should execute the benchmark', async t => {
const childs = await create(100)
let time = await execute(childs, 1, 100, { usePs: true })
t.log(`1 pid 100 times done in ${time.toFixed(3)} ms (${(1000 * 100 / time).toFixed(3)} op/s)`)
time = await execute(childs, 1, 100)
t.log(`(procfile) 1 pid 100 times done in ${time.toFixed(3)} ms (${(1000 * 100 / time).toFixed(3)} op/s)`)
time = await execute(childs, 2, 100, { usePs: true })
t.log(`2 pid 100 times done in ${time.toFixed(3)} ms (${(1000 * 100 / time).toFixed(3)} op/s)`)
time = await execute(childs, 2, 100)
t.log(`(procfile) 2 pid 100 times done in ${time.toFixed(3)} ms (${(1000 * 100 / time).toFixed(3)} op/s)`)
time = await execute(childs, 5, 100, { usePs: true })
t.log(`5 pid 100 times done in ${time.toFixed(3)} ms (${(1000 * 100 / time).toFixed(3)} op/s)`)
time = await execute(childs, 5, 100)
t.log(`(procfile) 5 pid 100 times done in ${time.toFixed(3)} ms (${(1000 * 100 / time).toFixed(3)} op/s)`)
time = await execute(childs, 10, 100, { usePs: true })
t.log(`10 pid 100 times done in ${time.toFixed(3)} ms (${(1000 * 100 / time).toFixed(3)} op/s)`)
time = await execute(childs, 10, 100)
t.log(`(procfile) 10 pid 100 times done in ${time.toFixed(3)} ms (${(1000 * 100 / time).toFixed(3)} op/s)`)
time = await execute(childs, 25, 100, { usePs: true })
t.log(`25 pid 100 times done in ${time.toFixed(3)} ms (${(1000 * 100 / time).toFixed(3)} op/s)`)
time = await execute(childs, 25, 100)
t.log(`(procfile) 25 pid 100 times done in ${time.toFixed(3)} ms (${(1000 * 100 / time).toFixed(3)} op/s)`)
time = await execute(childs, 50, 100, { usePs: true })
t.log(`50 pid 100 times done in ${time.toFixed(3)} ms (${(1000 * 100 / time).toFixed(3)} op/s)`)
time = await execute(childs, 50, 100)
t.log(`(procfile) 50 pid 100 times done in ${time.toFixed(3)} ms (${(1000 * 100 / time).toFixed(3)} op/s)`)
time = await execute(childs, 100, 100, { usePs: true })
t.log(`100 pid 100 times done in ${time.toFixed(3)} ms (${(1000 * 100 / time).toFixed(3)} op/s)`)
time = await execute(childs, 100, 100)
t.log(`(procfile) 100 pid 100 times done in ${time.toFixed(3)} ms (${(1000 * 100 / time).toFixed(3)} op/s)`)
await destroy(childs)
t.pass()
})
================================================
FILE: test/fixtures/_eventloop.js
================================================
const pidusage = require('../../')
pidusage(process.pid, { maxage: 1500 }, function (err, stat) {
if (err) {
throw err
}
console.log('Got stats', stat)
// clean the event loop right away
if (process.clear_pidusage === '1' || process.argv[2] === '1') {
pidusage.clear()
}
})
console.log('My pid is ' + process.pid)
================================================
FILE: test/gwmi.js
================================================
const mockery = require('mockery')
const test = require('ava')
const os = require('os')
const mockdate = require('mockdate')
const pify = require('pify')
const mocks = require('./helpers/_mocks')
const timeout = ms => new Promise((resolve, reject) => setTimeout(resolve, ms))
test.before(() => {
mockery.enable({
warnOnReplace: false,
warnOnUnregistered: false,
useCleanCache: true
})
mockdate.set(new Date(1427749200000))
})
test.beforeEach(() => {
mockery.resetCache()
})
test.after(() => {
mockery.disable()
mockdate.reset()
})
test('should parse gwmi output on Windows', async t => {
const stdout = '' +
'Active code page: 936' + os.EOL +
'' + os.EOL +
'' + os.EOL +
'CreationDate KernelModeTime ParentProcessId ProcessId UserModeTime WorkingSetSize' + os.EOL +
'------------ ----------- ----------- ------------ -------- --------' + os.EOL +
'20150329221650.080654+060 153750000 0 777 8556250000 110821376'
let calls = 0
mockery.registerMock('child_process', {
spawn: () => {
calls++
return mocks.spawn(stdout, '', null, 0, null)
}
})
const gwmi = require('../lib/gwmi')
let result = await pify(gwmi)([6456], { maxage: 1000 })
t.deepEqual(result, {
777: {
cpu: 0,
memory: 110821376,
ppid: 0,
pid: 777,
ctime: (855625 + 15375),
elapsed: 1427749200000 - new Date('2015-03-29T22:16:50.080654+0100').getTime(),
timestamp: 1427749200000
}
})
result = await pify(gwmi)([6456], { maxage: 1000 })
t.is(calls, 3, '2 first calls to put in history + 1')
mockdate.set(new Date(1427749202000))
// wait 1 second, it should do 2 calls again
await timeout(1000)
calls = 0
result = await pify(gwmi)([6456], { maxage: 1000 })
t.is(calls, 2, '2 first calls')
mockery.deregisterMock('child_process')
})
================================================
FILE: test/helpers/_mocks.js
================================================
const EventEmitter = require('events')
const streamify = require('string-to-stream')
const through = require('through')
module.exports = {
spawn: (stdout, stderr, error, code, signal) => {
const ee = new EventEmitter()
ee.stdout = through(function (d) { this.queue(d) })
ee.stderr = through(function (d) { this.queue(d) })
streamify(stderr).pipe(ee.stderr)
streamify(stdout).pipe(ee.stdout)
if (error) {
ee.emit('error', error)
} else if (!stderr) {
ee.stdout.on('end', () => ee.emit('close', code, signal))
} else {
ee.stderr.on('end', () => ee.emit('close', code, signal))
}
return ee
}
}
================================================
FILE: test/integration.js
================================================
const { spawn } = require('child_process')
const test = require('ava')
const os = require('os')
const path = require('path')
const m = require('..')
test('should work with a single pid', async t => {
const pid = process.pid
const result = await m(pid)
t.log(result)
t.is(typeof result, 'object')
t.is(typeof result, 'object', 'result')
t.is(typeof result.cpu, 'number', 'cpu')
t.false(isNaN(result.cpu), 'cpu')
t.is(typeof result.memory, 'number', 'memory')
// z/OS does not report memory
if (process.platform !== 'os390') {
t.false(isNaN(result.memory), 'memory')
}
t.is(typeof result.ppid, 'number', 'ppid')
t.false(isNaN(result.ppid), 'ppid')
t.is(typeof result.pid, 'number', 'pid')
t.false(isNaN(result.pid), 'pid')
t.is(typeof result.elapsed, 'number', 'elapsed')
t.false(isNaN(result.elapsed), 'elapsed')
t.is(typeof result.timestamp, 'number', 'timestamp')
t.false(isNaN(result.timestamp), 'timestamp')
})
test('should work with an array of pids', async t => {
const child = spawn(
'node',
['-e', 'console.log(`123`); setInterval(() => {}, 1000)'],
{ windowsHide: true }
)
const ppid = process.pid
const pid = child.pid
await t.notThrowsAsync(
new Promise((resolve, reject) => {
child.stdout.on('data', d => resolve(d.toString()))
child.stderr.on('data', d => reject(d.toString()))
child.on('error', reject)
child.on('exit', code => reject(new Error('script exited with code ' + code)))
}),
'script not executed'
)
const pids = [ppid, pid]
let result
try {
result = await m(pids)
child.kill()
} catch (err) {
child.kill()
t.notThrows(() => { throw err })
}
t.log(result)
t.is(typeof result, 'object')
t.deepEqual(Object.keys(result).sort(), pids.map(pid => pid.toString()).sort())
pids.forEach(pid => {
t.is(typeof result[pid], 'object', 'result')
t.is(typeof result[pid].cpu, 'number', 'cpu')
t.false(isNaN(result[pid].cpu), 'cpu')
t.is(typeof result[pid].memory, 'number', 'memory')
// z/OS does not report memory
if (process.platform !== 'os390') {
t.false(isNaN(result[pid].memory), 'memory')
}
t.is(typeof result[pid].ppid, 'number', 'ppid')
t.false(isNaN(result[pid].ppid), 'ppid')
t.is(typeof result[pid].pid, 'number', 'pid')
t.false(isNaN(result[pid].pid), 'pid')
t.is(typeof result[pid].elapsed, 'number', 'elapsed')
t.false(isNaN(result[pid].elapsed), 'elapsed')
t.is(typeof result[pid].timestamp, 'number', 'timestamp')
t.false(isNaN(result[pid].timestamp), 'timestamp')
})
m.clear()
})
test('should throw an error if no pid is provided', async t => {
const err = await t.throwsAsync(() => m([]))
t.is(err.message, 'You must provide at least one pid')
})
test('should throw an error if one of the pid is invalid', async t => {
let err = await t.throwsAsync(() => m(null))
t.is(err.message, 'One of the pids provided is invalid')
err = await t.throwsAsync(() => m([null]))
t.is(err.message, 'One of the pids provided is invalid')
err = await t.throwsAsync(() => m(['invalid']))
t.is(err.message, 'One of the pids provided is invalid')
err = await t.throwsAsync(() => m(-1))
t.is(err.message, 'One of the pids provided is invalid')
err = await t.throwsAsync(() => m([-1]))
t.is(err.message, 'One of the pids provided is invalid')
})
test('should not throw an error if one of the pids does not exists', async t => {
await t.notThrows(() => m([process.pid, 65535]))
await t.notThrows(() => m([65535, process.pid]))
})
test('should throw an error if the pid does not exists', async t => {
const err = await t.throwsAsync(() => m([65535]))
t.is(err.message, 'No matching pid found')
t.is(err.code, 'ENOENT')
})
test('should throw an error if the pid is too large', async t => {
await t.throwsAsync(async () => m(99999999))
})
test('should exit right away because we cleaned up the event loop', t => {
if (os.platform().match(/^win/)) return t.pass()
process.clear_pidusage = '1'
require(path.join(__dirname, '/fixtures/_eventloop'))
process.nextTick(() => {
t.pass()
})
})
test('should exit right away because the event loop ignores history', t => {
if (os.platform().match(/^win/)) return t.pass()
process.clear_pidusage = '0'
require(path.join(__dirname, '/fixtures/_eventloop'))
process.nextTick(() => {
t.pass()
})
})
test("should use the callback if it's provided", t => {
m(process.pid, () => t.pass())
})
process.on('unhandledException', (e) => {
console.error(e)
process.exit(1)
})
================================================
FILE: test/procfile.js
================================================
const mockery = require('mockery')
const test = require('ava')
const os = require('os')
const IS_WIN = os.platform().match(/^win/)
test.before(() => {
mockery.enable({
warnOnReplace: false,
warnOnUnregistered: false,
useCleanCache: true
})
})
test.beforeEach(() => {
mockery.resetCache()
})
test.after(() => {
mockery.disable()
})
test('procfile stat', async t => {
if (IS_WIN) {
t.pass()
return
}
const fs = require('fs')
let openCalled = 0
fs.open = function (path, mode, cb) {
openCalled++
cb(null, 10)
}
fs.readFile = function (path, encoding, callback) {
if (path === '/proc/uptime') {
callback(null, '100 0')
}
}
fs.read = function (fd, buffer, offset, length, position, callback) {
// proc/<pid>/stat
let infos = '0 (test)'
for (let i = 0; i < 22; i++) {
if (i === 12) {
infos += ' ' + 10000 // currentStime 10000 * clockTick
} else {
infos += ' 0'
}
}
buffer.write(infos)
callback(null, infos.length, buffer)
}
fs.existsSync = function (path) {
if (path === '/etc/alpine-release') { return true }
return false
}
const os = require('os')
os.platform = function () { return 'linux' }
mockery.registerMock('os', os)
mockery.registerMock('fs', fs)
mockery.registerMock('./cpu.js', function (cpu, next) {
next({
clockTick: 100,
uptime: 100,
pagesize: 4096
})
})
const m = require('..')
let stat = await m(10)
t.is(stat.cpu, 0)
t.is(stat.memory, 0)
t.is(stat.ppid, 0)
t.is(stat.pid, 10)
t.is(typeof stat.elapsed, 'number', 'elapsed')
t.false(isNaN(stat.elapsed), 'elapsed')
t.is(typeof stat.timestamp, 'number', 'timestamp')
t.false(isNaN(stat.timestamp), 'timestamp')
stat = await m(10)
t.is(openCalled, 1)
})
================================================
FILE: test/ps.js
================================================
const mockery = require('mockery')
const test = require('ava')
const os = require('os')
const mockdate = require('mockdate')
const pify = require('pify')
const mocks = require('./helpers/_mocks')
test.before(() => {
mockery.enable({
warnOnReplace: false,
warnOnUnregistered: false,
useCleanCache: true
})
mockdate.set(new Date(864000000))
})
test.beforeEach(() => {
mockery.resetCache()
})
test.after(() => {
mockery.disable()
mockdate.reset()
})
test('should parse ps output on Darwin', async t => {
const stdout = '' +
' ELAPSED PID PPID %CPU RSS TIME' + os.EOL +
'2-40:50:53 430 1 3.0 5145 1-02:03:04.07' + os.EOL +
' 40:50:53 432 430 0.0 2364 1-01:02:03.10' + os.EOL +
' 01:50:50 727 1 10.0 348932 14:27.26' + os.EOL +
' 00:20 7166 1 0.1 3756 0:00.02'
mockery.registerMock('child_process', {
spawn: () => mocks.spawn(stdout, '', null, 0, null)
})
mockery.registerMock('os', {
EOL: os.EOL,
platform: () => 'darwin',
type: () => 'type',
release: () => 'release'
})
const ps = require('../lib/ps')
const result = await pify(ps)([348932], {})
t.deepEqual(result, {
430: {
cpu: (93784070 / 319853000) * 100,
memory: 5145 * 1024,
ppid: 1,
pid: 430,
ctime: (1 * 86400 + 2 * 3600 + 3 * 60 + 4 * 1) * 1000 + (10 * 7),
elapsed: (2 * 86400 + 40 * 3600 + 50 * 60 + 53 * 1) * 1000,
timestamp: 864000000
},
432: {
cpu: (90123100 / 147053000) * 100,
memory: 2364 * 1024,
ppid: 430,
pid: 432,
ctime: (1 * 86400 + 1 * 3600 + 2 * 60 + 3 * 1) * 1000 + (10 * 10),
elapsed: (40 * 3600 + 50 * 60 + 53 * 1) * 1000,
timestamp: 864000000
},
727: {
cpu: (867260 / 6650000) * 100,
memory: 348932 * 1024,
ppid: 1,
pid: 727,
ctime: (14 * 60 + 27 * 1) * 1000 + (10 * 26),
elapsed: (1 * 3600 + 50 * 60 + 50 * 1) * 1000,
timestamp: 864000000
},
7166: {
cpu: (20 / 20000) * 100,
memory: 3756 * 1024,
ppid: 1,
pid: 7166,
ctime: (10 * 2),
elapsed: (20 * 1) * 1000,
timestamp: 864000000
}
})
mockery.deregisterMock('child_process')
mockery.deregisterMock('os')
})
test('should parse ps output on *nix', async t => {
t.pass()
// const stdout = '' +
// ' ELAPSED PID PPID %CPU RSS TIME' + os.EOL +
// '2-40:50:53 430 1 3.0 5145 1-02:03:04' + os.EOL +
// ' 40:50:53 432 430 0.0 2364 1-01:02:03' + os.EOL +
// ' 01:50:50 727 1 10.0 348932 14:27' + os.EOL +
// ' 00:20 7166 1 0.1 3756 0:00'
//
// mockery.registerMock('child_process', {
// spawn: () => mocks.spawn(stdout, '', null, 0, null)
// })
// mockery.registerMock('os', {
// EOL: os.EOL,
// platform: () => 'linux',
// type: () => 'type',
// release: () => 'release'
// })
//
// const ps = require('../lib/ps')
//
// const result = await pify(ps)([11678], {})
// t.deepEqual(result, {
// 430: {
// cpu: 3.0,
// memory: 5145 * 1024,
// ppid: 1,
// pid: 430,
// ctime: (1 * 86400 + 2 * 3600 + 3 * 60 + 4 * 1) * 1000,
// elapsed: (2 * 86400 + 40 * 3600 + 50 * 60 + 53 * 1) * 1000,
// timestamp: 864000000
// },
// 432: {
// cpu: 0.0,
// memory: 2364 * 1024,
// ppid: 430,
// pid: 432,
// ctime: (1 * 86400 + 1 * 3600 + 2 * 60 + 3 * 1) * 1000,
// elapsed: (40 * 3600 + 50 * 60 + 53 * 1) * 1000,
// timestamp: 864000000
// },
// 727: {
// cpu: 10.0,
// memory: 348932 * 1024,
// ppid: 1,
// pid: 727,
// ctime: (14 * 60 + 27 * 1) * 1000,
// elapsed: (1 * 3600 + 50 * 60 + 50 * 1) * 1000,
// timestamp: 864000000
// },
// 7166: {
// cpu: 0.1,
// memory: 3756 * 1024,
// ppid: 1,
// pid: 7166,
// ctime: 0,
// elapsed: (20 * 1) * 1000,
// timestamp: 864000000
// }
// })
//
// mockery.deregisterMock('child_process')
// mockery.deregisterMock('os')
})
test('should be able to set usePs from env var', async t => {
let usePsFromStats
mockery.registerMock('./lib/stats', (_, options) => {
usePsFromStats = options.usePs
})
const beforeValue = process.env.PIDUSAGE_USE_PS
process.env.PIDUSAGE_USE_PS = 'true'
const pidusage = require('../')
pidusage(1, () => {})
t.is(usePsFromStats, true)
process.env.PIDUSAGE_USE_PS = beforeValue
mockery.deregisterMock('./lib/stats')
})
================================================
FILE: test/wmic.js
================================================
const mockery = require('mockery')
const test = require('ava')
const os = require('os')
const mockdate = require('mockdate')
const pify = require('pify')
const mocks = require('./helpers/_mocks')
const timeout = ms => new Promise((resolve, reject) => setTimeout(resolve, ms))
test.before(() => {
mockery.enable({
warnOnReplace: false,
warnOnUnregistered: false,
useCleanCache: true
})
mockdate.set(new Date(1427749200000))
})
test.beforeEach(() => {
mockery.resetCache()
})
test.after(() => {
mockery.disable()
mockdate.reset()
})
test('should parse wmic output on Windows', async t => {
const stdout = '' +
'CreationDate KernelModeTime ParentProcessId ProcessId UserModeTime WorkingSetSize' + os.EOL +
'20150329221650.080654+060 153750000 0 777 8556250000 110821376'
let calls = 0
mockery.registerMock('child_process', {
spawn: () => {
calls++
return mocks.spawn(stdout, '', null, 0, null)
}
})
const wmic = require('../lib/wmic')
let result = await pify(wmic)([6456], { maxage: 1000 })
t.deepEqual(result, {
777: {
cpu: 0,
memory: 110821376,
ppid: 0,
pid: 777,
ctime: (855625 + 15375),
elapsed: 1427749200000 - new Date('2015-03-29T22:16:50.080654+0100').getTime(),
timestamp: 1427749200000
}
})
result = await pify(wmic)([6456], { maxage: 1000 })
t.is(calls, 3, '2 first calls to put in history + 1')
mockdate.set(new Date(1427749202000))
// wait 1 second, it should do 2 calls again
await timeout(1000)
calls = 0
result = await pify(wmic)([6456], { maxage: 1000 })
t.is(calls, 2, '2 first calls')
mockery.deregisterMock('child_process')
})
gitextract_s94v4rqx/
├── .github/
│ └── workflows/
│ ├── alpine.yml
│ ├── lint.yml
│ ├── macos.yml
│ ├── test.yml
│ └── windows.yml
├── .gitignore
├── CHANGELOG.md
├── Dockerfile
├── LICENSE
├── README.md
├── examples/
│ ├── README.md
│ ├── server.js
│ └── stresstest.js
├── index.js
├── lib/
│ ├── bin.js
│ ├── gwmi.js
│ ├── helpers/
│ │ ├── cpu.js
│ │ └── parallel.js
│ ├── history.js
│ ├── procfile.js
│ ├── ps.js
│ ├── stats.js
│ └── wmic.js
├── package.json
└── test/
├── bench.js
├── fixtures/
│ └── _eventloop.js
├── gwmi.js
├── helpers/
│ └── _mocks.js
├── integration.js
├── procfile.js
├── ps.js
└── wmic.js
SYMBOL INDEX (33 symbols across 12 files)
FILE: index.js
function pidusage (line 14) | function pidusage (pids, options, callback) {
FILE: lib/bin.js
function run (line 11) | function run (cmd, args, options, done) {
FILE: lib/gwmi.js
function parseDate (line 7) | function parseDate (datestr) {
function gwmi (line 28) | function gwmi (pids, options, done) {
FILE: lib/helpers/cpu.js
function updateCpu (line 10) | function updateCpu (cpu, next) {
function getRealUptime (line 41) | function getRealUptime (next) {
function getClockAndPageSize (line 54) | function getClockAndPageSize (next) {
function getconf (line 69) | function getconf (keyword, options, next) {
FILE: lib/helpers/parallel.js
function parallel (line 4) | function parallel (fns, options, done) {
FILE: lib/history.js
constant DEFAULT_MAXAGE (line 2) | const DEFAULT_MAXAGE = 60000
function get (line 11) | function get (pid, maxage) {
function set (line 23) | function set (pid, object, maxage, onExpire) {
function sheduleInvalidator (line 38) | function sheduleInvalidator (maxage) {
function runInvalidator (line 56) | function runInvalidator () {
function deleteLoop (line 75) | function deleteLoop (obj) { for (const i in obj) { delete obj[i] } }
function clear (line 77) | function clear () {
FILE: lib/procfile.js
constant SIZE (line 8) | const SIZE = 1024 // if the stat file is bigger then this I'll buy you a...
function noop (line 10) | function noop () {}
function open (line 12) | function open (path, history, cb) {
function close (line 17) | function close (history) {
function readUntilEnd (line 23) | function readUntilEnd (fd, buf, cb) {
function readProcFile (line 47) | function readProcFile (pid, options, done) {
function procfile (line 124) | function procfile (pids, options, done) {
FILE: lib/ps.js
constant PLATFORM (line 7) | const PLATFORM = os.platform()
function parseTime (line 9) | function parseTime (timestr, centisec) {
function ps (line 37) | function ps (pids, options, done) {
FILE: lib/stats.js
function get (line 57) | function get (pids, options, callback) {
FILE: lib/wmic.js
function parseDate (line 7) | function parseDate (datestr) {
function wmic (line 34) | function wmic (pids, options, done) {
FILE: test/bench.js
function create (line 7) | async function create (pidno) {
function destroy (line 31) | async function destroy (childs) {
function execute (line 35) | async function execute (childs, pidno, times, options = {}) {
FILE: test/procfile.js
constant IS_WIN (line 5) | const IS_WIN = os.platform().match(/^win/)
Condensed preview — 32 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (68K chars).
[
{
"path": ".github/workflows/alpine.yml",
"chars": 388,
"preview": "name: test-alpine\n\non:\n push:\n branches: '*'\n pull_request:\n branches: '*'\n\njobs:\n test:\n runs-on: ubuntu-la"
},
{
"path": ".github/workflows/lint.yml",
"chars": 400,
"preview": "name: lint\n\non:\n push:\n branches: '*'\n pull_request:\n branches: '*'\n\njobs:\n lint:\n runs-on: ubuntu-latest\n "
},
{
"path": ".github/workflows/macos.yml",
"chars": 297,
"preview": "name: test-macos\n\non:\n push:\n branches: '*'\n pull_request:\n branches: '*'\n\njobs:\n test:\n runs-on: macos-late"
},
{
"path": ".github/workflows/test.yml",
"chars": 701,
"preview": "name: linux\n\non:\n push:\n branches: '*'\n pull_request:\n branches: '*'\n\njobs:\n test:\n runs-on: ubuntu-latest\n "
},
{
"path": ".github/workflows/windows.yml",
"chars": 303,
"preview": "name: test-windows\n\non:\n push:\n branches: '*'\n pull_request:\n branches: '*'\n\njobs:\n test:\n runs-on: windows-"
},
{
"path": ".gitignore",
"chars": 34,
"preview": "node_modules\n.nyc_output\ncoverage\n"
},
{
"path": "CHANGELOG.md",
"chars": 3926,
"preview": "### 4.0.1\n\n- fix spawned wmic processes not exiting after wmic/gwmi detection in packaged apps, leading to infinite buil"
},
{
"path": "Dockerfile",
"chars": 68,
"preview": "FROM node:alpine\n\nRUN mkdir -p /var/pidusage\n\nWORKDIR /var/pidusage\n"
},
{
"path": "LICENSE",
"chars": 1072,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2014 soyuka\n\nPermission is hereby granted, free of charge, to any person obtaining "
},
{
"path": "README.md",
"chars": 7659,
"preview": "# pidusage\n\n[](https://github.com/soyuka"
},
{
"path": "examples/README.md",
"chars": 251,
"preview": "# Example section\n\n## server.js\n\nUsed to be tested with an HTTP benchmark tool like this one: https://github.com/wg/wrk."
},
{
"path": "examples/server.js",
"chars": 393,
"preview": "const http = require('http')\nconst pidusage = require('../')\n\nhttp.createServer(function (req, res) {\n res.writeHead(20"
},
{
"path": "examples/stresstest.js",
"chars": 2384,
"preview": "const pusage = require('../')\n\n// stress test to compare with top or another tool\nconsole.log('This is my PID: %s', proc"
},
{
"path": "index.js",
"chars": 1082,
"preview": "'use strict'\n\nconst stats = require('./lib/stats')\n\n/**\n * Get pid informations.\n * @public\n * @param {Number|Number[]|"
},
{
"path": "lib/bin.js",
"chars": 892,
"preview": "'use strict'\n\nconst spawn = require('child_process').spawn\n\n/**\n * Spawn a binary and read its stdout.\n * @param {Str"
},
{
"path": "lib/gwmi.js",
"chars": 4536,
"preview": "'use strict'\n\nconst os = require('os')\nconst bin = require('./bin')\nconst history = require('./history')\n\nfunction parse"
},
{
"path": "lib/helpers/cpu.js",
"chars": 2117,
"preview": "const os = require('os')\nconst fs = require('fs')\nconst exec = require('child_process').exec\nconst parallel = require('."
},
{
"path": "lib/helpers/parallel.js",
"chars": 987,
"preview": "// execute an array of asynchronous functions in parallel\n// @param {Array} fns - an array of functions\n// @param {Funct"
},
{
"path": "lib/history.js",
"chars": 1743,
"preview": "'use strict'\nconst DEFAULT_MAXAGE = 60000\n\nconst expiration = {}\nconst history = {}\nconst expireListeners = {}\n\nlet size"
},
{
"path": "lib/procfile.js",
"chars": 3925,
"preview": "const fs = require('fs')\nconst path = require('path')\nconst updateCpu = require('./helpers/cpu')\nconst parallel = requir"
},
{
"path": "lib/ps.js",
"chars": 3965,
"preview": "'use strict'\n\nconst os = require('os')\nconst bin = require('./bin')\nconst history = require('./history')\n\nconst PLATFORM"
},
{
"path": "lib/stats.js",
"chars": 2444,
"preview": "'use strict'\n\nconst fs = require('fs')\nconst os = require('os')\nconst spawn = require('child_process').spawn\n\nconst requ"
},
{
"path": "lib/wmic.js",
"chars": 4231,
"preview": "'use strict'\n\nconst os = require('os')\nconst bin = require('./bin')\nconst history = require('./history')\n\nfunction parse"
},
{
"path": "package.json",
"chars": 1284,
"preview": "{\n \"name\": \"pidusage\",\n \"version\": \"3.0.1\",\n \"description\": \"Cross-platform process cpu % and memory usage of a PID\","
},
{
"path": "test/bench.js",
"chars": 3474,
"preview": "const { spawn } = require('child_process')\nconst test = require('ava')\nconst tspan = require('time-span')\n\nconst m = req"
},
{
"path": "test/fixtures/_eventloop.js",
"chars": 337,
"preview": "const pidusage = require('../../')\n\npidusage(process.pid, { maxage: 1500 }, function (err, stat) {\n if (err) {\n thro"
},
{
"path": "test/gwmi.js",
"chars": 1932,
"preview": "const mockery = require('mockery')\nconst test = require('ava')\nconst os = require('os')\nconst mockdate = require('mockda"
},
{
"path": "test/helpers/_mocks.js",
"chars": 657,
"preview": "const EventEmitter = require('events')\nconst streamify = require('string-to-stream')\nconst through = require('through')\n"
},
{
"path": "test/integration.js",
"chars": 4605,
"preview": "const { spawn } = require('child_process')\nconst test = require('ava')\nconst os = require('os')\nconst path = require('pa"
},
{
"path": "test/procfile.js",
"chars": 1830,
"preview": "const mockery = require('mockery')\nconst test = require('ava')\nconst os = require('os')\n\nconst IS_WIN = os.platform().ma"
},
{
"path": "test/ps.js",
"chars": 4638,
"preview": "const mockery = require('mockery')\nconst test = require('ava')\nconst os = require('os')\nconst mockdate = require('mockda"
},
{
"path": "test/wmic.js",
"chars": 1747,
"preview": "const mockery = require('mockery')\nconst test = require('ava')\nconst os = require('os')\nconst mockdate = require('mockda"
}
]
About this extraction
This page contains the full source code of the soyuka/pidusage GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 32 files (62.8 KB), approximately 20.2k tokens, and a symbol index with 33 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.