2021-10-19 13:41:48 +00:00
|
|
|
__filename__ = "fitnessFunctions.py"
|
|
|
|
__author__ = "Bob Mottram"
|
|
|
|
__license__ = "AGPL3+"
|
|
|
|
__version__ = "1.2.0"
|
|
|
|
__maintainer__ = "Bob Mottram"
|
|
|
|
__email__ = "bob@libreserver.org"
|
|
|
|
__status__ = "Production"
|
|
|
|
__module_group__ = "Core"
|
|
|
|
|
2021-10-19 20:08:24 +00:00
|
|
|
import os
|
2021-10-19 13:41:48 +00:00
|
|
|
import time
|
2021-10-19 20:08:24 +00:00
|
|
|
from webapp_utils import htmlHeaderWithExternalStyle
|
|
|
|
from webapp_utils import htmlFooter
|
|
|
|
from utils import getConfigParam
|
2021-10-19 17:35:52 +00:00
|
|
|
from utils import saveJson
|
2021-10-19 13:41:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
def fitnessPerformance(startTime, fitnessState: {},
|
|
|
|
fitnessId: str, watchPoint: str, debug: bool) -> None:
|
|
|
|
"""Log a performance watchpoint
|
|
|
|
"""
|
|
|
|
if 'performance' not in fitnessState:
|
|
|
|
fitnessState['performance'] = {}
|
|
|
|
if fitnessId not in fitnessState['performance']:
|
|
|
|
fitnessState['performance'][fitnessId] = {}
|
2021-10-19 18:08:18 +00:00
|
|
|
if watchPoint not in fitnessState['performance'][fitnessId]:
|
|
|
|
fitnessState['performance'][fitnessId][watchPoint] = {
|
2021-10-19 18:12:48 +00:00
|
|
|
"total": float(0),
|
|
|
|
"ctr": int(0)
|
2021-10-19 18:08:18 +00:00
|
|
|
}
|
2021-10-19 13:41:48 +00:00
|
|
|
|
2021-10-19 18:12:48 +00:00
|
|
|
timeDiff = float(time.time() - startTime)
|
2021-10-19 13:41:48 +00:00
|
|
|
|
2021-10-19 18:08:18 +00:00
|
|
|
fitnessState['performance'][fitnessId][watchPoint]['total'] += timeDiff
|
|
|
|
fitnessState['performance'][fitnessId][watchPoint]['ctr'] += 1
|
|
|
|
if fitnessState['performance'][fitnessId][watchPoint]['ctr'] >= 1024:
|
|
|
|
fitnessState['performance'][fitnessId][watchPoint]['total'] /= 2
|
|
|
|
fitnessState['performance'][fitnessId][watchPoint]['ctr'] = \
|
|
|
|
int(fitnessState['performance'][fitnessId][watchPoint]['ctr'] / 2)
|
2021-10-19 13:41:48 +00:00
|
|
|
|
|
|
|
if debug:
|
2021-10-19 18:08:18 +00:00
|
|
|
ctr = fitnessState['performance'][fitnessId][watchPoint]['ctr']
|
|
|
|
total = fitnessState['performance'][fitnessId][watchPoint]['total']
|
2021-10-19 13:41:48 +00:00
|
|
|
print('FITNESS: performance/' + fitnessId + '/' +
|
2021-10-19 18:08:18 +00:00
|
|
|
watchPoint + '/' + str(total * 1000 / ctr))
|
2021-10-19 17:35:52 +00:00
|
|
|
|
|
|
|
|
2021-10-19 20:08:24 +00:00
|
|
|
def sortedWatchPoints(fitness: {}, fitnessId: str) -> []:
|
|
|
|
"""Returns a sorted list of watchpoints
|
2021-10-19 20:58:59 +00:00
|
|
|
times are in mS
|
2021-10-19 20:08:24 +00:00
|
|
|
"""
|
2021-10-19 20:46:29 +00:00
|
|
|
if not fitness.get('performance'):
|
|
|
|
return []
|
|
|
|
if not fitness['performance'].get(fitnessId):
|
2021-10-19 20:08:24 +00:00
|
|
|
return []
|
|
|
|
result = []
|
2021-10-19 20:46:29 +00:00
|
|
|
for watchPoint, item in fitness['performance'][fitnessId].items():
|
2021-10-19 20:08:24 +00:00
|
|
|
if not item.get('total'):
|
|
|
|
continue
|
2021-10-20 15:51:48 +00:00
|
|
|
averageTime = item['total'] * 1000 / item['ctr']
|
2021-10-30 19:23:51 +00:00
|
|
|
averageTimeStr = str(averageTime).zfill(8)
|
2021-10-20 15:48:19 +00:00
|
|
|
result.append(averageTimeStr + ' ' + watchPoint)
|
2021-10-19 20:08:24 +00:00
|
|
|
result.sort(reverse=True)
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
2021-12-25 16:17:53 +00:00
|
|
|
def htmlWatchPointsGraph(base_dir: str, fitness: {}, fitnessId: str,
|
2021-10-19 20:08:24 +00:00
|
|
|
maxEntries: int) -> str:
|
|
|
|
"""Returns the html for a graph of watchpoints
|
|
|
|
"""
|
|
|
|
watchPointsList = sortedWatchPoints(fitness, fitnessId)
|
|
|
|
|
2021-12-25 16:17:53 +00:00
|
|
|
cssFilename = base_dir + '/epicyon-graph.css'
|
|
|
|
if os.path.isfile(base_dir + '/graph.css'):
|
|
|
|
cssFilename = base_dir + '/graph.css'
|
2021-10-19 20:08:24 +00:00
|
|
|
|
|
|
|
instanceTitle = \
|
2021-12-25 16:17:53 +00:00
|
|
|
getConfigParam(base_dir, 'instanceTitle')
|
2021-11-07 10:38:11 +00:00
|
|
|
htmlStr = htmlHeaderWithExternalStyle(cssFilename, instanceTitle, None)
|
2021-10-19 20:08:24 +00:00
|
|
|
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
|
2021-10-19 20:58:59 +00:00
|
|
|
maxAverageTime = float(1)
|
2021-10-19 20:08:24 +00:00
|
|
|
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:
|
2021-10-20 08:51:19 +00:00
|
|
|
name = watchPoint.split(' ', 1)[1]
|
2021-10-19 20:08:24 +00:00
|
|
|
averageTime = float(watchPoint.split(' ')[0])
|
|
|
|
heightPercent = int(averageTime * 100 / maxAverageTime)
|
2021-10-19 20:58:59 +00:00
|
|
|
timeMS = int(averageTime)
|
2021-10-19 21:12:06 +00:00
|
|
|
if heightPercent == 0:
|
|
|
|
continue
|
2021-10-19 20:08:24 +00:00
|
|
|
htmlStr += \
|
|
|
|
'<tr style="height:' + str(heightPercent) + '%">\n' + \
|
|
|
|
' <th scope="row">' + name + '</th>\n' + \
|
2021-10-20 20:57:49 +00:00
|
|
|
' <td><span>' + str(timeMS) + '</span></td>\n' + \
|
2021-10-19 20:08:24 +00:00
|
|
|
'</tr>\n'
|
|
|
|
ctr += 1
|
|
|
|
if ctr >= maxEntries:
|
|
|
|
break
|
|
|
|
|
|
|
|
htmlStr += '</tbody></table>\n' + htmlFooter()
|
|
|
|
return htmlStr
|
|
|
|
|
|
|
|
|
2021-12-25 16:17:53 +00:00
|
|
|
def fitnessThread(base_dir: str, fitness: {}):
|
2021-10-19 17:35:52 +00:00
|
|
|
"""Thread used to save fitness function scores
|
|
|
|
"""
|
2021-12-25 21:45:06 +00:00
|
|
|
fitness_filename = base_dir + '/accounts/fitness.json'
|
2021-10-19 17:35:52 +00:00
|
|
|
while True:
|
|
|
|
# every 10 mins
|
|
|
|
time.sleep(60 * 10)
|
2021-12-25 21:45:06 +00:00
|
|
|
saveJson(fitness, fitness_filename)
|