All of lore.kernel.org
 help / color / mirror / Atom feed
From: Richard Purdie <richard.purdie@linuxfoundation.org>
To: Alexander Kanavin <alex.kanavin@gmail.com>
Cc: Khem Raj <raj.khem@gmail.com>,
	bitbake-devel <bitbake-devel@lists.openembedded.org>,
	Randy MacLeod <rwmacleod@gmail.com>,
	 Mark Hatle <mark.hatle@kernel.crashing.org>
Subject: Re: [bitbake-devel] regression of 'world' performance?
Date: Tue, 13 Feb 2024 08:57:40 +0000	[thread overview]
Message-ID: <b30b09d3a164e2425c8d0d43df495ea8bcb08679.camel@linuxfoundation.org> (raw)
In-Reply-To: <CANNYZj_gJnswnprhj-bM9fhaJwv4phi-Mi6WJbX90wAw3shZEA@mail.gmail.com>

On Mon, 2024-02-12 at 13:58 +0100, Alexander Kanavin wrote:
> On Sat, 10 Feb 2024 at 21:53, Richard Purdie
> <richard.purdie@linuxfoundation.org> wrote:
> 
> > Looking at the code, people have altered next_buildable_task() to add
> > per task thread limits and pressure regulation and they don't realise
> > how often that function can be called or how fast it really needs to
> > be. Note that the profile above doesn't include pressure regulation but
> > if it did, it would be much worse.
> > 
> > It can be reworked but it isn't trivial.
> 
> Thanks for working on this, over the weekend. I just re-run profiling
> with the fix for the mainloop, and here's what I see:
> 
> 1. There are three performance fixes in master-next. Without any of
> them, profile shows this (pressed ctrl-c while it was still not
> running any tasks):
> 
> Mon Feb 12 12:32:56 2024    profile-mainloop.log
> 
>          71983446 function calls (71606940 primitive calls) in 1546.118 seconds
> 
>    Ordered by: internal time
> 
>    ncalls  tottime  percall  cumtime  percall filename:lineno(function)
>      9448 1461.507    0.155 1491.991    0.158
> /srv/work/alex/poky/bitbake/lib/bb/runqueue.py:2147(execute)
> 9510/9448   14.437    0.002   14.530    0.002
> /srv/work/alex/poky/bitbake/lib/bb/runqueue.py:2672(scenequeue_updatecounters)
>   5250612    7.414    0.000    7.414    0.000
> /srv/work/alex/poky/bitbake/lib/bb/__init__.py:63(bbdebug)
>   5219489    6.090    0.000   13.472    0.000
> /srv/work/alex/poky/bitbake/lib/bb/__init__.py:57(debug2)
>         1    5.906    5.906   18.979   18.979
> /srv/work/alex/poky/bitbake/lib/bb/runqueue.py:644(prepare)
> 43827/23463    1.662    0.000    4.198    0.000
> /usr/lib/python3.11/re/_parser.py:507(_parse)
> 
> So it is indeed the execute() loop itself which is slow. It's only
> logical then that with the first two performance fixes applied,
> nothing changes:
> 
> Mon Feb 12 13:03:42 2024    profile-mainloop.log
> 
>          67576990 function calls (67201484 primitive calls) in 1226.143 seconds
> 
>    Ordered by: internal time
> 
>    ncalls  tottime  percall  cumtime  percall filename:lineno(function)
>      8711 1147.496    0.132 1173.321    0.135
> /srv/work/alex/poky/bitbake/lib/bb/runqueue.py:2149(execute)
> 8773/8711   12.261    0.001   12.347    0.001
> /srv/work/alex/poky/bitbake/lib/bb/runqueue.py:2683(scenequeue_updatecounters)
>   4498537    6.303    0.000    6.303    0.000
> /srv/work/alex/poky/bitbake/lib/bb/__init__.py:63(bbdebug)
>         1    6.238    6.238   16.135   16.135
> /srv/work/alex/poky/bitbake/lib/bb/runqueue.py:644(prepare)
>   4467414    5.149    0.000   11.418    0.000
> /srv/work/alex/poky/bitbake/lib/bb/__init__.py:57(debug2)
> 43827/23463    1.662    0.000    4.239    0.000
> /usr/lib/python3.11/re/_parser.py:507(_parse)
> 
> Do note the quadratic growth in tottime though: 9448/8711 = 1.08, but
> 1461/1148 = 1.27
> 
> 2. With the third fix (allow the loop to work through all items), I
> finally didn't have to press ctrl-c, and the dry world run completed,
> with the following picture:
> 
> Mon Feb 12 13:21:51 2024    profile-mainloop.log
> 
>          158073071 function calls (157658186 primitive calls) in 972.810 seconds
> 
>    Ordered by: internal time
> 
>    ncalls  tottime  percall  cumtime  percall filename:lineno(function)
>     35784  307.013    0.009  513.933    0.014
> /srv/work/alex/poky/bitbake/lib/bb/runqueue.py:225(next_buildable_task)
>     34092  160.895    0.005  168.126    0.005
> /srv/work/alex/poky/bitbake/lib/bb/runqueue.py:2438(build_taskdepdata)
>     35807  118.265    0.003  118.265    0.003 {method 'difference' of
> 'set' objects}
>     71592   54.910    0.001   54.910    0.001 {method
> 'difference_update' of 'set' objects}
>     34096   50.010    0.001   50.010    0.001 {method 'write' of
> '_io.BufferedWriter' objects}
> 17639/15964   48.203    0.003   48.480    0.003
> /srv/work/alex/poky/bitbake/lib/bb/runqueue.py:2685(scenequeue_updatecounters)
>    298834   45.690    0.000   45.691    0.000 {built-in method _pickle.dumps}
>     35827   22.092    0.001   22.092    0.001 {method
> 'intersection_update' of 'set' objects}
>     35783   10.610    0.000   10.610    0.000 {method 'index' of 'list' objects}
>     35957    9.649    0.000  916.610    0.025
> /srv/work/alex/poky/bitbake/lib/bb/runqueue.py:2149(execute)
> 
> execute() moves to the 10th place, and the time starts to be dominated
> by other items
> 
> 3. I'm not seeing anything obviously inefficient in the execute() loop
> itself: it's mostly doing standard data structure lookups.
> So I'd say execute() should be allowed to handle all the items in a
> batch or otherwise make its own decisions about when to return. This
> results in fails elsewhere as you've commented, I didn't yet look into
> that.

I worked out a way to make it work with "continue" however there was
more that was bugging me about the behaviour of this. You can see it in
this profile:

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    15223  807.225    0.053  838.759    0.055 /media/build/poky/bitbake/lib/bb/runqueue.py:2149(execute)
16970/15322   23.029    0.001   23.177    0.002 /media/build/poky/bitbake/lib/bb/runqueue.py:2683(scenequeue_updatecounters)
  5239701    3.361    0.000    3.361    0.000 /media/build/poky/bitbake/lib/bb/__init__.py:63(bbdebug)
        1    3.072    3.072    7.529    7.529 /media/build/poky/bitbake/lib/bb/runqueue.py:644(prepare)
  5208322    2.964    0.000    6.313    0.000 /media/build/poky/bitbake/lib/bb/__init__.py:57(debug2)
       43    1.236    0.029    1.236    0.029 {built-in method select.select}
 10707192    0.913    0.000    0.913    0.000 {method 'issubset' of 'set' objects}
24335/13567    0.669    0.000    1.264    0.000 /usr/lib/python3.11/re/_parser.py:509(_parse)
   996792    0.652    0.000    0.742    0.000 /usr/lib/python3.11/glob.py:141(_iterdir)
    41296    0.583    0.000    0.583    0.000 {built-in method posix.write}

Note that whilst they didn't take too long a time, there are 5 million
calls to debug2 (each is a line of log information) and 10 million
calls to issubset().

execute() should only be processing task entries when that entry has
some kind of "progress" that can be made and there is "space" to
execute a new task. The millions of log lines suggest something is
being "processed" multiple times over with no progress. The issubset()
gives a pointer to which code block.

As you've already identified, that points back to the code block:

if nexttask in self.sqdata.sq_harddeps_rev and not self.sqdata.sq_harddeps_rev[nexttask].issubset(self.scenequeue_covered | self.scenequeue_notcovered):
    logger.debug2("Deferring %s due to hard dependencies" % nexttask)

but I mainly mention this to show how it shows up in the profile.

The key question is why does that block keep getting triggered and how
can we make it only run when it needs to.

The answer is perhaps the patch I sent to the bitbake list a few hours
ago, which runs it once, then skips it until it has progress than can
be made (the harddep dependencies have run).

That change in behaviour is able to change the profile to:

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.069    0.069   62.756   62.756 /media/build/poky/bitbake/lib/bb/server/process.py:421(idle_thread_internal)
    15222    0.013    0.000   57.848    0.004 /media/build/poky/bitbake/lib/bb/cooker.py:1474(buildTargetsIdle)
    15222    0.012    0.000   57.834    0.004 /media/build/poky/bitbake/lib/bb/runqueue.py:1624(execute_runqueue)
    15222    0.057    0.000   57.822    0.004 /media/build/poky/bitbake/lib/bb/runqueue.py:1523(_execute_runqueue)
    15222   15.182    0.001   39.881    0.003 /media/build/poky/bitbake/lib/bb/runqueue.py:2150(execute)
16970/15322   23.639    0.001   23.775    0.002 /media/build/poky/bitbake/lib/bb/runqueue.py:2686(scenequeue_updatecounters)
16739/15091    0.017    0.000   23.723    0.002 /media/build/poky/bitbake/lib/bb/runqueue.py:2756(sq_task_failoutright)
        1    0.022    0.022    8.504    8.504 /media/build/poky/bitbake/lib/bb/runqueue.py:1814(__init__)
        1    2.842    2.842    7.013    7.013 /media/build/poky/bitbake/lib/bb/runqueue.py:644(prepare)
    16970    0.044    0.000    4.550    0.000 /media/build/poky/bitbake/lib/bb/build.py:855(find_stale_stamps)
    33948    0.032    0.000    4.197    0.000 /usr/lib/python3.11/glob.py:13(glob)

so without profiling enabled, "bitbake world -n --setscene-only" takes
around 30s (60s with profiling) for the workload which previously was
taking 12 minutes.

execute() is 40s of that and of the 40s, 23s is spent in the
scenequeue_updatecounters() accounting function.

The other "performance" changes I sent help the task execution phase
which happens after setscene() so they improve "bitbake world -n" but
not the setscene piece specifically.

The patches fix low hanging issues but I suspect there is more we
could/should do in this code.

Cheers,

Richard



  reply	other threads:[~2024-02-13  8:57 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-01-12 10:57 regression of 'world' performance? Alexander Kanavin
2024-01-12 12:13 ` [bitbake-devel] " Richard Purdie
2024-01-12 12:27   ` Alexander Kanavin
2024-01-12 22:19     ` Khem Raj
2024-02-09 15:23       ` Alexander Kanavin
2024-02-09 15:43         ` Richard Purdie
2024-02-09 15:59           ` Alexander Kanavin
2024-02-09 16:05             ` Richard Purdie
2024-02-09 16:16               ` Alexander Kanavin
2024-02-09 16:22                 ` Richard Purdie
2024-02-09 17:02                   ` Alexander Kanavin
     [not found]                   ` <17B24084174823DE.15017@lists.openembedded.org>
2024-02-09 20:44                     ` Alexander Kanavin
2024-02-09 21:43                       ` chris.laplante
2024-02-09 22:50                         ` chris.laplante
2024-02-09 23:33                       ` Richard Purdie
     [not found]                       ` <17B255DB2CE33879.588@lists.openembedded.org>
2024-02-09 23:59                         ` Richard Purdie
     [not found]                         ` <17B257441406400D.588@lists.openembedded.org>
2024-02-10 15:16                           ` Richard Purdie
     [not found]                           ` <17B2894C95E031D0.14481@lists.openembedded.org>
2024-02-10 20:42                             ` Richard Purdie
     [not found]                             ` <17B29B2072FF51A8.14481@lists.openembedded.org>
2024-02-10 20:52                               ` Richard Purdie
2024-02-12 12:58                                 ` Alexander Kanavin
2024-02-13  8:57                                   ` Richard Purdie [this message]
2024-02-13  9:42                                     ` Alexander Kanavin
2024-02-13 12:41                                       ` Richard Purdie
2024-02-14  6:59                                         ` Alexander Kanavin
2024-02-14  8:05                                           ` Richard Purdie
2024-02-13 10:49                                   ` Ross Burton
2024-02-13 12:31                                     ` Richard Purdie

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=b30b09d3a164e2425c8d0d43df495ea8bcb08679.camel@linuxfoundation.org \
    --to=richard.purdie@linuxfoundation.org \
    --cc=alex.kanavin@gmail.com \
    --cc=bitbake-devel@lists.openembedded.org \
    --cc=mark.hatle@kernel.crashing.org \
    --cc=raj.khem@gmail.com \
    --cc=rwmacleod@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.