Current-Users archive

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

Re: bmake inefficiencies



Responding to the original mail due to several follow ups.

Thanks for fixups so far.

Another note related to JobOpenTmpFile:

        JobSigLock(&mask);
        tfd = mkTempFile(TMPPAT, &tfile);
        if (!DEBUG(SCRIPT))
                (void)eunlink(tfile);
        JobSigUnlock(&mask);

is the signal stuff really necessary?

Apart from that, eunlink stats the path and this has happens in
default setting. Instead I propose the following: since mkTempFile has
only 2 consumers, passing in the buffer can be made mandatory. Then
another flag can control when the routine should unlink the result.
This would shorten this callsite to roughly:

char buf[MAXPATHLATEN];
...
tfd = mkTempFile(TMPPAT, buf, sizeof buf, !DEBUG(SCRIPT));

which will also save on memory alloc and string coying as the target
routine calls bmake_strdup to accomodate the request.

On 1/26/21, Mateusz Guzik <mjguzik%gmail.com@localhost> wrote:
> I had a look with truss at what bmake is doing and I think a lot of
> the syscalls can be easily avoided. Examples come from FreeBSD with
> bmake-20210110 and I don't know to what extent they are representative
> for other systems.
>
> 1. spurious waitpid
>
> when doing buildkernel I counted the following:
> 7010 cases of error code 0 (== nothing to do)
> 371 cases of ECHILD
> 1526 cases of reaping
>
> To my understanding bmake knows when there are any children to reap
> and at least the first case can be easily avoided.
>
> 2. FD_CLOEXEC
>
> for example mkstemp is used and FD_CLOEXEC performed on the result.
> Instead mkostemp can be used and mkTempFile can accept O_CLOEXEC as an
> argument to save explicit fcntl.
>
> 3. avoidable temp files
>
> JobOpenTmpFile opens a file and later checks if anything was written
> to it. Not an actual patch, but a hack to demonstrate the fix can be
> found at the end. Looks like checking can be done upfront in O(1) time
> (not done in the patch below).
>
> With this in place I get the following result for buildworld:
> 87930 JobOpenTmpFile: created!
> 70564 JobOpenTmpFile: skipped!
>
> i.e. about 44% of all temp files can be avoided at least in this workload.
>
> There is probably more, but I did not want to analyze further.
>
> Is this something you can address?
>
> Thanks,
>
> diff --git a/contrib/bmake/job.c b/contrib/bmake/job.c
> index d43761ca80ff..67b75f228547 100644
> --- a/contrib/bmake/job.c
> +++ b/contrib/bmake/job.c
> @@ -1022,6 +1022,24 @@ JobPrintCommand(Job *job, ShellWriter *wr,
> StringListNode *ln, const char *ucmd)
>   *
>   * Return whether at least one command was written to the shell file.
>   */
> +static Boolean
> +JobWillPrintCommands(Job *job)
> +{
> +       StringListNode *ln;
> +       Boolean seen = FALSE;
> +
> +       for (ln = job->node->commands.first; ln != NULL; ln = ln->next) {
> +               const char *cmd = ln->datum;
> +
> +               if (strcmp(cmd, "...") == 0) {
> +                       break;
> +               }
> +               seen = TRUE;
> +       }
> +
> +       return seen;
> +}
> +
>  static Boolean
>  JobPrintCommands(Job *job)
>  {
> @@ -1609,6 +1627,15 @@ JobOpenTmpFile(Job *job, GNode *gn, Boolean
> cmdsOK, Boolean *out_run)
>                 DieHorribly();
>         }
>
> +       if (getenv("MAKE_TRYSKIP") != NULL) {
> +               if (!JobWillPrintCommands(job)) {
> +                       printf("%s: skipped!\n", __func__);
> +                       *out_run = FALSE;
> +                       return;
> +               }
> +               printf("%s: created!\n", __func__);
> +       }
> +
>         JobSigLock(&mask);
>         tfd = mkTempFile(TMPPAT, &tfile);
>         if (!DEBUG(SCRIPT))
>
>
> -
>
> --
> Mateusz Guzik <mjguzik gmail.com>
>


-- 
Mateusz Guzik <mjguzik gmail.com>


Home | Main Index | Thread Index | Old Index