2021-10-19 13:41:48 +00:00
|
|
|
__filename__ = "fitnessFunctions.py"
|
|
|
|
__author__ = "Bob Mottram"
|
|
|
|
__license__ = "AGPL3+"
|
2024-01-21 19:01:20 +00:00
|
|
|
__version__ = "1.5.0"
|
2021-10-19 13:41:48 +00:00
|
|
|
__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-12-29 21:55:09 +00:00
|
|
|
from webapp_utils import html_header_with_external_style
|
|
|
|
from webapp_utils import html_footer
|
2024-05-12 12:35:26 +00:00
|
|
|
from utils import data_dir
|
2021-12-26 14:08:58 +00:00
|
|
|
from utils import get_config_param
|
2021-12-26 14:47:21 +00:00
|
|
|
from utils import save_json
|
2021-10-19 13:41:48 +00:00
|
|
|
|
|
|
|
|
2024-02-19 13:25:33 +00:00
|
|
|
def fitness_performance(start_time, fitness_state: {},
|
2022-01-02 13:18:11 +00:00
|
|
|
fitness_id: str, watch_point: str,
|
|
|
|
debug: bool) -> None:
|
2021-10-19 13:41:48 +00:00
|
|
|
"""Log a performance watchpoint
|
|
|
|
"""
|
2022-09-24 16:33:23 +00:00
|
|
|
if fitness_state is None:
|
|
|
|
return
|
2022-01-02 13:18:11 +00:00
|
|
|
if 'performance' not in fitness_state:
|
|
|
|
fitness_state['performance'] = {}
|
|
|
|
if fitness_id not in fitness_state['performance']:
|
|
|
|
fitness_state['performance'][fitness_id] = {}
|
|
|
|
if watch_point not in fitness_state['performance'][fitness_id]:
|
|
|
|
fitness_state['performance'][fitness_id][watch_point] = {
|
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
|
|
|
|
2024-02-19 13:25:33 +00:00
|
|
|
time_diff = float(time.time() - start_time)
|
2021-10-19 13:41:48 +00:00
|
|
|
|
2022-01-02 13:18:11 +00:00
|
|
|
fitness_state['performance'][fitness_id][watch_point]['total'] += time_diff
|
|
|
|
fitness_state['performance'][fitness_id][watch_point]['ctr'] += 1
|
|
|
|
if fitness_state['performance'][fitness_id][watch_point]['ctr'] >= 1024:
|
|
|
|
fitness_state['performance'][fitness_id][watch_point]['total'] /= 2
|
|
|
|
fitness_state['performance'][fitness_id][watch_point]['ctr'] = \
|
|
|
|
int(fitness_state['performance'][fitness_id][watch_point]['ctr'] /
|
|
|
|
2)
|
2021-10-19 13:41:48 +00:00
|
|
|
|
|
|
|
if debug:
|
2022-01-02 13:18:11 +00:00
|
|
|
ctr = fitness_state['performance'][fitness_id][watch_point]['ctr']
|
|
|
|
total = fitness_state['performance'][fitness_id][watch_point]['total']
|
|
|
|
print('FITNESS: performance/' + fitness_id + '/' +
|
2021-12-31 21:18:12 +00:00
|
|
|
watch_point + '/' + str(total * 1000 / ctr))
|
2021-10-19 17:35:52 +00:00
|
|
|
|
|
|
|
|
2022-01-02 13:18:11 +00:00
|
|
|
def sorted_watch_points(fitness: {}, fitness_id: str) -> []:
|
2021-10-19 20:08:24 +00:00
|
|
|
"""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 []
|
2022-01-02 13:18:11 +00:00
|
|
|
if not fitness['performance'].get(fitness_id):
|
2021-10-19 20:08:24 +00:00
|
|
|
return []
|
|
|
|
result = []
|
2022-01-02 13:18:11 +00:00
|
|
|
for watch_point, item in fitness['performance'][fitness_id].items():
|
2021-10-19 20:08:24 +00:00
|
|
|
if not item.get('total'):
|
|
|
|
continue
|
2022-04-23 19:47:40 +00:00
|
|
|
average_time = int(item['total'] * 1000 / item['ctr'])
|
|
|
|
average_time_str = str(average_time).zfill(16)
|
2021-12-31 21:18:12 +00:00
|
|
|
result.append(average_time_str + ' ' + watch_point)
|
2021-10-19 20:08:24 +00:00
|
|
|
result.sort(reverse=True)
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
2022-01-02 13:18:11 +00:00
|
|
|
def html_watch_points_graph(base_dir: str, fitness: {}, fitness_id: str,
|
|
|
|
max_entries: int) -> str:
|
2021-10-19 20:08:24 +00:00
|
|
|
"""Returns the html for a graph of watchpoints
|
|
|
|
"""
|
2022-01-02 13:18:11 +00:00
|
|
|
watch_points_list = sorted_watch_points(fitness, fitness_id)
|
2021-10-19 20:08:24 +00:00
|
|
|
|
2021-12-31 21:18:12 +00:00
|
|
|
css_filename = base_dir + '/epicyon-graph.css'
|
2021-12-25 16:17:53 +00:00
|
|
|
if os.path.isfile(base_dir + '/graph.css'):
|
2021-12-31 21:18:12 +00:00
|
|
|
css_filename = base_dir + '/graph.css'
|
2021-10-19 20:08:24 +00:00
|
|
|
|
2021-12-31 21:18:12 +00:00
|
|
|
instance_title = \
|
2021-12-26 14:08:58 +00:00
|
|
|
get_config_param(base_dir, 'instanceTitle')
|
2024-10-22 12:12:16 +00:00
|
|
|
preload_images = []
|
2021-12-31 21:18:12 +00:00
|
|
|
html_str = \
|
2024-10-22 12:12:16 +00:00
|
|
|
html_header_with_external_style(css_filename, instance_title, None,
|
|
|
|
preload_images)
|
2021-12-31 21:18:12 +00:00
|
|
|
html_str += \
|
2021-10-19 20:08:24 +00:00
|
|
|
'<table class="graph">\n' + \
|
2022-01-02 13:18:11 +00:00
|
|
|
'<caption>Watchpoints for ' + fitness_id + '</caption>\n' + \
|
2021-10-19 20:08:24 +00:00
|
|
|
'<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-12-31 21:18:12 +00:00
|
|
|
max_average_time = float(1)
|
|
|
|
if len(watch_points_list) > 0:
|
|
|
|
max_average_time = float(watch_points_list[0].split(' ')[0])
|
|
|
|
for watch_point in watch_points_list:
|
|
|
|
average_time = float(watch_point.split(' ')[0])
|
|
|
|
if average_time > max_average_time:
|
|
|
|
max_average_time = average_time
|
2021-10-19 20:08:24 +00:00
|
|
|
|
|
|
|
ctr = 0
|
2021-12-31 21:18:12 +00:00
|
|
|
for watch_point in watch_points_list:
|
|
|
|
name = watch_point.split(' ', 1)[1]
|
|
|
|
average_time = float(watch_point.split(' ')[0])
|
2022-01-02 13:18:11 +00:00
|
|
|
height_percent = int(average_time * 100 / max_average_time)
|
|
|
|
time_ms = int(average_time)
|
|
|
|
if height_percent == 0:
|
2021-10-19 21:12:06 +00:00
|
|
|
continue
|
2021-12-31 21:18:12 +00:00
|
|
|
html_str += \
|
2022-01-02 13:18:11 +00:00
|
|
|
'<tr style="height:' + str(height_percent) + '%">\n' + \
|
2021-10-19 20:08:24 +00:00
|
|
|
' <th scope="row">' + name + '</th>\n' + \
|
2022-01-02 13:18:11 +00:00
|
|
|
' <td><span>' + str(time_ms) + '</span></td>\n' + \
|
2021-10-19 20:08:24 +00:00
|
|
|
'</tr>\n'
|
|
|
|
ctr += 1
|
2022-01-02 13:18:11 +00:00
|
|
|
if ctr >= max_entries:
|
2021-10-19 20:08:24 +00:00
|
|
|
break
|
|
|
|
|
2021-12-31 21:18:12 +00:00
|
|
|
html_str += '</tbody></table>\n' + html_footer()
|
|
|
|
return html_str
|
2021-10-19 20:08:24 +00:00
|
|
|
|
|
|
|
|
2022-07-04 10:29:54 +00:00
|
|
|
def fitness_thread(base_dir: str, fitness: {}) -> None:
|
2021-10-19 17:35:52 +00:00
|
|
|
"""Thread used to save fitness function scores
|
|
|
|
"""
|
2024-05-12 12:35:26 +00:00
|
|
|
fitness_filename = data_dir(base_dir) + '/fitness.json'
|
2021-10-19 17:35:52 +00:00
|
|
|
while True:
|
|
|
|
# every 10 mins
|
|
|
|
time.sleep(60 * 10)
|
2021-12-26 14:47:21 +00:00
|
|
|
save_json(fitness, fitness_filename)
|