Browse Source

[#37192] graph: Added txt rendering

check-vt100
Marcelina Oset 4 years ago committed by Grzegorz Latosinski
parent
commit
9614266548
  1. 245
      graph.py
  2. 2
      sargraph.py
  3. 4
      watch.py

245
graph.py

@ -12,7 +12,10 @@ import socket
import subprocess
import sys
import time
import plotext as plt
import numpy as np
from pathlib import Path
from typing import List, Tuple, Optional
from common import *
global gnuplot
@ -28,9 +31,9 @@ TOTAL_RAM = 0
TOTAL_FS = 0
NAME_FS = "unknown"
UNAME="unknown"
CPUS=0
CPU_NAME="unknown"
UNAME = "unknown"
CPUS = 0
CPU_NAME = "unknown"
DURATION = 0.0
HOST = socket.gethostname()
@ -39,8 +42,8 @@ HOST = socket.gethostname()
NUMBER_OF_PLOTS = 3
# The default format
OUTPUT_TYPE="pngcairo"
OUTPUT_EXT="png"
OUTPUT_TYPE = "pngcairo"
OUTPUT_EXT = "png"
labels = []
@ -49,7 +52,8 @@ labels = []
p = run_or_fail("gnuplot", "--version", stdout=subprocess.PIPE)
version = scan(r"gnuplot (\S+)", str, p.stdout.readline().decode())
if not is_version_ge(version, GNUPLOT_VERSION_EXPECTED):
fail(f"gnuplot version too low. Need at least {GNUPLOT_VERSION_EXPECTED} found {version}")
fail(
f"gnuplot version too low. Need at least {GNUPLOT_VERSION_EXPECTED} found {version}")
# Run a command in a running gnuplot process
@ -191,27 +195,29 @@ def graph(session, fname='plot.png'):
labels = []
# The default format
OUTPUT_TYPE="pngcairo"
OUTPUT_EXT="png"
OUTPUT_TYPE = "pngcairo"
OUTPUT_EXT = "png"
if "SARGRAPH_OUTPUT_TYPE" in os.environ:
if os.environ["SARGRAPH_OUTPUT_TYPE"] == "svg":
OUTPUT_TYPE="svg"
OUTPUT_EXT="svg"
OUTPUT_TYPE = "svg"
OUTPUT_EXT = "svg"
elif fname.lower().endswith('.svg'):
OUTPUT_TYPE="svg"
OUTPUT_EXT="svg"
OUTPUT_TYPE = "svg"
OUTPUT_EXT = "svg"
elif fname.lower().endswith('.png'):
# Otherwise leave the default png
pass
else:
fail("unknown graph extension")
pass
# fail("unknown graph extension")
# Leave just the base name
fname = fname[:-4]
read_comments(session)
gnuplot = run_or_fail("gnuplot", stdin=subprocess.PIPE, stdout=subprocess.PIPE)
gnuplot = run_or_fail("gnuplot", stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
sdt = datetime.datetime.strptime(START_DATE, '%Y-%m-%d-%H:%M:%S')
edt = datetime.datetime.strptime(END_DATE, '%Y-%m-%d-%H:%M:%S')
@ -220,8 +226,8 @@ def graph(session, fname='plot.png'):
if seconds_between < 100:
seconds_between = 100
nsdt = sdt - datetime.timedelta(seconds = (seconds_between * 0.01))
nedt = edt + datetime.timedelta(seconds = (seconds_between * 0.01))
nsdt = sdt - datetime.timedelta(seconds=(seconds_between * 0.01))
nedt = edt + datetime.timedelta(seconds=(seconds_between * 0.01))
g(f"set terminal {OUTPUT_TYPE} size 1200,1200 background '#332d37' font 'monospace,{fix_size(8)}'")
@ -245,7 +251,6 @@ def graph(session, fname='plot.png'):
g("unset key")
g("set rmargin 6")
g(f"set output '{fname}.{OUTPUT_EXT}'")
title_machine = f"Running on {{/:Bold {HOST}}} \@ {{/:Bold {UNAME}}}, {{/:Bold {CPUS}}} threads x {{/:Bold {CPU_NAME}}}"
@ -260,7 +265,7 @@ def graph(session, fname='plot.png'):
i = 0
for label in labels:
if i%2 == 0:
if i % 2 == 0:
offset = 1.08
else:
offset = 1.20
@ -270,7 +275,7 @@ def graph(session, fname='plot.png'):
content = f"{{[{i}] {label[1][0:30]}"
length = len(label[1][0:30]) + len(str(i)) + 5
if OUTPUT_EXT == "svg":
length *= 0.75
length *= 0.75
# Draw the dotted line
g(f"set arrow nohead from '{label[0]}', graph 0.01 to '{label[0]}', graph {offset-0.04} front lc rgb '#e74a3c' dt 2")
@ -295,10 +300,204 @@ def graph(session, fname='plot.png'):
g("set object rectangle from graph 0, graph 0 to graph 2, graph 2 behind fillcolor rgb '#111111' fillstyle solid noborder")
g(f"set object rectangle from '{START_DATE.replace(' ', '-')}', 0 to '{END_DATE.replace(' ', '-')}', 100 behind fillcolor rgb '#000000' fillstyle solid noborder")
plot("cpu % load (user)", f"cpu load (average = {AVERAGE_LOAD:.2f} %)", session, 2, space=space)
plot("ram % usage", f"ram usage (max = {MAX_USED_RAM})", session, 3, space=space)
plot(f"{NAME_FS}", f"{NAME_FS} usage (max = {MAX_USED_FS})", session, 4, space=space)
plot("cpu % load (user)",
f"cpu load (average = {AVERAGE_LOAD:.2f} %)", session, 2, space=space)
plot("ram % usage",
f"ram usage (max = {MAX_USED_RAM})", session, 3, space=space)
plot(f"{NAME_FS}", f"{NAME_FS} usage (max = {MAX_USED_FS})",
session, 4, space=space)
g("unset multiplot")
g("unset output")
g("quit")
def read_data(session):
xdata = list()
ydata = [[], [], []]
with open(f"{session}.txt", "r") as f:
for line in f:
if(line[0] != '#'):
line = line.split(" ")
date = datetime.datetime.strptime(line[0], '%Y-%m-%d-%H:%M:%S')
xdata.append(date)
for i in range(3):
ydata[i].append(float(line[i+1]))
return (xdata, ydata)
def create_ascii_plot(
title: str,
xtitle: str,
xunit: str,
ytitle: str,
yunit: str,
xdata: List,
ydata: List,
xrange: Optional[Tuple] = (0, 10),
yrange: Optional[Tuple] = (0, 100),
trimxvalues: bool = True,
skipfirst: bool = False,
figsize: Tuple = (90, 30),
switchtobarchart: bool = False):
plt.clear_figure()
start = 1 if skipfirst else 0
xdata = np.array(xdata[start:], copy=True)
ydata = np.array(ydata[start:], copy=True)
if trimxvalues:
minx = min(xdata)
xdata = [x - minx for x in xdata]
xlabel = xtitle
if xunit is not None:
xlabel += f' [{xunit}]'
ylabel = ytitle
if yunit is not None:
ylabel += f' [{yunit}]'
if switchtobarchart == True:
plt.bar(xdata, ydata, width=0.1)
else:
plt.scatter(xdata, ydata)
plt.plot_size(figsize[0], figsize[1])
if xrange is not None:
plt.xlim(xrange[0], xrange[1])
if yrange is not None:
plt.ylim(yrange[0], yrange[1])
plt.title(title)
plt.xlabel(xtitle)
plt.ylabel(ytitle)
plt.show()
def render_ascii_plot(
outpath: Optional[Path],
title: str,
subtitles: List,
xtitles: List,
xunits: List,
ytitles: List,
yunits: List,
xdata: List,
ydata: List,
xrange: Optional[Tuple] = None,
yrange: Optional[Tuple] = None,
trimxvalues: bool = True,
skipfirst: bool = False,
figsize: Tuple = (1500, 1080),
bins: int = 20,
switchtobarchart: bool = True,
tags: List = [],
tagstype: str = "single",
outputext: str = "html"):
"""
Draws triple time series plot.
Used i.e. for timeline of resource usage.
It also draws the histograms of values that appeared throughout the
experiment.
Parameters
----------
outpath : Optional[Path]
Output path for the plot image. If None, the plot will be displayed.
title : str
Title of the plot
xtitle : str
Name of the X axis
xuint : str
Unit for the X axis
ytitle : str
Name of the Y axis
yunit : str
Unit for the Y axis
xdata : List
The values for X dimension
ydata : List
The values for Y dimension
xrange : Optional[Tuple]
The range of zoom on X axis
yrange : Optional[Tuple]
The range of zoom on Y axis
trimxvalues : bool
True if all values for the X dimension should be subtracted by
the minimal value on this dimension
skipfirst: bool
True if the first entry should be removed from plotting.
figsize: Tuple
The size of the figure
bins: int
Number of bins for value histograms
tags: list
List of tags and their timestamps
tagstype: String
"single" if given list contain tags with only one timestamp
"double" if given list contain tags with two (start and end)
timestamps.
outputext: String
Extension of generated file.
"html" for HTML file,
"png" for PNG file,
"svg" for SVG file,
"txt" for TXT file
"""
if outputext == "txt":
for plot_id in range(3):
create_ascii_plot(
title,
xtitles[plot_id],
xunits[plot_id],
ytitles[plot_id],
yunits[plot_id],
xdata,
ydata[plot_id],
xrange=xrange,
yrange=yrange,
trimxvalues=trimxvalues,
skipfirst=skipfirst,
switchtobarchart=switchtobarchart
)
return
def ascii_graph(session, fname='plot.png'):
plot_title = f"""Running on <b>{UNAME}</b>,
<b>{CPUS}</b> threads x <b>{CPU_NAME}</b><br>
Total ram: <b>{TOTAL_RAM}</b>,
Total disk space: <b> {TOTAL_FS}</b><br>
Duration: <b>{START_DATE}</b> .. <b>{END_DATE}</b> ({DURATION})"""
data = read_data(session)
subtitles = [f"""cpu load (average = {AVERAGE_LOAD} %)""",
f"""ram usage (max = {MAX_USED_RAM})""",
f"""{NAME_FS} usage (max = {MAX_USED_FS})"""]
y_titles = [f"cpu % load (user)",
f"ram % usage",
f"{NAME_FS}"]
xdata, ydata = data
xdata_to_int = [int(timestamp.replace(
tzinfo=datetime.timezone.utc).timestamp()*1000)/1000
for timestamp in xdata]
render_ascii_plot(
fname,
plot_title,
subtitles,
["time"]*3,
["s"]*3,
y_titles,
[None, None, None],
xdata_to_int,
ydata,
xrange=(0, 160),
yrange=(0, 100),
trimxvalues=True,
skipfirst=True,
switchtobarchart=True,
outputext="txt"
)

2
sargraph.py

@ -106,7 +106,9 @@ elif cmd[0] == 'save':
elif cmd[0] == 'plot':
if len(cmd) < 2:
graph.graph(sid)
graph.ascii_graph(sid)
else:
graph.graph(sid, cmd[1])
graph.ascii_graph(sid, cmd[1])
else:
fail(f"unknown command '{cmd[0]}'")

4
watch.py

@ -174,8 +174,10 @@ def watch(session, fsdev):
pass
elif label_line:
graph.graph(session, label_line)
graph.ascii_graph(session, label_line)
elif not dont_plot:
graph.graph(session)
graph.ascii_graph(session)
dont_plot = True
die = 1
break
@ -188,8 +190,10 @@ def watch(session, fsdev):
summarize(session)
if not label_line:
graph.graph(session)
graph.ascii_graph(session)
else:
graph.graph(session, label_line)
graph.ascii_graph(session, label_line)
elif label_line.startswith('label:'):
label_line = label_line[len('label:'):]
with open(f"{session}.txt", "a") as f:

Loading…
Cancel
Save