Full Code of soyuka/pidusage for AI

main 36383b8d70c2 cached
32 files
62.8 KB
20.2k tokens
33 symbols
1 requests
Download .txt
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

[![Lint](https://github.com/soyuka/pidusage/workflows/lint/badge.svg?branch=main)](https://github.com/soyuka/pidusage/actions?query=workflow:lint+branch:main)
[![MacOS](https://github.com/soyuka/pidusage/workflows/test-macos/badge.svg?branch=main)](https://github.com/soyuka/pidusage/actions?query=workflow:test-macos+branch:main)
[![Ubuntu](https://github.com/soyuka/pidusage/workflows/linux/badge.svg?branch=main)](https://github.com/soyuka/pidusage/actions?query=workflow:linux+branch:main)
[![Windows](https://github.com/soyuka/pidusage/workflows/test-windows/badge.svg?branch=main)](https://github.com/soyuka/pidusage/actions?query=workflow:test-windows+branch:main)
[![Alpine](https://github.com/soyuka/pidusage/workflows/test-alpine/badge.svg?branch=main)](https://github.com/soyuka/pidusage/actions?query=workflow:test-alpine+branch:main)
[![Code coverage](https://img.shields.io/codecov/c/github/soyuka/pidusage/master.svg)](https://codecov.io/gh/soyuka/pidusage)
[![npm version](https://img.shields.io/npm/v/pidusage.svg)](https://www.npmjs.com/package/pidusage)
[![license](https://img.shields.io/github/license/soyuka/pidusage.svg)](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.&lt;Object&gt;]</code>
Get pid informations.

**Kind**: global function
**Returns**: <code>Promise.&lt;Object&gt;</code> - Only when the callback is not provided.
**Access**: public

| Param | Type | Description |
| --- | --- | --- |
| pids | <code>Number</code> \| <code>Array.&lt;Number&gt;</code> \| <code>String</code> \| <code>Array.&lt;String&gt;</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')
})
Download .txt
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
Download .txt
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[![Lint](https://github.com/soyuka/pidusage/workflows/lint/badge.svg?branch=main)](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.

Copied to clipboard!