|
| 1 | +""" |
| 2 | +This module tests an lbmpy fork twith additional functionality added within the MultiXscale project. |
| 3 | +Long term, the goal is that this will be upstreamed in lbmpy. |
| 4 | +""" |
| 5 | + |
| 6 | +import reframe as rfm |
| 7 | +import reframe.utility.sanity as sn |
| 8 | + |
| 9 | +# added only to make the linter happy |
| 10 | +from reframe.core.builtins import parameter, performance_function, sanity_function, deferrable, run_after |
| 11 | + |
| 12 | +# Import the EESSI_Mixin class so that we can inherit from it |
| 13 | +from eessi.testsuite.eessi_mixin import EESSI_Mixin |
| 14 | +from eessi.testsuite.constants import COMPUTE_UNITS, DEVICE_TYPES, SCALES |
| 15 | +from eessi.testsuite.utils import find_modules |
| 16 | +from eessi.testsuite.hooks import set_compact_thread_binding |
| 17 | + |
| 18 | + |
| 19 | +def filter_singlenode_scales(): |
| 20 | + """ |
| 21 | + Filtering function that returns only single node scales. |
| 22 | + """ |
| 23 | + return [k for (k, v) in SCALES.items() if v['num_nodes'] == 1] |
| 24 | + |
| 25 | + |
| 26 | +@rfm.simple_test |
| 27 | +class EESSI_lbmpy_pssrt(rfm.RunOnlyRegressionTest, EESSI_Mixin): |
| 28 | + """ |
| 29 | + This test case simulates the Kelvin-Helmholtz instabilty where an initial hyperbolic tangent velocity profile |
| 30 | + imposed in a fully periodic 2D square box is slightly perturbed to initiate rolling of the shear layers. |
| 31 | +
|
| 32 | + This use case tests a modified version of lbmpy, with additional functionality. This test cases uses lbmpy with |
| 33 | + OpenMP parallelization. As such, this test will only be instantiated on scales up to 1 full node. |
| 34 | + The runtime is in the order of seconds to minutes. |
| 35 | +
|
| 36 | + The test script takes three (optional) arguments: --grid-size, --run-time, --openmp. |
| 37 | + If grid-size or run-time are modified, the reference value in the assert_normalized_average_kinetic_energy sanity |
| 38 | + check needs to be updated. The reference does _not_ change with the number of threads. |
| 39 | + """ |
| 40 | + |
| 41 | + # lbmpy-pssrt is only parallelized with OpenMP, so no multi-node tests should be ran |
| 42 | + scale = parameter(filter_singlenode_scales()) |
| 43 | + |
| 44 | + device_type = DEVICE_TYPES.CPU |
| 45 | + |
| 46 | + # lbmpy-pssrt is only OpenMP parallel, so launch only one task on a node |
| 47 | + compute_unit = COMPUTE_UNITS.NODE |
| 48 | + |
| 49 | + launcher = 'local' # no MPI module is loaded in this test |
| 50 | + |
| 51 | + module_name = parameter(find_modules('lbmpy-pssrt')) |
| 52 | + |
| 53 | + readonly_files = ['mixing_layer_2D.py'] |
| 54 | + |
| 55 | + executable = 'python' |
| 56 | + # grid-size of 512 seems to scale reasonable to 128 cores, and completes in reasonable time on one core (< 2 mins) |
| 57 | + executable_opts = ['mixing_layer_2D.py', '--grid-size 512'] # 512 seems to scale _reasonable_ to 128 cores |
| 58 | + time_limit = '10m00s' |
| 59 | + |
| 60 | + is_ci_test = True |
| 61 | + |
| 62 | + perf_regex = r'^\s+Median±\(max-min\)\s+=\s+(?P<perf>\S+)±(?P<perf_range>\S+)\s+MLUPS' |
| 63 | + |
| 64 | + def required_mem_per_node(self): |
| 65 | + """ |
| 66 | + Defines the required memory per node to run this test |
| 67 | + """ |
| 68 | + return self.num_cpus_per_task * 5 + 250 |
| 69 | + |
| 70 | + @deferrable |
| 71 | + def assert_normalized_average_kinetic_energy(self): |
| 72 | + """ |
| 73 | + Assert that the normalized average kinetic energy matches the reference (exactly). |
| 74 | + Note that the reference needs to be adjusted if a different --grid-size or --run-time is used. |
| 75 | + It should, however, be robust against changes in the number of threads. |
| 76 | + """ |
| 77 | + regex = r"Normalized Average Kinetic Energy\s+=\s+(?P<energy>\S+)" |
| 78 | + energy = sn.extractsingle(regex, self.stdout, 'energy', float) |
| 79 | + ref_energy = 0.9381 |
| 80 | + return sn.assert_eq(energy, ref_energy) |
| 81 | + |
| 82 | + @sanity_function |
| 83 | + def validate(self): |
| 84 | + """ |
| 85 | + This is the sanity function for this test. Currently, it only checks that |
| 86 | + assert_normalized_average_kinetic_energy is true, but this may be expanded with additional sanity checking |
| 87 | + if needed. |
| 88 | + """ |
| 89 | + return sn.assert_true(self.assert_normalized_average_kinetic_energy()) |
| 90 | + |
| 91 | + @performance_function('MLU/s') |
| 92 | + def lattice_updates(self): |
| 93 | + """ |
| 94 | + This test case reports number of Mega lattice updates per second (and a range) over 5 iterations. |
| 95 | + """ |
| 96 | + return sn.extractsingle(self.perf_regex, self.stdout, 'perf', float) |
| 97 | + |
| 98 | + @performance_function('MLU/s') |
| 99 | + def lattice_updates_range(self): |
| 100 | + """ |
| 101 | + This test case reports range (max-min) of number of Mega lattice updates per second, over 5 iterations. |
| 102 | + In other words, it takes the difference in Mega lattice updates per seconds between the slowest and the |
| 103 | + fastest iteration |
| 104 | + """ |
| 105 | + return sn.extractsingle(self.perf_regex, self.stdout, 'perf_range', float) |
| 106 | + |
| 107 | + @run_after('setup') |
| 108 | + def set_openmp_argument(self): |
| 109 | + """ |
| 110 | + If the number of cpus_per_task is larger than 1, enable OpenMP by setting the --openmp argument. |
| 111 | + Also, set compact thread binding in this case |
| 112 | + """ |
| 113 | + if self.num_cpus_per_task > 1: |
| 114 | + self.executable_opts += ['--openmp'] |
| 115 | + set_compact_thread_binding(self) |
0 commit comments