Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
|-----------------|------------------|-------------|------------|
| andrewcoughtrie | Andrew Coughtrie | Met Office | 2026-03-05 |
| mo-marqh | mark Hedley | Met Office | 2026-03-10 |
| oakleybrunt | Oakley Brunt | Met Office | 2026-03-09 |
| oakleybrunt | Oakley Brunt | Met Office | 2026-03-09 |
| EdHone | Ed Hone | Met Office | 2026-03-20 |
8 changes: 4 additions & 4 deletions post-processing/tests/data/vernier-output-test
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ Profiling on 1 thread(s).
(Size; Size/sec; Size/call; MinSize; MaxSize)
(self) (sec) (sec) (sec) ms/call ms/call

1 44.130 2.583 2.583 5.854 1 2583.167 5853.527 __test_app__
2 34.563 4.606 2.023 2.077 2 1011.582 1038.697 some_process
1 44.130 2.583 2.583 5.854 1 2583.167 5853.527 __test_app__@0
2 34.563 4.606 2.023 2.077 2 1011.582 1038.697 some_process@0

Task 2 of 2 : MPI rank ID 1
Profiling on 1 thread(s).
Expand All @@ -16,5 +16,5 @@ Profiling on 1 thread(s).
(Size; Size/sec; Size/call; MinSize; MaxSize)
(self) (sec) (sec) (sec) ms/call ms/call

1 43.991 3.009 3.009 3.069 2 1504.362 1534.740 some_process
2 37.835 5.596 2.588 6.839 1 2587.638 6839.336 __test_app__
1 43.991 3.009 3.009 3.069 2 1504.362 1534.740 some_process@0
2 37.835 5.596 2.588 6.839 1 2587.638 6839.336 __test_app__@0
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

Task 1 of 2 : MPI rank ID 0
Profiling on 4 thread(s).

# % Time Cumul Self Total # of calls Self Total Routine@
(Size; Size/sec; Size/call; MinSize; MaxSize)
(self) (sec) (sec) (sec) ms/call ms/call

1 40.000 2.000 2.000 3.000 2 1000.075 1500.115 MAIN_SUB@0
2 40.000 4.000 2.000 5.000 1 2000.140 5000.373 FULL@0
3 20.000 5.000 1.000 1.000 1 1000.073 1000.073 MAIN_SUB2@3
4 20.000 6.000 1.000 2.000 1 1000.072 2000.152 MAIN_SUB@3
5 20.000 7.001 1.000 1.000 1 1000.072 1000.072 MAIN_SUB2@0
6 20.000 8.001 1.000 1.000 1 1000.071 1000.071 MAIN_SUB2@2
7 20.000 9.001 1.000 1.000 1 1000.069 1000.069 MAIN_SUB2@1
8 20.000 10.001 1.000 2.000 1 1000.068 2000.151 MAIN_SUB@2
9 20.000 11.001 1.000 2.000 1 1000.067 2000.150 MAIN_SUB@1
10 0.000 11.001 0.000 0.000 2 0.008 0.008 __vernier__@2
11 0.000 11.001 0.000 0.000 4 0.004 0.004 __vernier__@0
12 0.000 11.001 0.000 0.000 2 0.008 0.008 __vernier__@1
13 0.000 11.001 0.000 0.000 2 0.007 0.007 __vernier__@3
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

Task 2 of 2 : MPI rank ID 1
Profiling on 4 thread(s).

# % Time Cumul Self Total # of calls Self Total Routine@
(Size; Size/sec; Size/call; MinSize; MaxSize)
(self) (sec) (sec) (sec) ms/call ms/call

1 40.031 2.004 2.004 5.006 1 2003.948 5005.940 FULL@0
2 39.956 4.004 2.000 3.002 2 1000.084 1500.991 MAIN_SUB@0
3 20.056 5.008 1.004 1.004 1 1003.995 1003.995 MAIN_SUB2@1
4 20.017 6.010 1.002 1.002 1 1002.034 1002.034 MAIN_SUB2@3
5 20.012 7.012 1.002 1.002 1 1001.809 1001.809 MAIN_SUB2@0
6 19.979 8.012 1.000 1.000 1 1000.149 1000.149 MAIN_SUB2@2
7 19.978 9.012 1.000 2.004 1 1000.063 2004.060 MAIN_SUB@1
8 19.978 10.012 1.000 2.002 1 1000.063 2002.101 MAIN_SUB@3
9 19.977 11.012 1.000 2.000 1 1000.038 2000.191 MAIN_SUB@2
10 0.002 11.012 0.000 0.000 2 0.052 0.052 __vernier__@2
11 0.002 11.012 0.000 0.000 2 0.052 0.052 __vernier__@1
12 0.002 11.013 0.000 0.000 2 0.052 0.052 __vernier__@3
13 0.001 11.013 0.000 0.000 4 0.007 0.007 __vernier__@0
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ Profiling on 1 thread(s).
(Size; Size/sec; Size/call; MinSize; MaxSize)
(self) (sec) (sec) (sec) ms/call ms/call

1 44.130 2.583 2.583 5.854 1 2583.167 5853.527 __test_app__
2 34.563 4.606 2.023 2.077 2 1011.582 1038.697 some_process
1 44.130 2.583 2.583 5.854 1 2583.167 5853.527 __test_app__@0
2 34.563 4.606 2.023 2.077 2 1011.582 1038.697 some_process@0
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ Profiling on 1 thread(s).
(Size; Size/sec; Size/call; MinSize; MaxSize)
(self) (sec) (sec) (sec) ms/call ms/call

1 43.991 3.009 3.009 3.069 2 1504.362 1534.740 some_process
2 37.835 5.596 2.588 6.839 1 2587.638 6839.336 __test_app__
1 43.991 3.009 3.009 3.069 2 1504.362 1534.740 some_process@0
2 37.835 5.596 2.588 6.839 1 2587.638 6839.336 __test_app__@0
6 changes: 3 additions & 3 deletions post-processing/tests/test_cli_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ def setUp(self):
self.test_data_dir = Path(__file__).parent / 'data'
# pylint: disable=line-too-long
self.test_data_kgo = (
'| Routine | Total time (s) | Self (s) | Cumul time (s) | No. calls | % time | Time per call (s) |\n' +
'| __test_app__ | 6.3465 | 2.5855 | 4.0895 | 1 | 40.9825 | 6.3465 |\n' +
'| some_process | 2.573 | 2.516 | 3.8075 | 2 | 39.277 | 1.2865 |\n'
'| Routine | Total time (s) | Self (s) | Cumul time (s) | Max no. calls | % time | Time per call (s) |\n' +
'| __test_app__ | 6.3465 | 2.5855 | 4.0895 | 1 | 40.9825 | 6.3465 |\n' +
'| some_process | 2.573 | 2.516 | 3.8075 | 2 | 39.277 | 1.2865 |\n'
)
return super().setUp()

Expand Down
126 changes: 108 additions & 18 deletions post-processing/tests/test_vernier_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,89 @@ def test_add_empty_calliper(self):
self.assertEqual(self.test_data.data["test_calliper"].self_time, [])
self.assertEqual(self.test_data.data["test_calliper"].total_time, [])
self.assertEqual(self.test_data.data["test_calliper"].n_calls, [])
self.assertEqual(self.test_data.data["test_calliper"].rank, [])
self.assertEqual(self.test_data.data["test_calliper"].thread, [])

def test_get(self):
"""
Tests that the get method of VernierData returns the expected data.
"""
self.test_data.add_calliper("test_calliper")
self.test_data.data["test_calliper"].time_percent = [10.0, 20.0]
self.test_data.data["test_calliper"].cumul_time = [30.0, 40.0]
self.test_data.data["test_calliper"].self_time = [5.0, 15.0]
self.test_data.data["test_calliper"].total_time = [25.0, 35.0]
self.test_data.data["test_calliper"].n_calls = [2, 2]
self.test_data.data["test_calliper"].rank = [0, 1]
self.test_data.data["test_calliper"].thread = [0, 0]
calliper_data = self.test_data.get("test_calliper")
self.assertEqual(calliper_data.time_percent, [10.0, 20.0])
self.assertEqual(calliper_data.cumul_time, [30.0, 40.0])
self.assertEqual(calliper_data.self_time, [5.0, 15.0])
self.assertEqual(calliper_data.total_time, [25.0, 35.0])
self.assertEqual(calliper_data.n_calls, [2, 2])
self.assertEqual(calliper_data.rank, [0, 1])
self.assertEqual(calliper_data.thread, [0, 0])

def test_get_rank(self):
"""
Tests getter for data from a single rank
"""
self.test_data.add_calliper("test_calliper")
self.test_data.data["test_calliper"].time_percent = [10.0, 20.0]
self.test_data.data["test_calliper"].cumul_time = [30.0, 40.0]
self.test_data.data["test_calliper"].self_time = [5.0, 15.0]
self.test_data.data["test_calliper"].total_time = [25.0, 35.0]
self.test_data.data["test_calliper"].n_calls = [2, 2]
self.test_data.data["test_calliper"].rank = [0, 1]
self.test_data.data["test_calliper"].thread = [0, 0]
calliper_data = self.test_data.get("test_calliper", rank=1)
self.assertEqual(calliper_data.time_percent, [20.0])
self.assertEqual(calliper_data.cumul_time, [40.0])
self.assertEqual(calliper_data.self_time, [15.0])
self.assertEqual(calliper_data.total_time, [35.0])
self.assertEqual(calliper_data.n_calls, [2])
self.assertEqual(calliper_data.rank, [1])
self.assertEqual(calliper_data.thread, [0])

def test_get_thread(self):
"""
Tests getter for data from a single thread
"""
self.test_data.add_calliper("test_calliper")
self.test_data.data["test_calliper"].time_percent = [10.0, 20.0]
self.test_data.data["test_calliper"].cumul_time = [30.0, 40.0]
self.test_data.data["test_calliper"].self_time = [5.0, 15.0]
self.test_data.data["test_calliper"].total_time = [25.0, 35.0]
self.test_data.data["test_calliper"].n_calls = [2, 2]
self.test_data.data["test_calliper"].rank = [0, 0]
self.test_data.data["test_calliper"].thread = [0, 1]
calliper_data = self.test_data.get("test_calliper", thread=1)
self.assertEqual(calliper_data.time_percent, [20.0])
self.assertEqual(calliper_data.cumul_time, [40.0])
self.assertEqual(calliper_data.self_time, [15.0])
self.assertEqual(calliper_data.total_time, [35.0])
self.assertEqual(calliper_data.n_calls, [2])
self.assertEqual(calliper_data.rank, [0])
self.assertEqual(calliper_data.thread, [1])

def test_get_rank_and_thread(self):
self.test_data.add_calliper("test_calliper")
self.test_data.data["test_calliper"].time_percent = [10.0, 20.0, 10.5, 20.5]
self.test_data.data["test_calliper"].cumul_time = [30.0, 40.0, 30.5, 40.5]
self.test_data.data["test_calliper"].self_time = [5.0, 15.0, 5.5, 15.5]
self.test_data.data["test_calliper"].total_time = [25.0, 35.0, 25.5, 35.5]
self.test_data.data["test_calliper"].n_calls = [2, 2, 2, 2]
self.test_data.data["test_calliper"].rank = [0, 0, 1, 1]
self.test_data.data["test_calliper"].thread = [0, 1, 0, 1]
calliper_data = self.test_data.get("test_calliper", thread=1, rank=1)
self.assertEqual(calliper_data.time_percent, [20.5])
self.assertEqual(calliper_data.cumul_time, [40.5])
self.assertEqual(calliper_data.self_time, [15.5])
self.assertEqual(calliper_data.total_time, [35.5])
self.assertEqual(calliper_data.n_calls, [2])
self.assertEqual(calliper_data.rank, [1])
self.assertEqual(calliper_data.thread, [1])

def test_filter_calliper(self):
"""
Expand Down Expand Up @@ -91,14 +174,16 @@ def test_write_txt_output_file(self):
self.test_data.data["test_calliper"].self_time = [5.0, 15.0]
self.test_data.data["test_calliper"].total_time = [25.0, 35.0]
self.test_data.data["test_calliper"].n_calls = [2]
self.test_data.data["test_calliper"].rank = [0, 1]
self.test_data.data["test_calliper"].thread = [0, 0]

# pylint: disable=unspecified-encoding
with tempfile.NamedTemporaryFile(delete=False) as tmp_file:
self.test_data.write_txt_output(Path(tmp_file.name))
contents = Path(tmp_file.name).read_text().splitlines()
# pylint: disable=line-too-long
self.assertEqual("| Routine | Total time (s) | Self (s) | Cumul time (s) | No. calls | % time | Time per call (s) |", contents[0])
self.assertEqual("| test_calliper | 30.0 | 10.0 | 35.0 | 2 | 15.0 | 15.0 |", contents[1])
self.assertEqual("| Routine | Total time (s) | Self (s) | Cumul time (s) | Max no. calls | % time | Time per call (s) |", contents[0])
self.assertEqual("| test_calliper | 30.0 | 10.0 | 35.0 | 2 | 15.0 | 15.0 |", contents[1])

def test_write_txt_output_terminal(self):
"""
Expand All @@ -111,15 +196,17 @@ def test_write_txt_output_terminal(self):
self.test_data.data["test_calliper"].self_time = [3.0, 4.0]
self.test_data.data["test_calliper"].total_time = [15.0, 55.0]
self.test_data.data["test_calliper"].n_calls = [2]
self.test_data.data["test_calliper"].rank = [0, 1]
self.test_data.data["test_calliper"].thread = [0, 0]

write_output = StringIO()
sys.stdout = write_output
self.test_data.write_txt_output()
sys.stdout = sys.__stdout__

# pylint: disable=line-too-long
self.assertEqual("| Routine | Total time (s) | Self (s) | Cumul time (s) | No. calls | % time | Time per call (s) |", write_output.getvalue().splitlines()[0])
self.assertEqual("| test_calliper | 35.0 | 3.5 | 11.0 | 2 | 45.0 | 17.5 |", write_output.getvalue().splitlines()[1])
self.assertEqual("| Routine | Total time (s) | Self (s) | Cumul time (s) | Max no. calls | % time | Time per call (s) |", write_output.getvalue().splitlines()[0])
self.assertEqual("| test_calliper | 35.0 | 3.5 | 11.0 | 2 | 45.0 | 17.5 |", write_output.getvalue().splitlines()[1])

def test_aggregate(self):
"""
Expand All @@ -133,6 +220,8 @@ def test_aggregate(self):
data1.data["calliper_a"].self_time = [5.0, 15.0]
data1.data["calliper_a"].total_time = [25.0, 35.0]
data1.data["calliper_a"].n_calls = [2, 2]
data1.data["calliper_a"].rank = [0, 1]
data1.data["calliper_a"].thread = [0, 0]

data2 = VernierData()
data2.add_calliper("calliper_a")
Expand All @@ -141,6 +230,8 @@ def test_aggregate(self):
data2.data["calliper_a"].self_time = [6.0, 16.0]
data2.data["calliper_a"].total_time = [28.0, 38.0]
data2.data["calliper_a"].n_calls = [3, 3]
data2.data["calliper_a"].rank = [0, 1]
data2.data["calliper_a"].thread = [0, 0]

aggregated = VernierData()
aggregated.aggregate([data1, data2])
Expand Down Expand Up @@ -174,6 +265,8 @@ def test_aggregate_inconsistent(self):
data1.data["calliper_a"].self_time = [5.0, 15.0]
data1.data["calliper_a"].total_time = [25.0, 35.0]
data1.data["calliper_a"].n_calls = [2, 2]
data1.data["calliper_a"].rank = [0, 1]
data1.data["calliper_a"].thread = [0, 0]

data2 = VernierData()
data2.add_calliper("calliper_b")
Expand All @@ -182,6 +275,8 @@ def test_aggregate_inconsistent(self):
data2.data["calliper_b"].self_time = [6.0, 16.0]
data2.data["calliper_b"].total_time = [28.0, 38.0]
data2.data["calliper_b"].n_calls = [3, 3]
data2.data["calliper_b"].rank = [0, 1]
data2.data["calliper_b"].thread = [0, 0]

with self.assertRaises(ValueError):
aggregated = VernierData()
Expand All @@ -203,19 +298,6 @@ def test_aggregate_inconsistent_ok(self):
self.assertIn("calliper_a", aggregated.data)
self.assertIn("calliper_b", aggregated.data)

def test_get(self):
"""
Test that the get method of the VernierData class works as expected.
"""
data1 = VernierData()
data1.add_calliper("calliper_a")
data1.data["calliper_a"].time_percent = [10.0, 20.0]
data1.data["calliper_a"].cumul_time = [30.0, 40.0]
data1.data["calliper_a"].self_time = [5.0, 15.0]
data1.data["calliper_a"].total_time = [25.0, 35.0]
data1.data["calliper_a"].n_calls = [2, 2]
self.assertEqual(len(data1.get("calliper_a")), 2)


class TestVernierCollation(unittest.TestCase):
"""
Expand All @@ -233,6 +315,8 @@ def _add_data(self):
data1.data["calliper_a"].self_time = [5.0, 15.0]
data1.data["calliper_a"].total_time = [25.0, 35.0]
data1.data["calliper_a"].n_calls = [2, 2]
data1.data["calliper_a"].rank = [0, 1]
data1.data["calliper_a"].thread = [0, 0]

data2 = VernierData()
data2.add_calliper("calliper_a")
Expand All @@ -241,6 +325,8 @@ def _add_data(self):
data2.data["calliper_a"].self_time = [6.0, 16.0]
data2.data["calliper_a"].total_time = [28.0, 38.0]
data2.data["calliper_a"].n_calls = [3, 3]
data2.data["calliper_a"].rank = [0, 1]
data2.data["calliper_a"].thread = [0, 0]

self.collation.add_data('test1', data1)
self.collation.add_data('test2', data2)
Expand All @@ -262,7 +348,7 @@ def test_remove_data(self):
self.collation.remove_data('test1')
self.assertEqual(len(self.collation), 1)

def test_get(self):
def test_get__collation(self):
"""
Test that the get method of VernierCollation returns the expected
VernierData instance.
Expand All @@ -284,13 +370,17 @@ def test_internal_consistency(self):
data_inc.data["calliper_a"].self_time = [5.0, 15.0]
data_inc.data["calliper_a"].total_time = [25.0, 35.0]
data_inc.data["calliper_a"].n_calls = [2, 2]
data_inc.data["calliper_a"].rank = [0, 1]
data_inc.data["calliper_a"].thread = [0, 0]

data_inc.add_calliper("calliper_b")
data_inc.data["calliper_b"].time_percent = [15.0, 25.0]
data_inc.data["calliper_b"].cumul_time = [35.0, 45.0]
data_inc.data["calliper_b"].self_time = [6.0, 16.0]
data_inc.data["calliper_b"].total_time = [28.0, 38.0]
data_inc.data["calliper_b"].n_calls = [3, 3]
data_inc.data["calliper_b"].rank = [0, 1]
data_inc.data["calliper_b"].thread = [0, 0]

with self.assertRaises(ValueError) as test_exception:
self.collation.add_data('test3', data_inc)
Expand Down
Loading
Loading