mirror of https://gitlab.com/bashrc2/epicyon
Showing performance graphs
parent
f721189769
commit
029d8bfcbf
29
daemon.py
29
daemon.py
|
@ -348,6 +348,8 @@ from speaker import getSSMLbox
|
|||
from city import getSpoofedCity
|
||||
from fitnessFunctions import fitnessPerformance
|
||||
from fitnessFunctions import fitnessThread
|
||||
from fitnessFunctions import sortedWatchPoints
|
||||
from fitnessFunctions import htmlWatchPointsGraph
|
||||
import os
|
||||
|
||||
|
||||
|
@ -12675,6 +12677,33 @@ class PubServer(BaseHTTPRequestHandler):
|
|||
'_GET', 'rss3 done',
|
||||
self.server.debug)
|
||||
|
||||
# show a performance graph
|
||||
if authorized and self.path.startswith('/performance?graph='):
|
||||
graph = self.path.split('?graph=')[1]
|
||||
if htmlGET and not graph.endswith('.json'):
|
||||
msg = \
|
||||
htmlWatchPointsGraph(self.server.baseDir,
|
||||
self.server.fitness,
|
||||
graph, 16)
|
||||
msglen = len(msg)
|
||||
self._set_headers('text/html', msglen,
|
||||
cookie, callingDomain, False)
|
||||
self._write(msg)
|
||||
fitnessPerformance(GETstartTime, self.server.fitness,
|
||||
'_GET', 'graph',
|
||||
self.server.debug)
|
||||
return
|
||||
else:
|
||||
graph = graph.replace('.json', '')
|
||||
watchPointsJson = sortedWatchPoints(self.server.fitness, graph)
|
||||
msg = json.dumps(watchPointsJson,
|
||||
ensure_ascii=False).encode('utf-8')
|
||||
msglen = len(msg)
|
||||
self._set_headers('application/json',
|
||||
msglen,
|
||||
None, callingDomain, False)
|
||||
self._write(msg)
|
||||
|
||||
# show the main blog page
|
||||
if htmlGET and (self.path == '/blog' or
|
||||
self.path == '/blog/' or
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
body, table, input, select, textarea {
|
||||
|
||||
}
|
||||
|
||||
.graph {
|
||||
margin-bottom:1em;
|
||||
font:normal 100%/150% arial,helvetica,sans-serif;
|
||||
}
|
||||
|
||||
.graph caption {
|
||||
font:bold 150%/120% arial,helvetica,sans-serif;
|
||||
padding-bottom:0.33em;
|
||||
}
|
||||
|
||||
.graph tbody th {
|
||||
text-align:right;
|
||||
}
|
||||
|
||||
@supports (display:grid) {
|
||||
|
||||
@media (min-width:32em) {
|
||||
|
||||
.graph {
|
||||
display:block;
|
||||
width:600px;
|
||||
height:300px;
|
||||
}
|
||||
|
||||
.graph caption {
|
||||
display:block;
|
||||
}
|
||||
|
||||
.graph thead {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.graph tbody {
|
||||
position:relative;
|
||||
display:grid;
|
||||
grid-template-columns:repeat(auto-fit, minmax(2em, 1fr));
|
||||
column-gap:2.5%;
|
||||
align-items:end;
|
||||
height:100%;
|
||||
margin:3em 0 1em 2.8em;
|
||||
padding:0 1em;
|
||||
border-bottom:2px solid rgba(0,0,0,0.5);
|
||||
background:repeating-linear-gradient(
|
||||
180deg,
|
||||
rgba(170,170,170,0.7) 0,
|
||||
rgba(170,170,170,0.7) 1px,
|
||||
transparent 1px,
|
||||
transparent 20%
|
||||
);
|
||||
}
|
||||
|
||||
.graph tbody:before,
|
||||
.graph tbody:after {
|
||||
position:absolute;
|
||||
left:-3.2em;
|
||||
width:2.8em;
|
||||
text-align:right;
|
||||
font:bold 80%/120% arial,helvetica,sans-serif;
|
||||
}
|
||||
|
||||
.graph tbody:before {
|
||||
content:"100%";
|
||||
top:-0.6em;
|
||||
}
|
||||
|
||||
.graph tbody:after {
|
||||
content:"0%";
|
||||
bottom:-0.6em;
|
||||
}
|
||||
|
||||
.graph tr {
|
||||
position:relative;
|
||||
display:block;
|
||||
}
|
||||
|
||||
.graph tr:hover {
|
||||
z-index:999;
|
||||
}
|
||||
|
||||
.graph th,
|
||||
.graph td {
|
||||
display:block;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.graph tbody th {
|
||||
position:absolute;
|
||||
top:-3em;
|
||||
left:0;
|
||||
width:100%;
|
||||
font-weight:normal;
|
||||
text-align:center;
|
||||
white-space:nowrap;
|
||||
text-indent:0;
|
||||
transform:rotate(-45deg);
|
||||
}
|
||||
|
||||
.graph tbody th:after {
|
||||
content:"";
|
||||
}
|
||||
|
||||
.graph td {
|
||||
width:100%;
|
||||
height:100%;
|
||||
background:#F63;
|
||||
border-radius:0.5em 0.5em 0 0;
|
||||
transition:background 0.5s;
|
||||
}
|
||||
|
||||
.graph tr:hover td {
|
||||
opacity:0.7;
|
||||
}
|
||||
|
||||
.graph td span {
|
||||
overflow:hidden;
|
||||
position:absolute;
|
||||
left:50%;
|
||||
top:50%;
|
||||
width:0;
|
||||
padding:0.5em 0;
|
||||
margin:-1em 0 0;
|
||||
font:normal 85%/120% arial,helvetica,sans-serif;
|
||||
/* background:white; */
|
||||
/* box-shadow:0 0 0.25em rgba(0,0,0,0.6); */
|
||||
font-weight:bold;
|
||||
opacity:0;
|
||||
transition:opacity 0.5s;
|
||||
color:white;
|
||||
}
|
||||
.toggleGraph:checked + table td span,
|
||||
.graph tr:hover td span {
|
||||
width:4em;
|
||||
margin-left:-2em;
|
||||
opacity:1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,7 +7,11 @@ __email__ = "bob@libreserver.org"
|
|||
__status__ = "Production"
|
||||
__module_group__ = "Core"
|
||||
|
||||
import os
|
||||
import time
|
||||
from webapp_utils import htmlHeaderWithExternalStyle
|
||||
from webapp_utils import htmlFooter
|
||||
from utils import getConfigParam
|
||||
from utils import saveJson
|
||||
|
||||
|
||||
|
@ -41,6 +45,74 @@ def fitnessPerformance(startTime, fitnessState: {},
|
|||
watchPoint + '/' + str(total * 1000 / ctr))
|
||||
|
||||
|
||||
def sortedWatchPoints(fitness: {}, fitnessId: str) -> []:
|
||||
"""Returns a sorted list of watchpoints
|
||||
"""
|
||||
if not fitness.get(fitnessId):
|
||||
return []
|
||||
result = []
|
||||
for watchPoint, item in fitness[fitnessId].items():
|
||||
if not item.get('total'):
|
||||
continue
|
||||
averageTime = item['total'] / item['ctr']
|
||||
result.append(str(averageTime) + ' ' + watchPoint)
|
||||
result.sort(reverse=True)
|
||||
return result
|
||||
|
||||
|
||||
def htmlWatchPointsGraph(baseDir: str, fitness: {}, fitnessId: str,
|
||||
maxEntries: int) -> str:
|
||||
"""Returns the html for a graph of watchpoints
|
||||
"""
|
||||
watchPointsList = sortedWatchPoints(fitness, fitnessId)
|
||||
|
||||
cssFilename = baseDir + '/epicyon-graph.css'
|
||||
if os.path.isfile(baseDir + '/graph.css'):
|
||||
cssFilename = baseDir + '/graph.css'
|
||||
|
||||
instanceTitle = \
|
||||
getConfigParam(baseDir, 'instanceTitle')
|
||||
htmlStr = htmlHeaderWithExternalStyle(cssFilename, instanceTitle)
|
||||
htmlStr += \
|
||||
'<table class="graph">\n' + \
|
||||
'<caption>Watchpoints for ' + fitnessId + '</caption>\n' + \
|
||||
'<thead>\n' + \
|
||||
' <tr>\n' + \
|
||||
' <th scope="col">Item</th>\n' + \
|
||||
' <th scope="col">Percent</th>\n' + \
|
||||
' </tr>\n' + \
|
||||
'</thead><tbody>\n'
|
||||
|
||||
# get the maximum time
|
||||
maxAverageTime = float(0.00001)
|
||||
if len(watchPointsList) > 0:
|
||||
maxAverageTime = float(watchPointsList[0].split(' ')[0])
|
||||
for watchPoint in watchPointsList:
|
||||
averageTime = float(watchPoint.split(' ')[0])
|
||||
if averageTime > maxAverageTime:
|
||||
maxAverageTime = averageTime
|
||||
|
||||
ctr = 0
|
||||
for watchPoint in watchPointsList:
|
||||
name = watchPoint.split(' ')[1]
|
||||
averageTime = float(watchPoint.split(' ')[0])
|
||||
heightPercent = int(averageTime * 100 / maxAverageTime)
|
||||
timeMS = int(averageTime * 1000)
|
||||
if timeMS == 0:
|
||||
break
|
||||
htmlStr += \
|
||||
'<tr style="height:' + str(heightPercent) + '%">\n' + \
|
||||
' <th scope="row">' + name + '</th>\n' + \
|
||||
' <td><span>' + str(timeMS) + 'mS</span></td>\n' + \
|
||||
'</tr>\n'
|
||||
ctr += 1
|
||||
if ctr >= maxEntries:
|
||||
break
|
||||
|
||||
htmlStr += '</tbody></table>\n' + htmlFooter()
|
||||
return htmlStr
|
||||
|
||||
|
||||
def fitnessThread(baseDir: str, fitness: {}):
|
||||
"""Thread used to save fitness function scores
|
||||
"""
|
||||
|
|
2
theme.py
2
theme.py
|
@ -104,7 +104,7 @@ def _getThemeFiles() -> []:
|
|||
return ('epicyon.css', 'login.css', 'follow.css',
|
||||
'suspended.css', 'calendar.css', 'blog.css',
|
||||
'options.css', 'search.css', 'links.css',
|
||||
'welcome.css')
|
||||
'welcome.css', 'graph.css')
|
||||
|
||||
|
||||
def isNewsThemeName(baseDir: str, themeName: str) -> bool:
|
||||
|
|
Loading…
Reference in New Issue