Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vernier #8

Merged
merged 10 commits into from
Feb 4, 2025
10 changes: 10 additions & 0 deletions infrastructure/build/fab/baf_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ def __init__(self, name, root_symbol=None):
self._tool_box = ToolBox()
parser = self.define_command_line_options()
self.handle_command_line_options(parser)
# Now allow further site-customisations depending on
# the command line arguments
self._site_config.handle_command_line_options(self._args)

if root_symbol:
self._root_symbol = root_symbol
Expand Down Expand Up @@ -103,6 +106,13 @@ def config(self):
'''
return self._config

@property
def args(self):
''':returns: the arg parse objects containing the user's
command line information.
'''
return self._args

def define_site_platform_target(self):
'''This method defines the attributes site, platform (and
target=site-platform) based on the command line option --site
Expand Down
22 changes: 22 additions & 0 deletions infrastructure/build/fab/default/config.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
#! /usr/bin/env python3


'''This module contains the default Baf configuration class.
'''

from default.setup_gnu import setup_gnu
from default.setup_intel_classic import setup_intel_classic


class Config:
'''This class is the default Configuration object for Baf builds.
It provides several callbacks which will be called from the build
scripts to allow site-specific customisations.
'''

def update_toolbox(self, build_config):
'''Set the default compiler flags for the various compiler
Expand All @@ -14,8 +22,22 @@ def update_toolbox(self, build_config):
self.setup_classic_intel(build_config)
self.setup_gnu(build_config)

def handle_command_line_options(self, args):
'''Additional callback function executed once all command line
options have been added. This is for example used to add
Vernier profiling flags, which are site-specific.
'''

def setup_classic_intel(self, build_config):
'''For now call an external function, since it is expected that
this configuration can be very lengthy (once we support
compiler modes).
'''
setup_intel_classic(build_config)

def setup_gnu(self, build_config):
'''For now call an external function, since it is expected that
this configuration can be very lengthy (once we support
compiler modes).
'''
setup_gnu(build_config)
4 changes: 3 additions & 1 deletion infrastructure/build/fab/default/setup_gnu.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
This function gets called from the default site-specific config file
'''

from typing import cast
from fab.build_config import BuildConfig
from fab.tools import Category, ToolRepository
from fab.tools import Category, Linker, ToolRepository


def setup_gnu(build_config: BuildConfig):
Expand Down Expand Up @@ -38,6 +39,7 @@ def setup_gnu(build_config: BuildConfig):
# This will implicitly affect all gfortran based linkers, e.g.
# linker-mpif90-gfortran will use these flags as well.
linker = tr.get_tool(Category.LINKER, "linker-gfortran")
linker = cast(Linker, linker)
linker.add_lib_flags("netcdf", nc_flibs)
linker.add_lib_flags("yaxt", ["-lyaxt", "-lyaxt_c"])
linker.add_lib_flags("xios", ["-lxios"])
Expand Down
6 changes: 5 additions & 1 deletion infrastructure/build/fab/default/setup_intel_classic.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
This function gets called from the default site-specific config file
'''

from typing import cast

from fab.build_config import BuildConfig
from fab.tools import Category, ToolRepository
from fab.tools import Category, Compiler, Linker, ToolRepository


def setup_intel_classic(build_config: BuildConfig):
Expand All @@ -25,6 +27,7 @@ def setup_intel_classic(build_config: BuildConfig):
# that the intel compiler actually works.
return

ifort = cast(Compiler, ifort)
# The flag groups are mainly from infrastructure/build/fortran
# /ifort.mk
no_optimisation_flags = ['-O0']
Expand Down Expand Up @@ -81,6 +84,7 @@ def setup_intel_classic(build_config: BuildConfig):
# This will implicitly affect all ifort based linkers, e.g.
# linker-mpif90-ifort will use these flags as well.
linker = tr.get_tool(Category.LINKER, "linker-ifort")
linker = cast(Linker, linker)
linker.add_lib_flags("netcdf", nc_flibs)
linker.add_lib_flags("yaxt", ["-lyaxt", "-lyaxt_c"])
linker.add_lib_flags("xios", ["-lxios"])
Expand Down
31 changes: 27 additions & 4 deletions infrastructure/build/fab/joerg_default/config.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,40 @@
#! /usr/bin/env python3

from fab.tools import ToolRepository
'''This module contains a setup for Joerg's laptop :)
'''

import argparse
from typing import cast

from fab.tools import Category, Linker, ToolRepository

from default.config import Config as DefaultConfig


class Config(DefaultConfig):
'''We need additional include flags for gfortran. Define this
by overwriting setup_gnu.
Also make gnu the default compiler.
'''This config class sets specific flags for Joerg's laptop :)
It makes gnu the default suite, and adds support for Vernier.
'''

def __init__(self):
super().__init__()
tr = ToolRepository()
tr.set_default_compiler_suite("gnu")

def handle_command_line_options(self, args: argparse.Namespace):
'''Called with the user's command line options. It checks if
Vernier profiling is requested, and if so, adds the required
include and linking flags.
'''

super().handle_command_line_options(args)
if args.vernier:
tr = ToolRepository()
gfortran = tr.get_tool(Category.FORTRAN_COMPILER, "gfortran")
gfortran.add_flags(
['-I', '/home/joerg/work/Vernier/local/include'])
linker = tr.get_tool(Category.LINKER, "linker-gfortran")
linker = cast(Linker, linker)
linker.add_lib_flags(
"vernier", ["-L", "/home/joerg/work/Vernier/local/lib",
"-lvernier_f", "-lvernier_c", "-lvernier"])
75 changes: 46 additions & 29 deletions infrastructure/build/fab/lfric_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def __init__(self, name, root_symbol=None):
# We need to find the apps directory (it will be required when
# finding source files in the build scripts). We shouldn't assume
# that it is 'next' to the core directory, nor should we assume
# that the name is 'apps'. In order to avoid reliance of any
# that the name is 'apps'. In order to avoid reliance on any
# environment variable, we analyse the call tree to find the first
# call that is not in our parent directory (in case that we ever
# add another layer of base class).
Expand Down Expand Up @@ -106,9 +106,11 @@ class which can provide its own instance (to easily allow for a
'--rose_picker', '-rp', type=str, default="v2.0.0",
help="Version of rose_picker. Use 'system' to use an installed "
"version.")
parser.add_argument("--vernier", action="store_true", default=False,
help="Support profiling with Vernier.")
parser.add_argument(
'--profile', '-pro', type=str, default="fast-debug",
help="Profie mode for compilation, choose from \
help="Profile mode for compilation, choose from \
'fast-debug'(default), 'full-debug', 'production'")
parser.add_argument(
'--precision', '-pre', type=str, default=None,
Expand Down Expand Up @@ -174,7 +176,10 @@ def get_linker_flags(self) -> List[str]:

:returns: list of flags for the linker.
'''
return ['yaxt', 'xios', 'netcdf', 'hdf5'] + super().get_linker_flags()
libs = ['yaxt', 'xios', 'netcdf', 'hdf5']
if self._args.vernier:
libs.append("vernier")
return libs + super().get_linker_flags()

def grab_files(self):
dirs = ['infrastructure/source/',
Expand All @@ -195,24 +200,26 @@ def grab_files(self):
grab_folder(self.config, src=self.lfric_core_root / dir,
dst_label='psyclone_config')

# Get the implementation of the PSyData API for profiling when using
# TAU. wget requires internet, which gitlab runner does not have.
# So I temporarily store the tau_psy.f90 in this repo under
# `infrastructure/source/psydata``. During the install stage, this
# folder will be copied to lfric_core checkout.
# tau_psy.f90 will therefore be grabbed when `infrastructure/source``
# is grabbed.
# compiler = self.config.tool_box[Category.FORTRAN_COMPILER]
# linker = self.config.tool_box[Category.LINKER]
# if "tau_f90.sh" in [compiler.exec_name, linker.exec_name]:
# _dst = self.config.source_root / 'psydata'
# if not _dst.is_dir():
# _dst.mkdir(parents=True)
# wget = Tool("wget", "wget")
# wget.run(additional_parameters=['-N',
# 'https://raw.githubusercontent.com/stfc/PSyclone/'
# 'master/lib/profiling/tau/tau_psy.f90'],
# cwd=_dst)
compiler = self.config.tool_box[Category.FORTRAN_COMPILER]
linker = self.config.tool_box.get_tool(Category.LINKER,
mpi=self.config.mpi,
openmp=self.config.openmp)
if (self.args.vernier or
"tau_f90.sh" in [compiler.exec_name, linker.exec_name]):
# Profiling. Grab the required psydata directory as well:
if self.args.vernier:
try:
linker.get_lib_flags("vernier")
except RuntimeError:
raise RuntimeError(f"The linker{linker} does not have "
f"linker flags for Vernier.")
dir = "vernier"

else:
dir = "tau"
grab_folder(self.config, src=self.lfric_core_root /
"infrastructure" / "build" / "psyclone" / "psydata"
/ dir, dst_label='psydata')

def find_source_files(self, path_filters=None):
self.configurator()
Expand Down Expand Up @@ -282,22 +289,32 @@ def preprocess_x90(self):

def psyclone(self):
psyclone_cli_args = self.get_psyclone_config()
compiler = self.config.tool_box[Category.FORTRAN_COMPILER]
linker = self.config.tool_box.get_tool(Category.LINKER,
mpi=self.config.mpi)
if "tau_f90.sh" in [compiler.exec_name, linker.exec_name]:
psyclone_cli_args.extend(self.get_psyclone_profiling_option())
psyclone_cli_args.extend(self.get_additional_psyclone_options())

psyclone(self.config, kernel_roots=[self.config.build_output],
transformation_script=self.get_transformation_script,
api="dynamo0.3",
cli_args=psyclone_cli_args)

def get_psyclone_config(self):
def get_psyclone_config(self) -> List[str]:
''':returns: the command line options to pick the right
PSyclone config file.
'''
return ["--config", self._psyclone_config]

def get_psyclone_profiling_option(self):
return ["--profile", "kernels"]
def get_additional_psyclone_options(self) -> List[str]:
''':returns: Additional PSyclone command line options. This
basic version checks if profiling using Tau or Vernier
is enabled, and if so, adds the kernel profiling flags
to PSyclone.
'''
compiler = self.config.tool_box[Category.FORTRAN_COMPILER]
linker = self.config.tool_box.get_tool(Category.LINKER,
mpi=self.config.mpi)
if (self.args.vernier or
"tau_f90.sh" in [compiler.exec_name, linker.exec_name]):
return ["--profile", "kernels"]
return []

def get_transformation_script(self, fpath, config):
''':returns: the transformation script to be used by PSyclone.
Expand Down
Loading