How to monitor usage of CPU when function is called in Python psutil?

Question:

Hey I’m learning psutil package and I want to know how to display current CPU usage when function is in progress? I suppose I need some threading or something like this, but how to do it? Thank u for any answers.

import psutil
import random

def iHateThis():
    tab = []
    for i in range(100000):
        tab.append(random.randint(1, 10000))

    tab.sort()
    return tab;

while(True):
    currentProcess = psutil.Process()
    print(currentProcess.cpu_percent(interval=1))
Asked By: ajirebardyn

||

Answers:

You can do this with the multiprocessing library. multiprocessing.Process is a class that represents a threaded process, is initiated with a function and name, and can be run at any time with .start().

import multiprocessing
import psutil
import random

def iHateThis():
    tab = []
    for i in range(100000):
        tab.append(random.randint(1, 10000))
    tab.sort()
    return tab;

hate = multiprocessing.Process(name='hate', target=iHateThis)
hate.start()

while(True):
    currentProcess = psutil.Process()
    print(currentProcess.cpu_percent(interval=1))
Answered By: Nat Weiland

You can use threading to run iHateThis or to run function with cpu_percent(). I choose second version. I will run cpu_percent() in thread.

Because it uses while True so thread would run forever and there wouldn’t be nice method to stop thread so I use global variaable running with while running to have method to stop this loop.

import threading
import psutil

def display_cpu():
    global running

    running = True

    currentProcess = psutil.Process()

    # start loop
    while running:
        print(currentProcess.cpu_percent(interval=1))

def start():
    global t

    # create thread and start it
    t = threading.Thread(target=display_cpu)
    t.start()

def stop():
    global running
    global t

    # use `running` to stop loop in thread so thread will end
    running = False

    # wait for thread's end
    t.join()

and now I can use it to start and stop thread which will display CPU. Because I may have to stop process using Ctrl+C so it will raise error so I use try/finally to stop thread even if there will be error.

def i_hate_this():
    tab = []
    for i in range(1000000):
        tab.append(random.randint(1, 10000))
    tab.sort()
    return tab

# ---

start()
try:
    result = i_hate_this()
finally: # stop thread even if I press Ctrl+C
    stop()

Full code:

import random
import threading
import psutil

def display_cpu():
    global running

    running = True

    currentProcess = psutil.Process()

    # start loop
    while running:
        print(currentProcess.cpu_percent(interval=1))

def start():
    global t

    # create thread and start it
    t = threading.Thread(target=display_cpu)
    t.start()

def stop():
    global running
    global t

    # use `running` to stop loop in thread so thread will end
    running = False

    # wait for thread's end
    t.join()

# ---

def i_hate_this():
    tab = []
    for i in range(1000000):
        tab.append(random.randint(1, 10000))
    tab.sort()
    return tab

# ---

start()
try:
    result = i_hate_this()
finally: # stop thread even if I press Ctrl+C
    stop()

BTW: this can be converted to class which inherits from class Thread and then it can hide variable running in class.

import psutil
import random
import threading

class DisplayCPU(threading.Thread):

    def run(self):

        self.running = True

        currentProcess = psutil.Process()

        while self.running:
            print(currentProcess.cpu_percent(interval=1))

    def stop(self):
        self.running = False

# ----

def i_hate_this():
    tab = []
    for i in range(1000000):
        tab.append(random.randint(1, 10000))
    tab.sort()
    return tab

# ---

display_cpu = DisplayCPU()

display_cpu.start()
try:
    result = i_hate_this()
finally: # stop thread even when I press Ctrl+C
    display_cpu.stop()

It could be also converted to context manager to run it as

with display_cpu():
    i_hate_this()

but I skip this part.

Answered By: furas

I don’t think you need to use psutil Process class as I think it is intended to be used to monitor a specific process. Using the code snippet from @furas (the accepted answer), you can do it with a thread like this:

def run(self):
    self.run = True 
    while self.run:
        psutil.cpu_percent(interval=1)

it works the same as the accepted answer in the following case:

    _monitor.start()
    try:
        for i in range(50):
            time.sleep(0.2)
    finally:    
        _monitor.stop()

If you don’t want to code it, I am doing it in a public repo if it can be of any help for someone: https://github.com/GTimothee/monitor

Answered By: ava_punksmash

Let approach the problem differently and propose a decorator that can serve to measure CPU utilization while running

from functools import partial, wraps


def log_cpu_usage(func=None, msg_prefix: str = None):
    """
    This function is a decorator that measures the execution time of a function and logs it.
    """
    debug = True
    if not debug:
        return func
    if func is None:
        return partial(log_cpu_usage, msg_prefix=msg_prefix)
    
    def new_func(data: mp.Queue, *args, **kwargs):
        result = func(*args, **kwargs)
        data.put(result)

    @wraps(func)
    def trace_execution(*args, **kwargs):
        manager = mp.Queue() # to save return val between multi process
        worker_process = mp.Process(target=new_func, args=(manager, *args), kwargs=kwargs)
        worker_process.start()
        p = psutil.Process(worker_process.pid)
        cpu_percents = []
        while worker_process.is_alive(): # while the subprocess is running
            cpu_percents.append(p.cpu_percent() / psutil.cpu_count())
            time.sleep(0.01)
        worker_process.join()
        ret_values = manager.get()
        return sum(cpu_percents) / len(cpu_percents), ret_values

@log_cpu_usage
def iHateThis():
    pass
Answered By: Alex Nea Kameni
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.