help-make
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: GNU Make 4.2 Query


From: David Boyce
Subject: Re: GNU Make 4.2 Query
Date: Mon, 2 Sep 2019 11:15:25 -0700

I did not suggest using lsmake, I simply mentioned that we use it.

On Mon, Sep 2, 2019 at 11:04 AM nikhil jain <address@hidden> wrote:

> Thanks for detailed information.
>
> I will see if I can use shell wrapper program as mentioned by you.
>
> I had used LSF a lot like for 5 years. I still use it.  bsub, bjobs.
> bkill, lim, sbatchd, mbatchd etc. it is easy to understand and use
>
> lsmake - I do not want to use IBM's proprietary stuff.
>
> Thanks for your suggestions.
>
> Nikhil
>
> On Mon, Sep 2, 2019 at 11:10 PM David Boyce <address@hidden>
> wrote:
>
>> I'm not going to address the remote execution topic since it sounds like
>> you already have the solution and are not looking for help. However, I do
>> have fairly extensive experience with the NFS/retry area so will try to
>> contribute there.
>>
>> First, I don't think what Paul says:
>>
>> > As for your NFS issue, another option would be to enable the .ONESHELL
>> > feature available in newer versions of GNU make: that will ensure that
>> > all lines in a recipe are invoked in a single shell, which means that
>> > they should all be invoked on the same remote host.
>>
>> Is sufficient. Consider the typical case of compiling foo.c to foo.o and
>> linking it into foo.exe. Typically, and correctly, those actions would be
>> in two separate recipes which in a distributed-build scenario could run on
>> different hosts so the linker may not find the .o file from a previous
>> recipe. Here .ONSHELL cannot help since they're different recipes.
>>
>> In my day job we use a product from IBM called LSF (Load Sharing
>> F-something,
>> https://www.ibm.com/support/knowledgecenter/en/SSETD4_9.1.3/lsf_welcome.html)
>> which exists to distribute jobs over a server farm (typically using NFS)
>> according to various metrics like load and free memory and so on. Part of
>> the LSF package is a program called lsmake (
>> https://www.ibm.com/support/knowledgecenter/en/SSETD4_9.1.3/lsf_command_ref/lsmake.1.html)
>> which under the covers is a version of GNU make with enhancement to enable
>> remote/distributed recipes and also adds retry-with-delay feature Nikhil
>> requested). Since GNU make is GPL, IBM is required to make its package of
>> enhancements available under GPL as well. Much of it is not of direct
>> interest to the open source community because it's all about communicating
>> with IBM's proprietary daemons but their retry logic could probably be
>> taken directly from the patch. At the very least, if retries were to be
>> added to GNU make per se it would be nice if the flags were compatible with
>> lsmake.
>>
>> However, my personal belief is that retries are God's way of telling us
>> to think harder and better. Retrying (and worse, delay-and-retry) is a form
>> of defeatism which I call "sleep and hope". Computers are deterministic,
>> there's always a root cause which can usually be found and addressed with
>> sufficient analysis, etc. Granted there are cases where you understand the
>> problem but can't address it for administrative/permissions/business
>> reasons but that can't be known until the problem is understood.
>>
>> NFS caching is the root cause of unreliable distributed builds, as you've
>> already described, but most or all of these issues can be addressed with a
>> less blunt instrument than sleep-and-retry. Even LSF engineers threw up
>> their hands and did retries but what we did here was take their patch,
>> which at last check was still targeted to 3.81, and while porting it to 4.1
>> added some of the cache-flushing strategies detailed below. This has solved
>> most if not all of our NFS sync problems. Caveat: most of our people still
>> use the LSF retry logic in addition, because they're not as absolutist as I
>> am and just want to get their jobs done (go figure), which makes it harder
>> to determine what percentage of problems are solved by cache flushing vs
>> retries but I'm pretty sure flushing has resolved the great majority of
>> problems.
>>
>> One problem with sleep-and-hope is that there's no amount of time
>> guaranteed to be enough so you're just driving the incidence rate down, not
>> fixing it.
>>
>> Since we were already working with a hacked version of GNU make we found
>> it most convenient to implement flushing directly in the make program but
>> it can also be done within recipes. In fact we have 3 different
>> implementations of the same NFS cache flushing logic:
>>
>> 1. Directly within our enhanced version of lsmake.
>> 2. In a standalone binary called "nfsflush".
>> 3. In a Python script called nfsflush.py.
>>
>> The Python script is a lab for trying out new strategies but it's too
>> slow for production use. The binary is a faster version of the same
>> techniques for direct use in recipes, and that same C code is linked
>> directly into lsmake as well. Here's the usage message of our Python script:
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>>
>> *$ nfsflush.py --helpusage: nfsflush.py [-h] [-f] [-l] [-r] [-t] [-u]
>> [-V] path [path ...]positional arguments:  path             directory paths
>> to flushoptional arguments:  -h, --help       show this help message and
>> exit  -f, --fsync      Use fsync() on named files  -l, --lock       Lock
>> and unlock the named files  -r, --recursive  flush recursively  -t, --touch
>>      additional flush action - touch and remove a temp file  -u, --upflush
>>    flush parent directories back to the root  -V, --verbose    increment
>> verbosity levelFlush the NFS filehandle caches of NFS directories.Newly
>> created files are sometimes unavailable via NFS for a periodof time due to
>> filehandle caching, leading to apparent race problems.See
>> http://tss.iki.fi/nfs-coding-howto.html#fhcache
>> <http://tss.iki.fi/nfs-coding-howto.html#fhcache> for details.This script
>> forces a flush using techniques mentioned in the URL. Itcan optionally do
>> so recursively.This always does an opendir/closedir sequence on each
>> directoryvisited, as described in the URL, because that's cheap and safe
>> andoften sufficient. Other strategies, such as creating and removing atemp
>> file, are optional.EXAMPLES:    nfsflush.py /nfs/path/...*
>>
>> The most important thing is to read the URL given above and/or to google
>> for similar resource of which there are many. While I'm not an NFS guru
>> myself, the summary of my understanding is that NFS caches all sorts of
>> things (metadata like atime/mtime, directory updates, etc) with various
>> degrees of aggression according to NFS vendor and internal configuration.
>> We've seen substantial variation between NAS providers such as NetApp, EMC,
>> etc, so much depends on whose NFS server you're using. However, the NFS
>> spec _requires_ that caches be flushed on a write operation so all
>> implementations will do this.
>>
>> Bottom line, the most common failure case is as mentioned above: foo.o is
>> compiled on host A and immediately linked on host B. The close() system
>> call following the final write() of foo.o on host A will cause its data to
>> be flushed. Similarly I *believe* the directory write (assuming foo.o is
>> newly created and not just updated) will cause the filehandle cache to be
>> flushed. Thus, after these two write ops (directory and file) the NFS
>> server will know about the new foo.o as soon as it's created.
>>
>> The problem typically arises on host B because no write operation has
>> taken place there after foo.o was created on A so no one has told it to
>> update its caches and as a result it doesn't know foo.o exists and the link
>> fails with ENOENT. All the flushing techniques in the script above are
>> attempts to address this. One takeaway from all this is that even if you do
>> retries, a "dumb" retry is immeasurably enhanced by adding a flush. In
>> other words the most efficient retry formula in a distributed build
>> scenario would be:
>>
>> <recipe> || flush || <recipe>
>>
>> This never flushes a cache unless the first attempt fails. It presumes
>> that NFS implementors and admins know what they're doing and thus caching
>> helps with performance so it's not done unless needed. This is what we
>> built into our variant of lsmake. However, the same can also be done in the
>> shell.
>>
>> Details about implemented cache flushing techniques: the filehandle cache
>> is the biggest source of problems in distributed builds and the simplest
>> solution for it seems to be opening and reading the directory entry. Thus
>> our script and its parallel C implementation always do that. We've also
>> seen cases where forcing a directory write operation is required which the
>> -t, --touch option does. Sometimes you can't easily enumerate all
>> directories involved (vpath etc) so the recurse-downward (-r) and recurse
>> upward (-u) flags may be helpful though they (especially -u) may also be
>> overkill. The -f and -l options were added based on advice found on the net
>> but have not been shown to be helpful in our environment.
>>
>> Some techniques may be of limited utility because they require write
>> and/or ownership privileges. For instance I've seen statements that
>> umounts, even failed umounts, will force flushes. Thus a command like "cd
>> <dir> && umount $(pwd)" would have to fail since the moount is busy but
>> would flush as a side effect. However I believe this requires root
>> privileges so is not helpful in the normal case.
>>
>> In summary: although I don't believe in retries, if they're going to be
>> used I think they should be implemented in a shell wrapper program which
>> could be passed to make as SHELL=<wrapper> and the wrapper should use
>> flushing in addition to, or instead of, retries. We didn't do it that way
>> but I think our nfsflush program could just as well have been implemented
>> as say "nfsshell" such that "nfsshell [other-options] -c <recipe>" would
>> run the recipe along with added flushing and retrying options. I agree with
>> Paul that I see no reason to implement any of these features, retry and/or
>> flush, directly in make.
>>
>> David
>>
>> On Mon, Sep 2, 2019 at 6:05 AM Paul Smith <address@hidden> wrote:
>>
>>> On Sun, 2019-09-01 at 23:23 -0700, Kaz Kylheku (gmake) wrote:
>>> > If your R&D team would allow you to add just one line to the
>>> > legacy GNU Makefile to assign the SHELL variable, you can assign that
>>> > to a shell wrapper program which performs command re-trying.
>>>
>>> You don't have to add any lines to the makefile.  You can reset SHELL
>>> on the command line, just like any other make variable:
>>>
>>>     make SHELL=/my/special/sh
>>>
>>> You can even override it only for specific targets using the --eval
>>> command line option:
>>>
>>>     make --eval 'somerule: SHELL := /my/special/sh'
>>>
>>> Or, you can add '-f mymakefile.mk -f Makefile' options to the command
>>> line to force reading of a personal makefile before the standard
>>> makefile.
>>>
>>> Clearly you can modify the command line, otherwise adding new options
>>> to control a putative retry on error option would not be possible.
>>>
>>> As for your NFS issue, another option would be to enable the .ONESHELL
>>> feature available in newer versions of GNU make: that will ensure that
>>> all lines in a recipe are invoked in a single shell, which means that
>>> they should all be invoked on the same remote host.  This can also be
>>> done from the command line, as above.  If your recipes are written well
>>> it should Just Work.  If they aren't, and you can't fix them, then
>>> obviously this solution won't work for you.
>>>
>>> Regarding changes to set re-invocation on failure, at this time I don't
>>> believe it's something I'd be willing to add to GNU make directly,
>>> especially not an option that simply retries every failed job.  This is
>>> almost never useful (why would you want to retry a compile, or link, or
>>> similar?  It will always just fail again, take longer, and generate
>>> confusing duplicate output--at best).
>>>
>>> The right answer for this problem is to modify the makefile to properly
>>> retry those specific rules which need it.
>>>
>>> I commiserate with you that your environment is static and you're not
>>> permitted to modify it, however adding new specialized capabilities to
>>> GNU make so that makefiles don't have to be modified isn't a design
>>> philosophy I want to adopt.
>>>
>>>
>>> _______________________________________________
>>> Help-make mailing list
>>> address@hidden
>>> https://lists.gnu.org/mailman/listinfo/help-make
>>>
>>


reply via email to

[Prev in Thread] Current Thread [Next in Thread]