Improve dependency file generation#1815
Conversation
* Search for all f90 files in dirs list once * Sort f90 files based on module name and location * Generate all dependencies files together if first time compiling * Fix issue generating dependencies on case insensitive file systems
The GNU Make shell function replaces carriage returns with spaces. This makes the output from the makedep.py difficult to read. The revised logic creates a new .PHONY target which will be executed when the compile script calls 'make -f Makefile'. The ifeq test within the .PHONY target will trigger 'make depend' to force generation of all dependency files if necessary; otherwise the target is essentially a no-op.
| # PHONY target to generate all dependency files at once if no dependency files | ||
| # are found, avoiding shell function to preserve carriage returns. | ||
| .PHONY: conditional_depend | ||
| conditional_depend: |
There was a problem hiding this comment.
Hi @emkemp
I should have mentioned that I tried this but the problem is the above line, -include $(DEPS) triggers %.d: %.F90 rules before any targets are executed, which builds dependency files one at a time. This is too slow, especially after changing os.path.isfile calls to set(Path(d).glob('*.f90')).
There's an alternative solution using target groups &: but this is only available in GNU Make 4.3 and newer, and Discover uses v4.2.
I also didn't like that the the GNU shell call function replaces newlines with spaces but couldn't find a better way. We do have the option to suppress the output entirely.
This reverts commit ecabaa5.
|
Hi @danrosen25 I see your point, and I reverted my changes. I wonder if it is worth changing the compile script to check if any .d files exist, and if not, call 'make depend' before calling 'make -f Makefile $njobs'. That would avoid use of that shell function, though it could be kept as a fail-safe. |
|
@emkemp That would work. The only caveat I can see is that the logic here specifically checks for any of the .d files listed in $(DEPS). So if there is a |
The lis/make/Makefile will use the shell function to run the makedep.py script if no dependency files are found in the lis/make directory. Unfortunately, the shell function removes the carriage returns from the output, which makes the message from makedep.py a bit difficult to read. Note that GNU Make doesn't provide an option to change this behavior as the shell function runs. With this change, the compile script will check to see if any dependency files are in lis/make. If not, compile will print warning messages and proceed to generating all dependencies up front, as if "./compile -m" was invoked.
|
Hi @danrosen25 I want to discuss this with @jvgeiger before making a final decision on this. But my thinking is that, if no .d files are available, it's probably safest to just do a complete rebuild from scratch. |
danrosen25
left a comment
There was a problem hiding this comment.
@emkemp
I'm suggesting the following changes to the compile script for POSIX-shell compatibility. Do these work for you? The old changes were causing an error.
Tweak to lis/compile for POSIX support. Co-authored-by: Daniel Rosen <drosen@ucar.edu>
Co-authored-by: Daniel Rosen <drosen@ucar.edu>
|
@danrosen25 I like your suggestions, and committed them to the PR. |
|
Regarding "Generate all dependencies files together if first time compiling", I believe that this is not needed. You can run the Would you please make case folding opt-in instead of default? The |
|
@jvgeiger The reason I even started this work is because I know it's not a high priority to run on Mac OS systems but I can't even run in a container on a Mac OS system if the volume from the Mac OS system is bind mounted into the container, which is how Dev Containers work. I'm looking to enhance the development portability so that development and testing don't have to happen on a small set of HPCs. |
|
Just to be clear, I like your changes to Yes, we only support Unix/Linux systems with case-sensitive file systems, but I understand your need to support a case-insensive file system. I ask that you make the case folding opt-in because I cannot control the development of third-party models that we incorporate into LIS. I like the performance improvements in By the way, you can combine the |
|
@jvgeiger Okay, I'll have to make some makedep.py changes to make it more efficient in the single dependency generation case if that's going to be the default. What I'll do when there is a single file is call Path(d).glob('.f90|.F90') for the directory of the current file and search for the module then Path(d).glob('.f90|.F90') for other directories. Path(d).glob is slow but supports case-insensitive file systems. The performance improvements in this PR come from calling glob as few times as possible. The code I'm replacing called os.path.isfile followed by glob.glob for each module search in each directory. |
|
Hello Dan, I apologize for my confusion. I do not understand your response. Please correct me where I am wrong. To me, your changes to Is |
|
@jvgeiger
If you're running makedep.py for a single file then you'd want to sort the directories by most likely and run Path.glob() then check the files in that directory then run Path.glob() on the next directory. This reduces the Path.glob calls depending on where it finds the module. os.path.isfile(), which is what is being replaced because it can't handle case insensitive file systems, takes 0.00005 seconds. Although os.path.isfile was only finding files sometimes and then it would go to .glob afterwards. |
Description
Improve dependency file generation speed and portability. Dependency file generation does not currently work from within a Docker container that has bind mounted the LISF source code from a case-insensitive file system #1814. Dependency file generation is slow due to multiple calls to list the contents of repeated directories and inefficient searching through directories. This PR reduces calls to list directory contents and sorts that list based on the module name and file location. These PR changes are particularly efficient if all dependency files are generated in a single call to
makedep.pybecause it only generates a list of f90 files once. ThereforeMakefileis also enhanced to determine if dependency files have not been generated yet and it will make a single call tomakedep.py. Compile time on Discover is reduced by 4m50s due to a ~77% reduction in dependency file generation time.Note: Single dependency file generation is often slower because previously the
makedep.pyfile would search for module_name.f90 files without building a list of all f90 files. But the logic did not support case-insensitive file systems. Generating dependency files one at a time is only marginally slower on Discover. It went from ~4m56s to ~5m15s to generate all dependency files one at a time. I have ideas to improve the single dependency file generation but it seems unnecessary.Improvements to compile time
total build time on Discover before changes: 33m39s
total build time on Discover after changes: 28m49s
Improvements to bulk dependency file generation
baseline
make depend: 3m25simproved
make depend: 1m20sResolves #1814
Change Log
Testcase
Tested on Discover using lisf_7.5_intel_2023.2.1_s2s with the following user.cfg settings