Source code for reframechecks.common.sphexa.sanity_mpip

# Copyright 2019-2021 Swiss National Supercomputing Centre (CSCS/ETH Zurich)
# HPCTools Project Developers. See the top-level LICENSE file for details.
#
# SPDX-License-Identifier: BSD-3-Clause

import os
import reframe as rfm
import reframe.utility.sanity as sn
from reframe.core.fields import ScopedDict
import sphexa.sanity as sphs
# import sphexa.sanity_intel as sphsintel


[docs]class MpipBaseTest(rfm.RegressionTest): def __init__(self): x = 0 # {{{ others @rfm.run_before('sanity') def rpt_file_txt(self): # As the report output file is hardcoded ( using getpid: # https://github.com/LLNL/mpiP/blob/master/mpiPi.c#L935 ), i.e changing # at every job, it's needed to extract the filename from stdout: self.rpt = sn.extractsingle( r'^mpiP: Storing mpiP output in \[(?P<rpt>.*)\]', self.stdout, 'rpt', str) # }}} # {{{ sanity patterns @rfm.run_before('sanity') def mpip_sanity_patterns(self): '''Checks tool's version: .. code-block:: > cat ./sqpatch.exe.6.31820.1.mpiP @ mpiP @ Command : sqpatch.exe -n 62 -s 1 @ Version : 3.4.2 <-- 57fc864 ''' reference_tool_version = { 'daint': '3.4.2', 'dom': '3.4.2', } ref_version = reference_tool_version[self.current_system.name] regex = r'^@ Version\s+: (?P<toolversion>\S+)$' res_version = sn.extractsingle(regex, self.rpt, 'toolversion') self.sanity_patterns = sn.all([ # check the job output: sn.assert_found(r'Total time for iteration\(0\)', self.stdout), # check the tool version: sn.assert_eq(res_version, ref_version), ]) # }}} # {{{ performance patterns # --- 1 @rfm.run_before('performance') def set_basic_perf_patterns(self): '''A set of basic perf_patterns shared between the tests ''' self.perf_patterns = sn.evaluate(sphs.basic_perf_patterns(self)) # --- 2 @rfm.run_before('performance') def set_mpip_perf_patterns(self): '''More perf_patterns for the tool .. code-block:: ----------------------------------- @--- MPI Time (seconds) ----------- ----------------------------------- Task AppTime MPITime MPI% 0 8.6 0.121 1.40 <-- min 1 8.6 0.157 1.82 2 8.6 5.92 68.84 <-- max * 25.8 6.2 24.02 <--- => NonMPI= AppTime - MPITime Typical performance reporting: .. code-block:: * mpip_avg_app_time: 8.6 s (= 25.8/3mpi) * mpip_avg_mpi_time: 2.07 s (= 6.2/3mpi) * %mpip_avg_mpi_time: 24.02 % * %mpip_avg_non_mpi_time: 75.98 % ''' regex_star = r'^\s+\*\s+(?P<appt>\S+)\s+(?P<mpit>\S+)\s+(?P<pct>\S+)$' app_t = sn.extractsingle(regex_star, self.rpt, 'appt', float) mpi_t = sn.extractsingle(regex_star, self.rpt, 'mpit', float) mpi_pct = sn.extractsingle(regex_star, self.rpt, 'pct', float) nonmpi_pct = sn.round(100 - mpi_pct, 2) # min/max regex = (r'^\s+(?P<mpirk>\S+)\s+(?P<appt>\S+)\s+(?P<mpit>\S+)\s+' r'(?P<pct>\S+)$') mpi_pct_max = sn.max(sn.extractall(regex, self.rpt, 'pct', float)) mpi_pct_min = sn.min(sn.extractall(regex, self.rpt, 'pct', float)) perf_pattern = { 'mpip_avg_app_time': sn.round(app_t / self.num_tasks, 2), 'mpip_avg_mpi_time': sn.round(mpi_t / self.num_tasks, 2), '%mpip_avg_mpi_time': mpi_pct, '%mpip_avg_mpi_time_max': mpi_pct_max, '%mpip_avg_mpi_time_min': mpi_pct_min, '%mpip_avg_non_mpi_time': nonmpi_pct, } if self.perf_patterns: self.perf_patterns = {**self.perf_patterns, **perf_pattern} else: self.perf_patterns = perf_pattern # }}} # {{{ performance reference # --- 1 @rfm.run_before('performance') def set_basic_reference(self): self.reference = sn.evaluate(sphs.basic_reference_scoped_d(self)) # --- 2 @rfm.run_before('performance') def set_mpip_reference(self): ref = ScopedDict() # first, copy the existing self.reference (if any): if self.reference: for kk in self.reference: ref[kk] = self.reference['*:%s' % kk] # then add more: myzero_s = (0, None, None, 's') myzero_p = (0, None, None, '%') ref['mpip_avg_app_time'] = myzero_s ref['mpip_avg_mpi_time'] = myzero_s ref['%mpip_avg_mpi_time'] = myzero_p ref['%mpip_avg_non_mpi_time'] = myzero_p ref['%mpip_avg_mpi_time_max'] = myzero_p ref['%mpip_avg_mpi_time_min'] = myzero_p # final reference: self.reference = ref
# }}} @sn.sanity_function def mpip_perf_patterns(obj, reg): '''More perf_patterns for the tool .. code-block:: ----------------------------------- @--- MPI Time (seconds) ----------- ----------------------------------- Task AppTime MPITime MPI% 0 8.6 0.121 1.40 <-- min 1 8.6 0.157 1.82 2 8.6 5.92 68.84 <-- max * 25.8 6.2 24.02 <--- => NonMPI= AppTime - MPITime Typical performance reporting: .. code-block:: * mpip_avg_app_time: 8.6 s (= 25.8/3mpi) * mpip_avg_mpi_time: 2.07 s (= 6.2/3mpi) * %mpip_avg_mpi_time: 24.02 % * %max/%min * %mpip_avg_non_mpi_time: 75.98 % ''' # rpt = os.path.join(obj.stagedir, obj.rpt_file_txt) rpt = sn.extractsingle( r'^mpiP: Storing mpiP output in \[(?P<rpt>.*)\]', obj.stdout, 'rpt', str ) regex_star = r'^\s+\*\s+(?P<appt>\S+)\s+(?P<mpit>\S+)\s+(?P<pct>\S+)$' regex_minmax = (r'^\s+(?P<mpirk>\S+)\s+(?P<appt>\S+)\s+(?P<mpit>\S+)\s+' r'(?P<pct>\S+)$') if reg == 1: # mpip_avg_mpi_time result = sn.round( sn.extractsingle(regex_star, rpt, 'mpit', float) / obj.num_tasks, 2 ) elif reg == 2: # mpip_avg_app_time result = sn.round( sn.extractsingle(regex_star, rpt, 'appt', float) / obj.num_tasks, 2 ) elif reg == 3: # %mpip_avg_mpi_time result = sn.extractsingle(regex_star, rpt, 'pct', float) elif reg == 4: # %nonmpi mpi_pct = sn.extractsingle(regex_star, rpt, 'pct', float) result = sn.round(100 - mpi_pct, 2) elif reg == 5: # %mpip_avg_mpi_time_max result = sn.max(sn.extractall(regex_minmax, rpt, 'pct', float)) elif reg == 6: # %mpip_avg_mpi_time_min result = sn.min(sn.extractall(regex_minmax, rpt, 'pct', float)) else: raise ValueError('unknown region id in mpip_perf_patterns') return result