Summarizing multicore usage using entropy

2023-01-02

I am an xmonad user, and use xmobar as my status bar. Previously, I had a 4-core CPU, and showed the CPU usage in the status bar using the MultiCpu plugin, which gave me something like:

0% 10% 1% 2%

which is fairly simple to read. However, I just changed laptops, and now I have a 16-core CPU, resulting in something like:

0% 10% 1% 2% 0% 12% 3% 0% 1% 0% 5% 6% 0% 2% 3% 1%

which is hard to understand. I thought about replacing it by just the average usage, but sometimes it’s useful to know how some software is using the cores – just one core with 100% and sixteen cores with 6.25% are very different.

Here, I will propose a solution where one can report the following CPU usage:

100% 100% 100% 100% 0% 0% 0% 0% 0% 0% 0% 0% 0% 0% 0% 0%

as

25% 4.0

where the first number is the average usage, and the second is the effective number of used cores. This is an useful summary, and if more detail is needed, one can always open htop.

1 Entropy and effective numbers

Entropy is number that (in short) indicates how uniform a statistical distribution is. The more the distribution is uniform, the higher the entropy. For a distribution with probabilities p_1, …, p_n, entropy is calculated as:

S = - \sum_{k=1}^n p_k \log p_k

Less well-known, but closely related are effective numbers or diversity indexes. The idea is that in a probability distribution, some states may be overrepresented, and may represent the almost totality of the distribution. Effective numbers are a way to count such states. They are simple to calculate:

N = e^S

This is the number we will report in the status bar.

2 Code

I report the CPU usage using a custom command, which executes the following Python script:

import psutil
import numpy as np
import scipy as sc

# Get CPU usage, using a 2 second time interval
list = psutil.cpu_percent(percpu=True, interval=2)

# Get the total usage, abort earlier if this is 0 somehow.
tot = sum(list)
if tot == 0:
    print("0% 16.0")

# Transform the usage numbers into a probability distribution
probs = np.asarray(list) / tot

# Calculate the effective number
av = tot / len(list)
eff = np.exp(sc.stats.entropy(probs))

print("{0:.0f}% {1:.1f}".format(av ,eff))

This should be simple to adapt to other use cases.