|
3 | 3 | # |
4 | 4 | # SPDX-License-Identifier: BSD-3-Clause |
5 | 5 |
|
6 | | -import contextlib |
7 | 6 | import reframe as rfm |
8 | 7 | import reframe.utility.sanity as sn |
9 | 8 |
|
10 | 9 |
|
11 | 10 | @rfm.simple_test |
12 | 11 | class CPMDCheck(rfm.RunOnlyRegressionTest): |
13 | | - scale = parameter(['small', 'large']) |
14 | | - descr = 'CPMD check (C4H6 metadynamics)' |
15 | | - maintainers = ['AJ', 'LM'] |
16 | | - tags = {'production'} |
17 | | - valid_systems = ['daint:gpu'] |
18 | | - num_tasks_per_node = 1 |
19 | | - valid_prog_environs = ['builtin'] |
20 | 12 | modules = ['CPMD'] |
21 | 13 | executable = 'cpmd.x' |
22 | | - executable_opts = ['ana_c4h6.in > stdout.txt'] |
23 | | - readonly_files = ['ana_c4h6.in', 'C_MT_BLYP', 'H_MT_BLYP'] |
24 | | - use_multithreading = True |
25 | | - strict_check = False |
| 14 | + executable_opts = ['ana_c4h6.in'] |
26 | 15 | extra_resources = { |
27 | 16 | 'switches': { |
28 | 17 | 'num_switches': 1 |
29 | 18 | } |
30 | 19 | } |
31 | | - allref = { |
32 | | - '9': { |
33 | | - 'p100': { |
34 | | - 'time': (284, None, 0.15, 's') |
| 20 | + strict_check = False |
| 21 | + use_multithreading = False |
| 22 | + tags = {'maintenance', 'production'} |
| 23 | + maintainers = ['AJ', 'LM'] |
| 24 | + |
| 25 | + num_nodes = parameter([6, 16], loggable=True) |
| 26 | + references = { |
| 27 | + 6: { |
| 28 | + 'sm_60': { |
| 29 | + 'dom:gpu': {'time': (120, None, 0.15, 's')}, |
| 30 | + 'daint:gpu': {'time': (120, None, 0.15, 's')}, |
| 31 | + }, |
| 32 | + 'broadwell': { |
| 33 | + 'dom:mc': {'time': (150.0, None, 0.15, 's')}, |
| 34 | + 'daint:mc': {'time': (150.0, None, 0.15, 's')}, |
35 | 35 | }, |
36 | 36 | }, |
37 | | - '16': { |
38 | | - 'p100': { |
39 | | - 'time': (226, None, 0.15, 's') |
40 | | - } |
| 37 | + 16: { |
| 38 | + 'sm_60': { |
| 39 | + 'daint:gpu': {'time': (120, None, 0.15, 's')} |
| 40 | + }, |
| 41 | + 'broadwell': { |
| 42 | + 'daint:mc': {'time': (150.0, None, 0.15, 's')}, |
| 43 | + }, |
41 | 44 | } |
42 | 45 | } |
43 | 46 |
|
44 | | - @run_after('init') |
45 | | - def setup_by_scale(self): |
46 | | - if self.scale == 'small': |
47 | | - self.valid_systems += ['dom:gpu'] |
48 | | - self.num_tasks = 9 |
49 | | - else: |
50 | | - self.num_tasks = 16 |
51 | | - |
52 | | - @run_before('performance') |
53 | | - def set_perf_reference(self): |
54 | | - proc = self.current_partition.processor |
55 | | - pname = self.current_partition.fullname |
56 | | - if pname in ('daint:gpu', 'dom:gpu'): |
57 | | - arch = 'p100' |
58 | | - else: |
59 | | - arch = proc.arch |
60 | | - |
61 | | - with contextlib.suppress(KeyError): |
62 | | - self.reference = { |
63 | | - pname: { |
64 | | - 'perf': self.allref[self.num_tasks][arch][self.benchmark] |
65 | | - } |
66 | | - } |
| 47 | + @performance_function('s') |
| 48 | + def elapsed_time(self): |
| 49 | + return sn.extractsingle(r'^ cpmd(\s+[\d\.]+){3}\s+(?P<time>\S+)', |
| 50 | + self.stdout, 'time', float) |
67 | 51 |
|
68 | 52 | @sanity_function |
69 | 53 | def assert_energy_diff(self): |
70 | | - # OpenMP version of CPMD segfaults |
71 | | - # self.variables = { 'OMP_NUM_THREADS' : '8' } |
72 | 54 | energy = sn.extractsingle( |
73 | 55 | r'CLASSICAL ENERGY\s+-(?P<result>\S+)', |
74 | | - 'stdout.txt', 'result', float) |
| 56 | + self.stdout, 'result', float) |
75 | 57 | energy_reference = 25.81 |
76 | 58 | energy_diff = sn.abs(energy - energy_reference) |
77 | 59 | return sn.assert_lt(energy_diff, 0.26) |
78 | 60 |
|
79 | | - @performance_function('s') |
80 | | - def time(self): |
81 | | - return sn.extractsingle(r'^ cpmd(\s+[\d\.]+){3}\s+(?P<perf>\S+)', |
82 | | - 'stdout.txt', 'perf', float) |
| 61 | + @run_after('init') |
| 62 | + def setup_system_filtering(self): |
| 63 | + self.descr = f'CPMD check ({self.num_nodes} node(s))' |
| 64 | + |
| 65 | + # setup system filter |
| 66 | + valid_systems = { |
| 67 | + 6: ['daint:gpu', 'daint:mc', 'dom:gpu', 'dom:mc'], |
| 68 | + 16: ['daint:gpu', 'daint:mc'] |
| 69 | + } |
| 70 | + |
| 71 | + self.skip_if(self.num_nodes not in valid_systems, |
| 72 | + f'No valid systems found for {self.num_nodes}(s)') |
| 73 | + self.valid_systems = valid_systems[self.num_nodes] |
| 74 | + |
| 75 | + # setup programming environment filter |
| 76 | + self.valid_prog_environs = ['builtin'] |
| 77 | + |
| 78 | + @run_before('run') |
| 79 | + def setup_run(self): |
| 80 | + # retrieve processor data |
| 81 | + self.skip_if_no_procinfo() |
| 82 | + proc = self.current_partition.processor |
| 83 | + |
| 84 | + # set architecture for GPU partition (no auto-detection) |
| 85 | + if self.current_partition.fullname in ['daint:gpu', 'dom:gpu']: |
| 86 | + arch = 'sm_60' |
| 87 | + self.variables = { |
| 88 | + 'CRAY_CUDA_MPS': '1' |
| 89 | + } |
| 90 | + else: |
| 91 | + arch = proc.arch |
| 92 | + |
| 93 | + # common setup for every architecture |
| 94 | + self.job.launcher.options = ['--cpu-bind=cores'] |
| 95 | + self.job.options = ['--distribution=block:block'] |
| 96 | + # FIXME: the current test case does not scale beyond 72 MPI tasks, |
| 97 | + # so the last node in 16-nodes jobs will be used only partially. |
| 98 | + # The test case needs to be updated (warning about XC_DRIVER IN &DFT) |
| 99 | + self.num_tasks = 72 |
| 100 | + |
| 101 | + try: |
| 102 | + found = self.references[self.num_nodes][arch] |
| 103 | + except KeyError: |
| 104 | + self.skip(f'Configuration with {self.num_nodes} node(s) ' |
| 105 | + f'is not supported on {arch!r}') |
| 106 | + |
| 107 | + # setup performance references |
| 108 | + self.reference = self.references[self.num_nodes][arch] |
0 commit comments