Search code examples
flaskmonitoringmetricspsutil

psutil's cpu_percent always returns 0.0


I would like my Flask application to report how much CPU and memory it is currently using as a percentage:

import psutil
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route("/test", methods=["GET"])
def healthz():
    return jsonify(msg="OK"), 200

@app.route("/stats", methods=["GET"])
def stats():
    p = psutil.Process()
    json_body = {
        "cpu_percent": p.cpu_percent(interval=None),
        "cpu_times": p.cpu_times(),
        "mem_info": p.memory_info(),
        "mem_percent": p.memory_percent()
    }
    return jsonify(json_body), 200


def main():
    app.run(host="0.0.0.0", port=8000, debug=False)

if __name__ == '__main__':
    main()

While sending a lot of requests to /test, /stats will always returns 0.0 for cpu_percent:

$ while true; do curl http://127.0.0.1:8000/test &>/dev/null; done &
$ curl http://127.0.0.1:8000/stats
{
  "cpu_percent": 0.0, 
  "cpu_times": [
    4.97, 
    1.28, 
    0.0, 
    0.0
  ], 
  "mem_info": [
    19652608, 
    243068928, 
    4292608, 
    4096, 
    0, 
    14675968, 
    0
  ], 
  "mem_percent": 1.8873787935409003
}

However, if I manually check using ipython:

import psutil
p = psutil.Process(10993)
p.cpu_percent()

This correctly returns a value greater than 0.0.


Solution

  • Simply define "p = psutil.Process()" globally (outside of stat() function). cpu_percent() keeps track of CPU times since last call, and that's how it is able to determine percentage.

    The first call will always be 0.0 as calculating percentage is something which requires comparing two values over time, and as such, some time has to pass.