From b03c778b4d3ec34360e34667839fc5042bb5a470 Mon Sep 17 00:00:00 2001 From: nalonso Date: Mon, 15 Jul 2024 15:58:57 +0200 Subject: [PATCH 1/4] Updated tests for statistics module --- test/unit/test_statistics.py | 151 +++++++++++++++++++++++++---------- 1 file changed, 107 insertions(+), 44 deletions(-) diff --git a/test/unit/test_statistics.py b/test/unit/test_statistics.py index f2c3d84b..c4c1f803 100644 --- a/test/unit/test_statistics.py +++ b/test/unit/test_statistics.py @@ -2,7 +2,7 @@ from datetime import datetime, timedelta import time import pytest # TODO: need to import something or add to project requirements? -from typing import List, Any +from typing import List, Any, Tuple from random import seed, randint, choice from pyparsing import Dict @@ -20,6 +20,80 @@ NUM_JOBS = 1000 # modify this value to test with different job number MAX_NUM_RETRIALS_PER_JOB = 20 # modify this value to test with different retrials number +@pytest.fixture(scope="function") +def job_with_different_retrials(): + job_aux = Job(name="example_name", job_id="example_id", status="COMPLETED", priority=0) + job_aux.processors = "1" + job_aux.wallclock = '00:05' + job_aux.section = "example_section" + job_aux.member = "example_member" + job_aux.chunk = "example_chunk" + job_aux.processors_per_node = "1" + job_aux.tasks = "1" + job_aux.nodes = "1" + job_aux.exclusive = "example_exclusive" + job_aux.retrials = 7 + + retrials = [ + [ + datetime(2024, 3, 2, 15, 24, 16), + datetime(2024, 3, 2, 15, 26, 14), + datetime(2024, 3, 3, 00, 10, 7), + "COMPLETED" + ], + [ + datetime(2024, 3, 2, 15, 17, 31), + datetime(2024, 3, 2, 15, 23, 45), + datetime(2024, 3, 2, 15, 24, 45), + "FAILED" + ], + [ + datetime(2024, 3, 2, 15, 17, 31), + datetime(1970, 1, 1, 2, 00, 00), + datetime(2024, 3, 2, 15, 23, 45), + "FAILED" + ], + [ + datetime(2024, 3, 2, 15, 17, 31), + datetime(2024, 3, 2, 15, 23, 45), + datetime(1970, 1, 1, 2, 00, 00), + "FAILED" + ], + [ + datetime(2024, 3, 2, 15, 17, 31), + datetime(2024, 3, 2, 15, 23, 45), + "FAILED" + ], + [ + datetime(2024, 3, 2, 15, 17, 31), + datetime(1970, 1, 1, 2, 00, 00), + "FAILED" + ], + [ + datetime(2024, 3, 2, 15, 17, 31), + "FAILED" + ] + ] + job_aux.get_last_retrials = lambda: retrials + + job_stat_aux = JobStat("example_name", 1, float(5)/60, "example_section", + "example_date", "example_member", "example_chunk", "1", + "1", "1", "example_exclusive") + + job_stat_aux.submit_time = retrials[len(retrials) - 1][0] + job_stat_aux.start_time = None + job_stat_aux.finish_time = None + job_stat_aux.completed_queue_time = timedelta(seconds=118) + job_stat_aux.completed_run_time = timedelta(seconds=31433) + job_stat_aux.failed_queue_time = timedelta(seconds=374) * 3 + timedelta() * 2 + job_stat_aux.failed_run_time = timedelta(seconds=60) + timedelta(days=19784, seconds=48225) + timedelta() + job_stat_aux.retrial_count = 7 + job_stat_aux.completed_retrial_count = 1 + job_stat_aux.failed_retrial_count = 6 + + return [job_aux], job_stat_aux + + @pytest.fixture(scope="function") def jobs_instances(): # type: () -> List[Job] @@ -70,7 +144,7 @@ def jobs_instances(): else: retrial[3] = job_aux.status retrials.append(retrial) - job_aux.get_last_retrials = lambda: retrials # override get_last_retrials method, similar to mock + job_aux.get_last_retrials = lambda: retrials jobs.append(job_aux) return jobs @@ -146,18 +220,18 @@ def summary_instance_as_list(summary_instance): # type: (StatsSummary) -> List[str] return [ "Summary: ", - "{} : {}".format("CPU Consumption Percentage", str(summary_instance.cpu_consumption_percentage) + "%"), - "{} : {:,} hrs.".format("Total Queue Time", round(summary_instance.total_queue_time, 2)), - "{} : {:,}".format("Submitted Count", summary_instance.submitted_count), - "{} : {:,}".format("Run Count", summary_instance.run_count), - "{} : {:,}".format("Completed Count", summary_instance.completed_count), - "{} : {:,}".format("Failed Count", summary_instance.failed_count), - "{} : {:,} hrs.".format("Expected Consumption", round(summary_instance.expected_consumption, 4)), - "{} : {:,} hrs.".format("Real Consumption", round(summary_instance.real_consumption, 4)), - "{} : {:,} hrs.".format("Failed Real Consumption", round(summary_instance.failed_real_consumption, 4)), - "{} : {:,} hrs.".format("Expected CPU Consumption", round(summary_instance.expected_cpu_consumption, 4)), - "{} : {:,} hrs.".format("CPU Consumption", round(summary_instance.cpu_consumption, 4)), - "{} : {:,} hrs.".format("Failed CPU Consumption", round(summary_instance.failed_cpu_consumption, 4)) + "CPU Consumption Percentage : " + "{}".format(str(summary_instance.cpu_consumption_percentage) + "%"), + "Total Queue Time : " + "{:,}".format((round(summary_instance.total_queue_time, 2))) + " hrs.", + "Submitted Count : " + "{:,}".format(summary_instance.submitted_count), + "Run Count : " + "{:,}".format(summary_instance.run_count), + "Completed Count : " + "{:,}".format(summary_instance.completed_count), + "Failed Count : " + "{:,}".format(summary_instance.failed_count), + "Expected Consumption : " + "{:,}".format(round(summary_instance.expected_consumption, 4)) + " hrs.", + "Real Consumption : " + "{:,}".format(round(summary_instance.real_consumption, 4)) + " hrs.", + "Failed Real Consumption : " + "{:,}".format(round(summary_instance.failed_real_consumption, 4)) + " hrs.", + "Expected CPU Consumption : " + "{:,}".format(round(summary_instance.expected_cpu_consumption, 4)) + " hrs.", + "CPU Consumption : " + "{:,}".format(round(summary_instance.cpu_consumption, 4)) + " hrs.", + "Failed CPU Consumption : " + "{:,}".format(round(summary_instance.failed_cpu_consumption, 4)) + " hrs." ] @@ -207,36 +281,25 @@ def test_working_functions(jobs_instances): exp_stats.build_failed_jobs_only_list() -def test_calculate_statistics(statistics_instance, jobs_instances): - # type: (Statistics, List[Job]) -> None - stats = statistics_instance - job_list = jobs_instances - job_stats = stats.calculate_statistics() - - assert len(job_stats) == len(job_list) - for index, job_stat in enumerate(job_stats): - original_retrials = job_list[index].get_last_retrials() - last_retrial = original_retrials[(len(original_retrials) - 1)] - - assert job_stat.retrial_count == len(original_retrials) - assert job_stat.completed_retrial_count == len( - [retrial for retrial in original_retrials - if len(retrial) == 4 and retrial[3] == "COMPLETED"]) - - assert job_stat.failed_retrial_count == len( - [retrial for retrial in original_retrials - if (len(retrial) == 4 and retrial[3] != "COMPLETED") - or (len(retrial) < 4)]) - - assert job_stat.submit_time == ( - last_retrial[0] if (len(last_retrial) == 4 or len(last_retrial) == 3 or len(last_retrial) == 2) else None) - assert job_stat.start_time == (last_retrial[1] if (len(last_retrial) == 4 or len(last_retrial) == 3) else None) - assert job_stat.finish_time == (last_retrial[2] if (len(last_retrial) == 4) else None) - - # TODO: by making retrials creation random it is "imposible" to predict the results of: - # TODO: completed_queue_time, completed_run_time, failed_queue_time, failed_run_time - # TODO: idea, remove randomness and create a fixed dataset dependending on a constant, easier to test - +def test_calculate_statistics(statistics_instance, job_with_different_retrials): + # type: (Statistics, Tuple[List[Job], JobStat]) -> None + statistics_instance._jobs = job_with_different_retrials[0] + + job_stats = statistics_instance.calculate_statistics() + + # Times + assert job_stats[0].submit_time == job_with_different_retrials[1].submit_time + assert job_stats[0].start_time == job_with_different_retrials[1].start_time + assert job_stats[0].finish_time == job_with_different_retrials[1].finish_time + # Retrials + assert job_stats[0].retrial_count == job_with_different_retrials[1].retrial_count + assert job_stats[0].completed_retrial_count == job_with_different_retrials[1].completed_retrial_count + assert job_stats[0].failed_retrial_count == job_with_different_retrials[1].failed_retrial_count + # Queue/run times + assert job_stats[0].completed_queue_time == job_with_different_retrials[1].completed_queue_time + assert job_stats[0].completed_run_time == job_with_different_retrials[1].completed_run_time + assert job_stats[0].failed_queue_time == job_with_different_retrials[1].failed_queue_time + assert job_stats[0].failed_run_time == job_with_different_retrials[1].failed_run_time def test_calculate_summary(statistics_instance, summary_instance): -- GitLab From bb54e50b60c035a239afa2422095f128a4a3cd69 Mon Sep 17 00:00:00 2001 From: nalonso Date: Tue, 16 Jul 2024 14:16:59 +0200 Subject: [PATCH 2/4] Initial commit --- autosubmit/autosubmit.py | 10 +- autosubmit/monitor/diagram.py | 202 ++++++++++++++++++++++++++-------- autosubmit/monitor/monitor.py | 20 +++- 3 files changed, 180 insertions(+), 52 deletions(-) diff --git a/autosubmit/autosubmit.py b/autosubmit/autosubmit.py index 8d3516c3..4e23fc95 100644 --- a/autosubmit/autosubmit.py +++ b/autosubmit/autosubmit.py @@ -311,6 +311,8 @@ class Autosubmit: 'in number of hours back') subparser.add_argument('-o', '--output', choices=('pdf', 'png', 'ps', 'svg'), default='pdf', help='type of output for generated plot') + subparser.add_argument('-s', '--include_summary', action='store_true', default=False, + help='Includes summary in the plot') subparser.add_argument('--hide', action='store_true', default=False, help='hides plot window') subparser.add_argument('-nt', '--notransitive', action='store_true', @@ -715,7 +717,7 @@ class Autosubmit: args.expand_status, args.hide_groups, args.notransitive, args.check_wrapper, args.txt_logfiles, args.profile, detail=False) elif args.command == 'stats': - return Autosubmit.statistics(args.expid, args.filter_type, args.filter_period, args.output, args.hide, + return Autosubmit.statistics(args.expid, args.filter_type, args.filter_period, args.output, args.include_summary, args.hide, args.notransitive, args.database) elif args.command == 'clean': return Autosubmit.clean(args.expid, args.project, args.plot, args.stats) @@ -2780,7 +2782,7 @@ class Autosubmit: return True @staticmethod - def statistics(expid, filter_type, filter_period, file_format, hide, notransitive=False, db = False): + def statistics(expid, filter_type, filter_period, file_format, summary, hide, notransitive=False, db = False): """ Plots statistics graph for a given experiment. Plot is created in experiment's plot folder with name __