Recentlym I came across the talk talk from the Diabolia
Among all the great tips, the vmstat
command line utility seems to deliver great insights when it comes to quick performance analysis of Linux-based systems.
E. g., with a vmstat 1 60
, vmstat
will deliver you basic statistics about the utilization of your system frictionless:
It looks like a good idea to have a Jupyter notebook in place that can parse and visualize the data that vmstat
produces. This could be very handy for quick performance analysis.
First, we parse our way through the data. I executed some tasks with high CPU load, downloaded something from the web and and copyied a huge file. I've recorded the results into the text file vmstat_load.log
, which looks like this:
Yes, it's really ugly kind of input data with kind of fixed size columns. Nevertheless, let's get this into a nicely formated pandas dataframe.
import pandas as pd
vmstat_raw = pd.read_csv("datasets/vmstat_load90.log", sep="\n", header=None, skiprows=1, names=["raw"])
vmstat_raw.head(2)
raw | |
---|---|
0 | r b swpd free buff ... |
1 | 0 0 6144 2720868 41924 ... |
For getting rid of the fixed sized data, we can apply a little trick:
raw
columns (with the default whitespace character). This gives us an array with all the non-whitespace parts.pd.Series
accordingly. This gives us a collection Series (aka a DataFrame).vmstat_temp = vmstat_raw['raw'].str.split().apply(pd.Series)
vmstat_temp.head(2)
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | r | b | swpd | free | buff | cache | si | so | bi | bo | in | cs | us | sy | id | wa | st | UTC | NaN |
1 | 0 | 0 | 6144 | 2720868 | 41924 | 345548 | 0 | 0 | 29 | 691 | 588 | 541 | 2 | 4 | 93 | 1 | 0 | 2019-01-13 | 16:09:33 |
We also need suitable names for the columns of our newly DataFrame. For this, we can simply use the first columns of the new DataFrame.
vmstat_temp.columns = vmstat_temp.iloc[0]
vmstat_temp = vmstat_temp.dropna().reset_index(drop=True)
vmstat_temp.head()
r | b | swpd | free | buff | cache | si | so | bi | bo | in | cs | us | sy | id | wa | st | UTC | nan | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 6144 | 2720868 | 41924 | 345548 | 0 | 0 | 29 | 691 | 588 | 541 | 2 | 4 | 93 | 1 | 0 | 2019-01-13 | 16:09:33 |
1 | 0 | 0 | 6144 | 2718404 | 42276 | 347908 | 0 | 0 | 1421 | 116 | 1789 | 7724 | 1 | 6 | 92 | 1 | 0 | 2019-01-13 | 16:09:34 |
2 | 0 | 0 | 6144 | 2718404 | 42276 | 347912 | 0 | 0 | 0 | 44 | 1853 | 7724 | 3 | 3 | 94 | 0 | 0 | 2019-01-13 | 16:09:35 |
3 | 0 | 0 | 6144 | 2717652 | 42276 | 347912 | 0 | 0 | 0 | 24 | 1778 | 7022 | 1 | 3 | 95 | 0 | 0 | 2019-01-13 | 16:09:36 |
4 | 0 | 0 | 6144 | 2717652 | 42276 | 347912 | 0 | 0 | 0 | 20 | 1753 | 7033 | 1 | 4 | 96 | 0 | 0 | 2019-01-13 | 16:09:37 |
OK, let's start to convert the nicely formatted data now to the right data types:
to_numeric
helper function on this data.to_datetime
helper function on the data.vmstat = vmstat_temp.iloc[:,:-2].apply(pd.to_numeric)
vmstat['UTC'] = pd.to_datetime(vmstat_temp['UTC'] + " " + vmstat_temp[None])
vmstat_timed = vmstat.set_index('UTC')
vmstat_timed.head(2)
r | b | swpd | free | buff | cache | si | so | bi | bo | in | cs | us | sy | id | wa | st | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
UTC | |||||||||||||||||
2019-01-13 16:09:33 | 0 | 0 | 6144 | 2720868 | 41924 | 345548 | 0 | 0 | 29 | 691 | 588 | 541 | 2 | 4 | 93 | 1 | 0 |
2019-01-13 16:09:34 | 0 | 0 | 6144 | 2718404 | 42276 | 347908 | 0 | 0 | 1421 | 116 | 1789 | 7724 | 1 | 6 | 92 | 1 | 0 |
Last, because we have a timeseries with one entry per second, we can set the timestamp colum as index. This makes further time-based processing much easier.
vmstat_timed = vmstat.set_index('UTC')
vmstat_timed.head(2)
r | b | swpd | free | buff | cache | si | so | bi | bo | in | cs | us | sy | id | wa | st | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
UTC | |||||||||||||||||
2019-01-13 16:09:33 | 0 | 0 | 6144 | 2720868 | 41924 | 345548 | 0 | 0 | 29 | 691 | 588 | 541 | 2 | 4 | 93 | 1 | 0 |
2019-01-13 16:09:34 | 0 | 0 | 6144 | 2718404 | 42276 | 347908 | 0 | 0 | 1421 | 116 | 1789 | 7724 | 1 | 6 | 92 | 1 | 0 |
from ozapfdis.linux import vmstat
vmstat_timed = vmstat.read_logfile("datasets/vmstat_load90.log")
Second, we visualize all the measures with an appropriate diagram. I'll also explain, what I did execute during the various time periods.
vmstat_timed[['r', 'b']].plot();
vmstat_timed[['swpd', 'free', 'buff', 'cache']].plot();
vmstat_timed[['si', 'so']].plot();
vmstat_timed[['bi', 'bo']].plot();
vmstat_timed[['in', 'cs']].plot();
These are percentages of total CPU time.
vmstat_timed[['us', 'sy', 'id', 'wa', 'st']].plot.area();