Skip to content

Commit 8b3cca5

Browse files
committed
--case-optimization refresh
1 parent cb349d7 commit 8b3cca5

File tree

10 files changed

+213
-180
lines changed

10 files changed

+213
-180
lines changed

CMakeLists.txt

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,8 @@ macro(HANDLE_SOURCES target useCommon)
229229
set(${target}_DIR "${CMAKE_SOURCE_DIR}/src/${target}")
230230
set(common_DIR "${CMAKE_SOURCE_DIR}/src/common")
231231

232+
string(TOUPPER ${target} ${target}_UPPER)
233+
232234
# Gather src/[<target>,common]/*.f90
233235
file(GLOB ${target}_F90s CONFIGURE_DEPENDS "${${target}_DIR}/*.f90")
234236
set(${target}_SRCs ${${target}_F90s})
@@ -245,9 +247,9 @@ macro(HANDLE_SOURCES target useCommon)
245247
endif()
246248

247249
# Locate src/[<target>,common]/include/*.fpp
248-
if (EXISTS "${${target}_DIR}/include")
249-
file(GLOB ${target}_incs CONFIGURE_DEPENDS "${${target}_DIR}/include/*.fpp")
250-
endif()
250+
file(GLOB ${target}_incs CONFIGURE_DEPENDS "${${target}_DIR}/include/*.fpp"
251+
"${CMAKE_CURRENT_BINARY_DIR}/include/*.fpp")
252+
251253
if (${useCommon})
252254
file(GLOB common_incs CONFIGURE_DEPENDS "${common_DIR}/include/*.fpp")
253255
list(APPEND ${target}_incs ${common_incs})
@@ -261,11 +263,14 @@ macro(HANDLE_SOURCES target useCommon)
261263
add_custom_command(
262264
OUTPUT ${f90}
263265
COMMAND ${FYPP_EXE} -m re
264-
-I "${common_DIR}"
265-
-I "${common_DIR}/include"
266+
-I "${CMAKE_CURRENT_BINARY_DIR}/include"
266267
-I "${${target}_DIR}/include"
268+
-I "${common_DIR}/include"
269+
-I "${common_DIR}"
267270
-D MFC_${CMAKE_Fortran_COMPILER_ID}
271+
-D MFC_${${target}_UPPER}
268272
-D MFC_COMPILER="${CMAKE_Fortran_COMPILER_ID}"
273+
-D MFC_CASE_OPTIMIZATION=False
269274
--line-numbering
270275
--no-folding
271276
"${fpp}" "${f90}"
@@ -317,10 +322,10 @@ function(MFC_SETUP_TARGET)
317322
"${CMAKE_SOURCE_DIR}/src/${ARGS_TARGET}/include")
318323
endif()
319324

320-
string(TOUPPER "${ARGS_TARGET}" ARGS_TARGET_UPPER)
325+
string(TOUPPER "${ARGS_TARGET}" ${ARGS_TARGET}_UPPER)
321326
target_compile_definitions(
322327
${ARGS_TARGET} PRIVATE MFC_${CMAKE_Fortran_COMPILER_ID}
323-
MFC_${ARGS_TARGET_UPPER}
328+
MFC_${${ARGS_TARGET}_UPPER}
324329
)
325330

326331
if (MFC_MPI AND ARGS_MPI)

src/pre_process/include/case.fpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
! This file was generated by MFC. It is only used when analytical patches are
2-
! present in the input file. It is used to define the analytical patches with
3-
! expressions that are evaluated at runtime from the input file.
1+
! By default, no analytical patches are defined.
42

53
#:def analytical()
6-
74
#:enddef

src/simulation/include/case.fpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,2 @@
1-
! This file was generated by MFC. It is only used if the --case-optimization
2-
! option is passed to ./mfc.sh run or test, enabling a GPU-oriented optimization
3-
! that hard-codes certain case parameters from the input file.
4-
5-
#:set MFC_CASE_OPTIMIZATION = False
1+
! This file is purposefully empty. It is only important for builds that make use
2+
! of --case-optimization.

toolchain/mfc/args.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import re, os.path, argparse, dataclasses
22

33
from .build import TARGETS, DEFAULT_TARGETS, DEPENDENCY_TARGETS
4-
from .common import format_list_to_string
4+
from .common import MFCException, format_list_to_string
55
from .test.test import CASES as TEST_CASES
66
from .packer import packer
77

@@ -45,7 +45,7 @@ def add_common_arguments(p, mask = None):
4545

4646
if "t" not in mask:
4747
p.add_argument("-t", "--targets", metavar="TARGET", nargs="+", type=str.lower, choices=[ _.name for _ in TARGETS ],
48-
default=[ _.name for _ in DEFAULT_TARGETS ],
48+
default=[ _.name for _ in sorted(DEFAULT_TARGETS, key=lambda t: t.runOrder) ],
4949
help=f"Space separated list of targets to act upon. Allowed values are: {format_list_to_string([ _.name for _ in TARGETS ])}.")
5050

5151
if "m" not in mask:
@@ -70,6 +70,8 @@ def add_common_arguments(p, mask = None):
7070

7171
# === BUILD ===
7272
add_common_arguments(build, "g")
73+
build.add_argument("-i", "--input", type=str, default=None, help="(GPU Optimization) Build a version of MFC optimized for a case.")
74+
build.add_argument("--case-optimization", action="store_true", default=False, help="(GPU Optimization) Compile MFC targets with some case parameters hard-coded (requires --input).")
7375

7476
# === CLEAN ===
7577
add_common_arguments(clean, "jg")
@@ -146,6 +148,12 @@ def append_defaults_to_data(name: str, parser):
146148
# "Slugify" the name of the job
147149
args["name"] = re.sub(r'[\W_]+', '-', args["name"])
148150

151+
# build's --case-optimization and --input depend on each other
152+
if args["command"] == "build":
153+
if (args["input"] is not None) ^ args["case_optimization"] :
154+
raise MFCException(f"./mfc.sh build's --case-optimization requires --input")
155+
156+
# Input files to absolute paths
149157
for e in ["input", "input1", "input2"]:
150158
if e not in args:
151159
continue

toolchain/mfc/build.py

Lines changed: 87 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
import re, os, typing, dataclasses
1+
import re, os, typing, hashlib, dataclasses
22

33
from .common import MFCException, system, delete_directory, create_directory
44
from .state import ARG, CFG
55
from .printer import cons
6-
from .run.input import MFCInputFile
7-
6+
from .run import input
87

98
@dataclasses.dataclass
109
class MFCTarget:
@@ -26,19 +25,27 @@ def compute(self) -> typing.Set:
2625
isDefault: bool # Should it be built by default? (unspecified -t | --targets)
2726
isRequired: bool # Should it always be built? (no matter what -t | --targets is)
2827
requires: Dependencies # Build dependencies of the target
28+
runOrder: int # For MFC Targets: Order in which targets should logically run
2929

3030
def __hash__(self) -> int:
3131
return hash(self.name)
3232

3333
# Get path to directory that will store the build files
3434
def get_build_dirpath(self) -> str:
35+
subdir = 'dependencies' if self.isDependency else CFG().make_slug()
36+
37+
if not self.isDependency and ARG("case_optimization"):
38+
m = hashlib.sha256()
39+
m.update(input.load().get_fpp(self).encode())
40+
subdir = f"{subdir}-{m.hexdigest()[:6]}"
41+
3542
return os.sep.join([
3643
os.getcwd(),
3744
"build",
38-
[CFG().make_slug(), 'dependencies'][int(self.isDependency)],
45+
subdir,
3946
self.name
4047
])
41-
48+
4249
# Get the directory that contains the target's CMakeLists.txt
4350
def get_cmake_dirpath(self) -> str:
4451
# The CMakeLists.txt file is located:
@@ -84,31 +91,16 @@ def get_configuration_txt(self) -> typing.Optional[dict]:
8491

8592
return None
8693

87-
88-
def build(self, history: typing.Set[str] = None):
89-
if history is None:
90-
history = set()
91-
92-
if self.name in history:
93-
return
94-
95-
history.add(self.name)
96-
97-
build_targets(REQUIRED_TARGETS, history)
98-
99-
cons.print(f"[bold]Building [magenta]{self.name}[/magenta]:[/bold]")
100-
cons.indent()
101-
94+
def is_buildable(self) -> bool:
10295
if ARG("no_build"):
103-
cons.print("--no-build specified, skipping...")
104-
cons.unindent()
105-
return
96+
return False
10697

10798
if self.isDependency and ARG(f"no_{self.name}"):
108-
cons.print(f"--no-{self.name} given, skipping...")
109-
cons.unindent()
110-
return
99+
return False
111100

101+
return True
102+
103+
def configure(self):
112104
build_dirpath = self.get_build_dirpath()
113105
cmake_dirpath = self.get_cmake_dirpath()
114106
install_dirpath = self.get_install_dirpath()
@@ -144,42 +136,36 @@ def build(self, history: typing.Set[str] = None):
144136
flags.append(f"-DMFC_OpenACC={'ON' if ARG('gpu') else 'OFF'}")
145137

146138
configure = ["cmake"] + flags + ["-S", cmake_dirpath, "-B", build_dirpath]
147-
build = ["cmake", "--build", build_dirpath,
148-
"--target", self.name,
149-
"-j", ARG("jobs"),
150-
"--config", 'Debug' if ARG('debug') else 'Release']
151-
if ARG('verbose'):
152-
build.append("--verbose")
153139

154-
install = ["cmake", "--install", build_dirpath]
140+
delete_directory(build_dirpath)
141+
create_directory(build_dirpath)
155142

156-
if not self.is_configured():
157-
build_targets(self.requires.compute(), history)
143+
if system(configure, no_exception=True) != 0:
144+
raise MFCException(f"Failed to configure the [bold magenta]{self.name}[/bold magenta] target.")
145+
146+
147+
def build(self):
148+
if ARG("case_optimization"):
149+
input.load().generate_fpp(self)
158150

159-
delete_directory(build_dirpath)
160-
create_directory(build_dirpath)
151+
build = ["cmake", "--build", self.get_build_dirpath(),
152+
"--target", self.name,
153+
"-j", ARG("jobs"),
154+
"--config", 'Debug' if ARG('debug') else 'Release']
155+
if ARG('verbose'):
156+
build.append("--verbose")
161157

162-
if system(configure, no_exception=True) != 0:
163-
raise MFCException(f"Failed to configure the [bold magenta]{self.name}[/bold magenta] target.")
158+
system(build, exception_text=f"Failed to build the [bold magenta]{self.name}[/bold magenta] target.")
164159

165-
if not self.isDependency and ARG("command") == "build":
166-
MFCInputFile("", "", {}).generate(self, bOnlyFPPs = True)
160+
def install(self):
161+
install = ["cmake", "--install", self.get_build_dirpath()]
167162

168-
system(build, exception_text=f"Failed to build the [bold magenta]{self.name}[/bold magenta] target.")
169163
system(install, exception_text=f"Failed to install the [bold magenta]{self.name}[/bold magenta] target.")
170164

171-
cons.print(no_indent=True)
172-
cons.unindent()
173-
174165
def clean(self):
175-
cons.print(f"[bold]Cleaning [magenta]{self.name}[/magenta]:[/bold]")
176-
cons.indent()
177-
178166
build_dirpath = self.get_build_dirpath()
179167

180168
if not os.path.isdir(build_dirpath):
181-
cons.print("Target not configured. Nothing to clean.")
182-
cons.unindent()
183169
return
184170

185171
clean = ["cmake", "--build", build_dirpath, "--target", "clean",
@@ -190,17 +176,15 @@ def clean(self):
190176

191177
system(clean, exception_text=f"Failed to clean the [bold magenta]{self.name}[/bold magenta] target.")
192178

193-
cons.unindent()
194-
195179

196-
FFTW = MFCTarget('fftw', ['-DMFC_FFTW=ON'], True, False, False, MFCTarget.Dependencies([], [], []))
197-
HDF5 = MFCTarget('hdf5', ['-DMFC_HDF5=ON'], True, False, False, MFCTarget.Dependencies([], [], []))
198-
SILO = MFCTarget('silo', ['-DMFC_SILO=ON'], True, False, False, MFCTarget.Dependencies([HDF5], [], []))
199-
PRE_PROCESS = MFCTarget('pre_process', ['-DMFC_PRE_PROCESS=ON'], False, True, False, MFCTarget.Dependencies([], [], []))
200-
SIMULATION = MFCTarget('simulation', ['-DMFC_SIMULATION=ON'], False, True, False, MFCTarget.Dependencies([], [FFTW], []))
201-
POST_PROCESS = MFCTarget('post_process', ['-DMFC_POST_PROCESS=ON'], False, True, False, MFCTarget.Dependencies([FFTW, SILO], [], []))
202-
SYSCHECK = MFCTarget('syscheck', ['-DMFC_SYSCHECK=ON'], False, False, True, MFCTarget.Dependencies([], [], []))
203-
DOCUMENTATION = MFCTarget('documentation', ['-DMFC_DOCUMENTATION=ON'], False, False, False, MFCTarget.Dependencies([], [], []))
180+
FFTW = MFCTarget('fftw', ['-DMFC_FFTW=ON'], True, False, False, MFCTarget.Dependencies([], [], []), -1)
181+
HDF5 = MFCTarget('hdf5', ['-DMFC_HDF5=ON'], True, False, False, MFCTarget.Dependencies([], [], []), -1)
182+
SILO = MFCTarget('silo', ['-DMFC_SILO=ON'], True, False, False, MFCTarget.Dependencies([HDF5], [], []), -1)
183+
PRE_PROCESS = MFCTarget('pre_process', ['-DMFC_PRE_PROCESS=ON'], False, True, False, MFCTarget.Dependencies([], [], []), 0)
184+
SIMULATION = MFCTarget('simulation', ['-DMFC_SIMULATION=ON'], False, True, False, MFCTarget.Dependencies([], [FFTW], []), 1)
185+
POST_PROCESS = MFCTarget('post_process', ['-DMFC_POST_PROCESS=ON'], False, True, False, MFCTarget.Dependencies([FFTW, SILO], [], []), 2)
186+
SYSCHECK = MFCTarget('syscheck', ['-DMFC_SYSCHECK=ON'], False, False, True, MFCTarget.Dependencies([], [], []), -1)
187+
DOCUMENTATION = MFCTarget('documentation', ['-DMFC_DOCUMENTATION=ON'], False, False, False, MFCTarget.Dependencies([], [], []), -1)
204188

205189
TARGETS = { FFTW, HDF5, SILO, PRE_PROCESS, SIMULATION, POST_PROCESS, SYSCHECK, DOCUMENTATION }
206190

@@ -230,17 +214,55 @@ def get_dependency_install_dirpath() -> str:
230214
raise MFCException("No dependency target found.")
231215

232216

217+
def build_target(target: typing.Union[MFCTarget, str], history: typing.Set[str] = None):
218+
if history is None:
219+
history = set()
220+
221+
t = get_target(target)
222+
223+
if t.name in history or not t.is_buildable():
224+
return
225+
226+
history.add(t.name)
227+
228+
build_targets(t.requires.compute(), history)
229+
230+
if not t.is_configured():
231+
t.configure()
232+
233+
t.build()
234+
t.install()
235+
233236
def build_targets(targets: typing.Iterable[typing.Union[MFCTarget, str]], history: typing.Set[str] = None):
234237
if history is None:
235238
history = set()
239+
240+
for target in list(REQUIRED_TARGETS) + targets:
241+
build_target(target, history)
242+
243+
244+
def clean_target(target: typing.Union[MFCTarget, str], history: typing.Set[str] = None):
245+
if history is None:
246+
history = set()
247+
248+
t = get_target(target)
236249

237-
for target in targets:
238-
get_target(target).build(history)
250+
if t.name in history or not t.is_buildable():
251+
return
239252

253+
history.add(t.name)
254+
255+
t.clean()
256+
257+
258+
def clean_targets(targets: typing.Iterable[typing.Union[MFCTarget, str]], history: typing.Set[str] = None):
259+
if history is None:
260+
history = set()
240261

241-
def clean_targets(targets: typing.Iterable[typing.Union[MFCTarget, str]]):
242-
for target in targets:
243-
get_target(target).clean()
262+
for target in list(REQUIRED_TARGETS) + targets:
263+
t = get_target(target)
264+
if t.is_configured():
265+
t.clean()
244266

245267

246268
def get_configured_targets() -> typing.List[MFCTarget]:

toolchain/mfc/run/engines.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ def run(self, targets: typing.List[MFCTarget]) -> None:
161161

162162
cons.print(f"[bold green]Done[/bold green] (in {datetime.timedelta(seconds=end_time - start_time)})")
163163

164+
cons.print()
164165
cons.unindent()
165166

166167

0 commit comments

Comments
 (0)