Skip to content

Commit 8fc1b64

Browse files
committed
Populate redis with resource-allocation data
1 parent ddff1c4 commit 8fc1b64

File tree

5 files changed

+143
-83
lines changed

5 files changed

+143
-83
lines changed

qiita_db/meta_util.py

Lines changed: 90 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
from json import loads, dump, dumps
3939

4040
from qiita_db.util import create_nested_path, _retrieve_resource_data
41-
from qiita_db.util import resource_allocation_plot, get_software_commands
41+
from qiita_db.util import resource_allocation_plot
4242
from qiita_core.qiita_settings import qiita_config, r_client
4343
from qiita_core.configuration_manager import ConfigurationManager
4444
import qiita_db as qdb
@@ -49,6 +49,7 @@
4949
"parameters", "samples", "columns", "input_size", "extra_info",
5050
"MaxRSSRaw", "ElapsedRaw", "Start", "node_name", "node_model"]
5151

52+
5253
def _get_data_fpids(constructor, object_id):
5354
"""Small function for getting filepath IDS associated with data object
5455
@@ -554,40 +555,96 @@ def generate_plugin_releases():
554555
f(redis_key, v)
555556

556557

557-
def initialize_resource_allocations_redis():
558-
time = datetime.now().strftime('%m-%d-%y %H:%M:%S')
558+
def get_software_commands():
559+
# TODO change active=False to True. In test, the data is active=False.
560+
software_list = [s for s in qdb.software.Software.iter(active=False)]
561+
software_commands = dict()
562+
for software in software_list:
563+
sname = software.name
564+
sversion = software.version
565+
commands = software.commands
566+
if sname not in software_commands:
567+
software_commands[sname] = {}
568+
if sversion not in software_commands[sname]:
569+
software_commands[sname][sversion] = []
570+
for command in commands:
571+
software_commands[sname][sversion].append(command.name)
572+
return software_commands
573+
574+
575+
def update_resource_allocation_redis():
576+
time = datetime.now().strftime('%m-%d-%y')
559577
scommands = get_software_commands()
560-
for software, versions in scommands.items():
561-
for version, commands in versions.items():
562-
for command in commands:
563-
print("Generating plot for:", software, version, command)
564-
update_resource_allocation_redis(command, software,
565-
version, time)
566578
redis_key = 'resources:commands'
567579
r_client.set(redis_key, str(scommands))
568580

581+
for sname, versions in scommands.items():
582+
for version, commands in versions.items():
583+
for cname in commands:
569584

570-
def update_resource_allocation_redis(cname, sname, version, time):
571-
col_name = "samples * columns"
572-
573-
df = _retrieve_resource_data(cname, sname, version, columns)
574-
fig, axs = resource_allocation_plot(df, cname, sname, col_name)
575-
576-
fig.tight_layout()
577-
plot = BytesIO()
578-
fig.savefig(plot, format='png')
579-
plot.seek(0)
580-
581-
img = 'data:image/png;base64,' + quote(b64encode(plot.getbuffer()).decode('ascii'))
582-
plt.close(fig)
583-
584-
# SID, CID, col_name
585-
values = [
586-
("img", img, r_client.set),
587-
('time', time, r_client.set)
588-
]
589-
590-
for k, v, f in values:
591-
redis_key = 'resources$#%s$#%s$#%s:%s' % (cname, sname, col_name, k)
592-
r_client.delete(redis_key)
593-
f(redis_key, v)
585+
print("Generating plot for:", sname, version, cname)
586+
col_name = "samples * columns"
587+
df = _retrieve_resource_data(cname, sname, version, columns)
588+
if len(df) == 0:
589+
print("No available data for", sname, version, cname)
590+
continue
591+
592+
fig, axs = resource_allocation_plot(df, cname, sname, col_name)
593+
titles = [0, 0]
594+
images = [0, 0]
595+
596+
# Splitting 1 image plot into 2 separate for better layout.
597+
for i, ax in enumerate(axs):
598+
titles[i] = ax.get_title()
599+
ax.set_title("")
600+
# new_fig, new_ax – copy with either only memory plot or
601+
# only time
602+
new_fig = plt.figure()
603+
new_ax = new_fig.add_subplot(111)
604+
605+
scatter_data = ax.collections[0]
606+
new_ax.scatter(scatter_data.get_offsets()[:, 0],
607+
scatter_data.get_offsets()[:, 1],
608+
s=scatter_data.get_sizes(), label="data")
609+
610+
line = ax.lines[0]
611+
new_ax.plot(line.get_xdata(), line.get_ydata(),
612+
linewidth=1, color='orange')
613+
614+
if len(ax.collections) > 1:
615+
failure_data = ax.collections[1]
616+
new_ax.scatter(failure_data.get_offsets()[:, 0],
617+
failure_data.get_offsets()[:, 1],
618+
color='red', s=3, label="failures")
619+
620+
new_ax.set_xscale('log')
621+
new_ax.set_yscale('log')
622+
new_ax.set_xlabel(ax.get_xlabel())
623+
new_ax.set_ylabel(ax.get_ylabel())
624+
new_ax.legend(loc='upper left')
625+
626+
new_fig.tight_layout()
627+
plot = BytesIO()
628+
new_fig.savefig(plot, format='png')
629+
plot.seek(0)
630+
img = 'data:image/png;base64,' + quote(
631+
b64encode(plot.getvalue()).decode('ascii'))
632+
images[i] = img
633+
plt.close(new_fig)
634+
plt.close(fig)
635+
636+
# SID, CID, col_name
637+
values = [
638+
("img_mem", images[0], r_client.set),
639+
("img_time", images[1], r_client.set),
640+
('time', time, r_client.set),
641+
("title_mem", titles[0], r_client.set),
642+
("title_time", titles[1], r_client.set)
643+
]
644+
print(time, titles[0], titles[1])
645+
646+
for k, v, f in values:
647+
redis_key = 'resources$#%s$#%s$#%s$#%s:%s' % (
648+
cname, sname, version, col_name, k)
649+
r_client.delete(redis_key)
650+
f(redis_key, v)

qiita_db/test/test_meta_util.py

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from os.path import exists, join
1414

1515
import pandas as pd
16+
from datetime import datetime
1617

1718
from qiita_core.qiita_settings import qiita_config, r_client
1819
from qiita_core.util import qiita_test_checker
@@ -523,18 +524,29 @@ def test_update_resource_allocation_redis(self):
523524
cname = "Split libraries FASTQ"
524525
sname = "QIIMEq2"
525526
col_name = "samples * columns"
526-
qdb.meta_util.update_resource_allocation_redis(cname, sname)
527-
528-
vals = [
529-
("img", b's', r_client.get),
530-
('time', b'2024-11-11', r_client.get)
531-
]
532-
533-
for k, exp, f in vals:
534-
redis_key = 'resources$#%s$#%s$#%s:%s' % (cname, sname, col_name, k)
535-
# checking redis values
536-
print(f(redis_key))
537-
# self.assertEqual(f(redis_key), exp)
527+
version = "1.9.1"
528+
qdb.meta_util.update_resource_allocation_redis()
529+
# since time is month, day, year, it should be equal unless test is ran
530+
# at midnight.
531+
time = datetime.now().strftime('%m-%d-%y')
532+
title_mem_str = 'resources$#%s$#%s$#%s$#%s:%s' % (
533+
cname, sname, version, col_name, 'title_mem')
534+
title_mem = str(r_client.get(title_mem_str))
535+
self.assertTrue(
536+
"model_chosen: "
537+
"k * log(x) + "
538+
"b * log(x)^2 + "
539+
"a * log(x)^2.5" in title_mem
540+
)
541+
542+
title_time_str = 'resources$#%s$#%s$#%s$#%s:%s' % (
543+
cname, sname, version, col_name, 'title_time')
544+
title_time = str(r_client.get(title_time_str))
545+
self.assertTrue("model_chosen: a + b + log(x) * k" in title_time)
546+
time_create_str = 'resources$#%s$#%s$#%s$#%s:%s' % (
547+
cname, sname, version, col_name, 'time')
548+
time_create = str(r_client.get(time_create_str))
549+
self.assertTrue(time in time_create)
538550

539551

540552
if __name__ == '__main__':

qiita_db/util.py

Lines changed: 25 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,27 @@
9999
MODELS_TIME = [time_model1, time_model2, time_model3, time_model4]
100100

101101

102+
def get_model_name(model):
103+
if model == mem_model1:
104+
return "k * log(x) + x * a + b"
105+
elif model == mem_model2:
106+
return "k * log(x) + b * log(x)^2 + a"
107+
elif model == mem_model3:
108+
return "k * log(x) + b * log(x)^2 + a * log(x)^3"
109+
elif model == mem_model4:
110+
return "k * log(x) + b * log(x)^2 + a * log(x)^2.5"
111+
elif model == time_model1:
112+
return "a + b + log(x) * k"
113+
elif model == time_model2:
114+
return "a + b * x + log(x) * k"
115+
elif model == time_model3:
116+
return "a + b * log(x)^2 + log(x) * k"
117+
elif model == time_model4:
118+
return "a * log(x)^3 + b * log(x)^2 + log(x) * k"
119+
else:
120+
return "Unknown model"
121+
122+
102123
def scrub_data(s):
103124
r"""Scrubs data fields of characters not allowed by PostgreSQL
104125
@@ -2496,7 +2517,6 @@ def _resource_allocation_plot_helper(
24962517
cmin = naturalsize(cmin_value, gnu=True) if curr == "MaxRSSRaw" else \
24972518
str(timedelta(seconds=round(cmin_value, 2))).rstrip('0').rstrip('.')
24982519

2499-
25002520
x_plot = np.array(df[col_name])
25012521
failures_df = _resource_allocation_failures(
25022522
df, k, a, b, best_model, col_name, curr)
@@ -2505,7 +2525,10 @@ def _resource_allocation_plot_helper(
25052525
ax.scatter(failures_df[col_name], failures_df[curr], color='red', s=3,
25062526
label="failures")
25072527

2508-
ax.set_title(f'{cname}: {sname}\n real: {mini} || {maxi}\n'
2528+
ax.set_title(
2529+
f'k||a||b: {k}||{a}||{b}\n'
2530+
f'model_chosen: {get_model_name(best_model)}\n'
2531+
f'real: {mini} || {maxi}\n'
25092532
f'calculated: {cmin} || {cmax}\n'
25102533
f'failures: {failures}')
25112534
ax.legend(loc='upper left')
@@ -2924,35 +2947,3 @@ def merge_rows(rows):
29242947
row['node_model']]
29252948
qdb.sql_connection.TRN.add(sql, sql_args=to_insert)
29262949
qdb.sql_connection.TRN.execute()
2927-
2928-
2929-
def get_software_commands():
2930-
res = []
2931-
with qdb.sql_connection.TRN:
2932-
sql_command = """
2933-
SELECT DISTINCT
2934-
s.name AS sName,
2935-
s.version AS sVersion,
2936-
sc.name AS cName
2937-
FROM
2938-
qiita.slurm_resource_allocations sra
2939-
JOIN
2940-
qiita.processing_job pr
2941-
ON sra.processing_job_id = pr.processing_job_id
2942-
JOIN
2943-
qiita.software_command sc on pr.command_id = sc.command_id
2944-
JOIN
2945-
qiita.software s ON sc.software_id = s.software_id
2946-
"""
2947-
qdb.sql_connection.TRN.add(sql_command)
2948-
res = qdb.sql_connection.TRN.execute_fetchindex()
2949-
2950-
software_commands = dict()
2951-
for s_name, s_version, c_name in res:
2952-
if s_name not in software_commands:
2953-
software_commands[s_name] = {}
2954-
if s_version not in software_commands[s_name]:
2955-
software_commands[s_name][s_version] = set()
2956-
software_commands[s_name][s_version].add(c_name)
2957-
2958-
return software_commands

scripts/all-qiita-cron-job

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ qiita-cron-job empty-trash-upload-folder
44
qiita-cron-job generate-biom-and-metadata-release
55
qiita-cron-job purge-filepaths
66
qiita-cron-job update-redis-stats
7-
qiita-cron-job initialize-resource-allocations-redis
7+
qiita-cron-job update-resource-allocation-redis
88
qiita-cron-job generate-plugin-releases
99
qiita-cron-job purge-json-web-tokens

scripts/qiita-cron-job

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ from qiita_db.util import (
1616
quick_mounts_purge as qiita_quick_mounts_purge)
1717
from qiita_db.meta_util import (
1818
update_redis_stats as qiita_update_redis_stats,
19-
initialize_resource_allocations_redis as qiita_initialize_resource_allocations_redis,
19+
update_resource_allocation_redis as qiita_update_resource_allocation_redis,
2020
generate_biom_and_metadata_release as
2121
qiita_generate_biom_and_metadata_release,
2222
generate_plugin_releases as qiita_generate_plugin_releases)
@@ -50,8 +50,8 @@ def update_redis_stats():
5050

5151

5252
@commands.command()
53-
def initialize_resource_allocations_redis():
54-
qiita_initialize_resource_allocations_redis()
53+
def update_resource_allocation_redis():
54+
qiita_update_resource_allocation_redis()
5555

5656

5757
@commands.command()

0 commit comments

Comments
 (0)