From: Markus Armbruster <armbru@redhat.com>
To: qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] Our use of #include is undisciplined, and what to do about it
Date: Mon, 27 May 2019 15:12:34 +0200 [thread overview]
Message-ID: <877eac82il.fsf@dusky.pond.sub.org> (raw)
In-Reply-To: <87wpp4m6n1.fsf@blackfin.pond.sub.org> (Markus Armbruster's message of "Tue, 15 Mar 2016 10:29:06 +0100")
It's been three years, let's examine how things have evolved.
I'm using commit db3d11ee3f0, which is a bit behind current master, just
so I can apply my "[PATCH 0/4] Cleanups around qemu-common.h" cleanly.
Markus Armbruster <armbru@redhat.com> writes:
[...]
> = The status quo and why I hate it =
>
> I've seen several schools of thought on use of #include.
>
> There's the "no #include in headers" school: every .c file includes
> exactly the headers it needs, and the prerequisites they need. Cyclic
> inclusion becomes impossible. You can't sweep cyclic dependencies under
> the rug. Headers are read just once per compilation unit. The amount
> of crap you include is clearly visible. However, maintaining the
> #include directives is a drag, not least because their order matters.
> Especially when headers neglect to spell out their dependencies. Or
> they do, but it's wrong.
>
> There's the "headers must be self-contained" school: every header
> includes everything it needs. Headers can be included in any order.
> Sorted #include directives are tidy and easy to navigate. Headers can
> be read multiple times, which can only hurt compilation time.
Our compilers avoid this for headers with proper header guards.
> You need
> to make an effort to avoid cyclic dependencies and excessive inclusion.
>
> And then there's the school of non-thought: when it doesn't compile,
> sprinkle #include on the mess semi-randomly until it does.
>
> We do a bit of all three, but the result looks awfully close to what the
> school of non-thought produces.
>
> Every .c file includes qemu/osdep.h first. For me, a .c file that
> includes nothing but that comes out well over half a Megabyte in >23k
> lines preprocessed. Where does all this crap come from?
>
> #lines KiBytes #files source
> 5233 102 5 QEMU
> 8035 159 70 system
> 7915 224 73 GLib
> 2458 89 1 # lines
> 23641 576 149 total
>
> "# lines" are lines added by the preprocessor so the rest of the
> compiler can keep track of source locations.
#lines KiBytes #files source
375 8 5 QEMU
9722 230 113 system
8212 254 74 GLib
1517 65 N/A # lines
19826 557 192 total
The weight QEMU lost, system + GLib put on.
> Having the compiler wade through almost half a Megabyte of system+GLib
> crap before it begins to consider the code we care about feels wasteful.
> Perhaps we should rethink our approach to including library headers.
No change.
> Of the 102K that are actually our own, just 7K come from include/. 95K
> come from qapi-types.h.
Fixed.
> Judging from the .d files in my build tree, 95% of the .c files include
> qemu-common.h. That makes things a good deal worse.
Down to 90%. My "[PATCH 0/4] Cleanups around qemu-common.h" shrinks it
to less than 10%. Small enough for me not to repeat the measurements
below.
> Without
> NEED_CPU_H, this adds a modest 44K of our own headers, but almost 100K
> of system headers:
>
> #lines KiBytes #files source
> 6938 146 16 QEMU
> 11426 254 74 system
> 7915 224 73 GLib
> 2658 100 1 # lines
> 28937 726 164 total
>
> NEED_CPU_H adds another 120K of our own headers:
>
> #lines KiBytes #files source
> 11534 263 43 QEMU
> 11548 256 78 system
> 7915 225 72 GLib
> 3370 138 1 # lines
> 34367 883 194 total
>
> The average size of a .c file is just over 15KiB. To get to the actual
> C code there, the compiler has to wade through at least 550-880KiB of
> headers. In other words, roughly 2% of the source comes from .c in the
> best case.
>
> But that's not even the worst part. The worst part by far are our
> "touch this and recompile the world" headers.
>
> I find just short 4000 .d files in my build tree.
Some 6400 now, ignoring the .d that don't contain ".o:".
> Guess how many of our
> headers are listed as prerequisites in more than 90% of them (thus
> touching them will recompile the .c file)? *Twenty-two*.
Down to 12 before my "[PATCH 0/4] Cleanups around qemu-common.h", and to
10 afterwards.
> Almost fifty
> recompile more half of the world.
No significant change.
> Naturally, touching osdep.h or anything it includes recompiles the
> world. These are:
>
> config-host.h
> include/glib-compat.h
> include/qapi/error.h
> include/qemu/compiler.h
> include/qemu/osdep.h
> include/qemu/typedefs.h
> include/sysemu/os-posix.h
> qapi-types.h
>
> NEED_CPU_H adds
>
> config-target.h
>
> Fine, except for qapi/error.h and qapi-types.h. The latter is an itch I
> need to scratch urgently. My first patch series will take a swing at
> it.
Both are gone.
New: include/exec/poison.h
[...]
>
> A fun exercise is to count occurences of each header in .d files and
> multiply their number by their size. That's the number of bytes read
> from them when compiling from scratch. Top scorers:
>
> size * count size count
> 525760413 698221 753 trace/generated-tracers.h
> 298039140 93723 3180 qapi-types.h
> 197442619 55759 3541 include/qom/object.h
> 185845916 53884 3449 include/exec/memory.h
> 143750444 36878 3898 /usr/include/glib-2.0/glib/gunicode.h
> 117362690 30643 3830 include/fpu/softfloat.h
> 109783272 28164 3898 /usr/include/glib-2.0/glib/gregex.h
> 105830700 27150 3898 /usr/include/glib-2.0/glib/gvariant.h
> 92972157 123469 753 trace/generated-events.h
> 88706786 22757 3898 /usr/include/glib-2.0/glib/gtestutils.h
After my "[PATCH 0/4] Cleanups around qemu-common.h":
size * count size count
428019130 82789 5170 include/exec/memory.h
336965209 60857 5537 include/qom/object.h
248105382 39121 6342 /usr/include/glib-2.0/glib/gunicode.h
187247550 29525 6342 /usr/include/glib-2.0/glib/gvariant.h
182359220 172037 1060 trace-root.h
178178490 28095 6342 /usr/include/glib-2.0/glib/gregex.h
167477688 71848 2331 qapi/qapi-types-block-core.h
166926546 36947 4518 include/qom/cpu.h
161105826 25403 6342 /usr/include/glib-2.0/glib/gmessages.h
153508110 24205 6342 /usr/include/glib-2.0/glib/gtestutils.h
[...]
>
> = What to do about it =
>
> The immediately obvious thing to do is reduce "recompile the world"
> headers that change frequently. I've started to do that.
>
> Another one is attacking widely included bulky files (see "Top
> scorers"). Some can simply be included less. Others need to be split,
> in particular the generated tracers.
Some progress, notably around trace and QAPI.
> Yet another one is reviewing the way we include system and GLib headers.
Not attempted.
> But our root problem is our undisciplined use of #include. Can we agree
> on a sane set of rules? Here's my proposal:
>
> 1. Have a carefully curated header that's included everywhere first. We
> got that already thanks to Peter: osdep.h.
>
> 2. Headers should normally include everything they need beyond osdep.h.
> If exceptions are needed for some reason, they must be documented in
> the header. If all that's needed from a header is typedefs, put
> those into qemu/typedefs.h instead of including the header.
>
> 3. Cyclic inclusion is forbidden.
>
> Nice to have: "make check" checks 2. and 3.
See my "[RFC v4 0/7] Baby steps towards saner headers".
[...]
Headers that are prerequisites of more than 2000 .o:
6312 config-host.h
2827 include/block/aio.h
4537 include/disas/dis-asm.h
3634 include/exec/cpu-all.h
5177 include/exec/cpu-common.h
3634 include/exec/cpu-defs.h
5401 include/exec/hwaddr.h
5395 include/exec/memattrs.h
5170 include/exec/memory.h
3514 include/exec/memory_ldst.inc.h
3514 include/exec/memory_ldst_cached.inc.h
3514 include/exec/memory_ldst_phys.inc.h
3517 include/exec/ramlist.h
5699 include/fpu/softfloat-types.h
6312 include/glib-compat.h
5429 include/hw/hotplug.h
2423 include/hw/hw.h
5437 include/hw/irq.h
5428 include/hw/qdev-core.h
2520 include/hw/qdev-properties.h
2297 include/hw/qdev.h
2425 include/migration/qemu-file-types.h
2564 include/migration/vmstate.h
2502 include/qapi/error.h
6063 include/qapi/util.h
5939 include/qemu/atomic.h
5494 include/qemu/bitmap.h
5673 include/qemu/bitops.h
5697 include/qemu/bswap.h
6312 include/qemu/compiler.h
3701 include/qemu/coroutine.h
2838 include/qemu/event_notifier.h
5683 include/qemu/host-utils.h
4680 include/qemu/int128.h
3701 include/qemu/lockable.h
3187 include/qemu/log-for-trace.h
2230 include/qemu/log.h
2483 include/qemu/main-loop.h
5568 include/qemu/module.h
5137 include/qemu/notify.h
6312 include/qemu/osdep.h
5561 include/qemu/processor.h
5560 include/qemu/qsp.h
5863 include/qemu/queue.h
5178 include/qemu/rcu.h
5398 include/qemu/rcu_queue.h
5178 include/qemu/sys_membarrier.h
5560 include/qemu/thread-posix.h
5560 include/qemu/thread.h
4356 include/qemu/timer.h
6312 include/qemu/typedefs.h
2008 include/qemu/uuid.h
4518 include/qom/cpu.h
5537 include/qom/object.h
6312 include/sysemu/os-posix.h
2456 include/sysemu/reset.h
2000 include/sysemu/sysemu.h
6062 qapi/qapi-builtin-types.h
2821 qapi/qapi-types-block-core.h
2669 qapi/qapi-types-block.h
3806 qapi/qapi-types-common.h
2860 qapi/qapi-types-crypto.h
2825 qapi/qapi-types-job.h
3038 qapi/qapi-types-misc.h
5249 qapi/qapi-types-run-state.h
3148 qapi/qapi-types-sockets.h
3634 tcg/i386/tcg-target.h
3634 tcg/tcg-mo.h
2369 trace/control-internal.h
2369 trace/control.h
2369 trace/event-internal.h
2361 trace/ftrace.h
5224 x86_64-softmmu/config-target.h
Bulky headers:
size * count size count
17744958 16461 1078 accel/tcg/tcg-runtime.h
32519424 10304 6312 config-host.h
21298950 525900 81 hw/display/trace.h
25070220 1432584 35 hw/net/trace.h
28700355 604218 95 hw/vfio/trace.h
57913922 20486 2827 include/block/aio.h
54939528 30744 1787 include/block/block.h
15698796 53763 292 include/block/block_int.h
12076546 6758 1787 include/block/dirty-bitmap.h
90694630 19990 4537 include/disas/dis-asm.h
22187844 68481 324 include/elf.h
41198658 11337 3634 include/exec/cpu-all.h
19118661 3693 5177 include/exec/cpu-common.h
26052146 7169 3634 include/exec/cpu-defs.h
10698472 11098 964 include/exec/cpu_ldst.h
32181064 19144 1681 include/exec/exec-all.h
14027000 2600 5395 include/exec/memattrs.h
428019130 82789 5170 include/exec/memory.h
12590662 3583 3514 include/exec/memory_ldst.inc.h
13254808 3772 3514 include/exec/memory_ldst_cached.inc.h
18258744 5196 3514 include/exec/memory_ldst_phys.inc.h
37693186 6614 5699 include/fpu/softfloat-types.h
40152640 41480 968 include/fpu/softfloat.h
24408504 3867 6312 include/glib-compat.h
16216423 2987 5429 include/hw/hotplug.h
10178064 1872 5437 include/hw/irq.h
27001315 27137 995 include/hw/pci/pci.h
10509377 10541 997 include/hw/pci/pci_ids.h
84058008 15486 5428 include/hw/qdev-core.h
38099880 15119 2520 include/hw/qdev-properties.h
10165600 4192 2425 include/migration/qemu-file-types.h
140199520 54680 2564 include/migration/vmstate.h
28062432 11216 2502 include/qapi/error.h
14093499 21649 651 include/qapi/visitor.h
122361217 20603 5939 include/qemu/atomic.h
53242354 9691 5494 include/qemu/bitmap.h
91409049 16113 5673 include/qemu/bitops.h
82589409 14497 5697 include/qemu/bswap.h
48009072 7606 6312 include/qemu/compiler.h
32872282 8882 3701 include/qemu/coroutine.h
20290224 11348 1788 include/qemu/hbitmap.h
64189485 11295 5683 include/qemu/host-utils.h
24059880 5141 4680 include/qemu/int128.h
16473456 8474 1944 include/qemu/iov.h
33191317 18553 1789 include/qemu/job.h
11054887 2987 3701 include/qemu/lockable.h
29294434 11798 2483 include/qemu/main-loop.h
14081472 2529 5568 include/qemu/module.h
120111048 19029 6312 include/qemu/osdep.h
14389467 7383 1949 include/qemu/qht.h
142840269 24363 5863 include/qemu/queue.h
24735306 4777 5178 include/qemu/rcu.h
68419650 12675 5398 include/qemu/rcu_queue.h
59775560 10751 5560 include/qemu/thread.h
122708520 28170 4356 include/qemu/timer.h
26573520 4210 6312 include/qemu/typedefs.h
166926546 36947 4518 include/qom/cpu.h
336965209 60857 5537 include/qom/object.h
55562856 55786 996 include/standard-headers/linux/pci_regs.h
12834339 18361 699 include/sysemu/kvm.h
19453584 3082 6312 include/sysemu/os-posix.h
12720000 6360 2000 include/sysemu/sysemu.h
16650270 26429 630 linux-user/qemu.h
53241630 84110 633 linux-user/syscall_defs.h
29144784 1214366 48 migration/trace.h
16888732 5572 6062 qapi/qapi-builtin-types.h
202683208 215544 2821 qapi/qapi-types-block-core.h
11236490 12630 2669 qapi/qapi-types-block.h
15791094 12447 3806 qapi/qapi-types-common.h
21564400 22620 2860 qapi/qapi-types-crypto.h
83229048 82188 3038 qapi/qapi-types-misc.h
11551995 28665 1209 qapi/qapi-types-net.h
25888068 14796 5249 qapi/qapi-types-run-state.h
14465060 13785 3148 qapi/qapi-types-sockets.h
18174224 62526 872 qapi/qapi-types-ui.h
60562920 124872 485 target/arm/cpu.h
18587552 63656 292 target/i386/cpu.h
18575446 36139 514 target/mips/cpu.h
44133336 109512 403 target/ppc/cpu.h
28893934 7951 3634 tcg/i386/tcg-target.h
24384936 51663 472 tcg/tcg-op.h
18304270 11285 1622 tcg/tcg-opc.h
79108184 48772 1622 tcg/tcg.h
64600980 95352 1355 trace-dtrace-root.h
233110135 344074 1355 trace-root.h
22750450 33580 1355 trace-ust-root.h
16220543 6847 2369 trace/control.h
prev parent reply other threads:[~2019-05-27 13:13 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-03-15 9:29 [Qemu-devel] Our use of #include is undisciplined, and what to do about it Markus Armbruster
2016-03-15 9:40 ` Paolo Bonzini
2016-03-15 12:19 ` Markus Armbruster
2016-03-15 14:51 ` Paolo Bonzini
2016-03-15 10:03 ` Peter Maydell
2016-03-15 12:28 ` Markus Armbruster
2016-03-15 12:56 ` Peter Maydell
2016-03-15 13:39 ` Stefan Hajnoczi
2016-03-15 13:51 ` Daniel P. Berrange
2016-03-15 13:56 ` Dr. David Alan Gilbert
2016-03-16 18:23 ` Stefan Hajnoczi
2016-03-16 18:27 ` Dr. David Alan Gilbert
2016-03-17 11:25 ` Stefan Hajnoczi
2016-03-17 16:29 ` Dr. David Alan Gilbert
2016-03-17 19:21 ` Paolo Bonzini
2016-03-17 19:43 ` Dr. David Alan Gilbert
2016-03-17 19:58 ` Paolo Bonzini
2016-03-17 20:14 ` Richard Henderson
2016-03-17 20:27 ` Peter Maydell
2016-03-17 20:29 ` Richard Henderson
2016-03-17 21:02 ` Paolo Bonzini
2016-03-17 20:59 ` Paolo Bonzini
2016-03-17 19:40 ` Richard Henderson
2019-05-27 13:12 ` Markus Armbruster [this message]
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=877eac82il.fsf@dusky.pond.sub.org \
--to=armbru@redhat.com \
--cc=qemu-devel@nongnu.org \
/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.