• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1.. _module-pw_bloat:
2
3========
4pw_bloat
5========
6.. pigweed-module::
7   :name: pw_bloat
8
9``pw_bloat`` provides tools and helpers around using
10`Bloaty McBloatface <https://github.com/google/bloaty>`_ including generating
11size report cards for output binaries through :ref:`Pigweed's GN build
12system <module-pw_build-gn>`.
13
14Bloat report cards allow tracking the memory usage of a system over time as code
15changes are made and provide a breakdown of which parts of the code have the
16largest size impact.
17
18------------------------
19``pw bloat`` CLI command
20------------------------
21``pw_bloat`` includes a plugin for the Pigweed command line capable of running
22size reports on ELF binaries.
23
24.. note::
25
26   The bloat CLI plugin is still experimental and only supports a small subset
27   of ``pw_bloat``'s capabilities.
28
29Basic usage
30===========
31
32Running a size report on a single executable
33--------------------------------------------
34By default, ``pw bloat`` assumes that
35:ref:`memoryregions <module-pw_bloat-memoryregions>` symbols are defined in
36binaries, and uses them to automatically generate a Bloaty config file.
37
38.. code-block:: sh
39
40   $ pw bloat out/docs/obj/pw_result/size_report/bin/ladder_and_then.elf
41
42   ▒█████▄   █▓  ▄███▒  ▒█    ▒█ ░▓████▒ ░▓████▒ ▒▓████▄
43    ▒█░  █░ ░█▒ ██▒ ▀█▒ ▒█░ █ ▒█  ▒█   ▀  ▒█   ▀  ▒█  ▀█▌
44    ▒█▄▄▄█░ ░█▒ █▓░ ▄▄░ ▒█░ █ ▒█  ▒███    ▒███    ░█   █▌
45    ▒█▀     ░█░ ▓█   █▓ ░█░ █ ▒█  ▒█   ▄  ▒█   ▄  ░█  ▄█▌
46    ▒█      ░█░ ░▓███▀   ▒█▓▀▓█░ ░▓████▒ ░▓████▒ ▒▓████▀
47
48   +----------------------+---------+
49   |     memoryregions    |  sizes  |
50   +======================+=========+
51   |FLASH                 |1,048,064|
52   |RAM                   |  196,608|
53   |VECTOR_TABLE          |      512|
54   +======================+=========+
55   |Total                 |1,245,184|
56   +----------------------+---------+
57
58Running a size report diff
59--------------------------
60
61.. code-block:: sh
62
63   $ pw bloat out/docs/obj/pw_metric/size_report/bin/one_metric.elf \
64         --diff out/docs/obj/pw_metric/size_report/bin/base.elf \
65         -d symbols
66
67   ▒█████▄   █▓  ▄███▒  ▒█    ▒█ ░▓████▒ ░▓████▒ ▒▓████▄
68    ▒█░  █░ ░█▒ ██▒ ▀█▒ ▒█░ █ ▒█  ▒█   ▀  ▒█   ▀  ▒█  ▀█▌
69    ▒█▄▄▄█░ ░█▒ █▓░ ▄▄░ ▒█░ █ ▒█  ▒███    ▒███    ░█   █▌
70    ▒█▀     ░█░ ▓█   █▓ ░█░ █ ▒█  ▒█   ▄  ▒█   ▄  ░█  ▄█▌
71    ▒█      ░█░ ░▓███▀   ▒█▓▀▓█░ ░▓████▒ ░▓████▒ ▒▓████▀
72
73   +-----------------------------------------------------------------------------------+
74   |                                                                                   |
75   +-----------------------------------------------------------------------------------+
76   | diff|     memoryregions    |                    symbols                    | sizes|
77   +=====+======================+===============================================+======+
78   |     |FLASH                 |                                               |    -4|
79   |     |                      |[section .FLASH.unused_space]                  |  -408|
80   |     |                      |main                                           |   +60|
81   |     |                      |__sf_fake_stdout                               |    +4|
82   |     |                      |pw_boot_PreStaticMemoryInit                    |    -2|
83   |     |                      |_isatty                                        |    -2|
84   |  NEW|                      |_GLOBAL__sub_I_group_foo                       |   +84|
85   |  NEW|                      |pw::metric::Group::~Group()                    |   +34|
86   |  NEW|                      |pw::intrusive_list_impl::List::insert_after()  |   +32|
87   |  NEW|                      |pw::metric::Metric::Increment()                |   +32|
88   |  NEW|                      |__cxa_atexit                                   |   +28|
89   |  NEW|                      |pw::metric::Metric::Metric()                   |   +28|
90   |  NEW|                      |pw::metric::Metric::as_int()                   |   +28|
91   |  NEW|                      |pw::intrusive_list_impl::List::Item::unlist()  |   +20|
92   |  NEW|                      |pw::metric::Group::Group()                     |   +18|
93   |  NEW|                      |pw::intrusive_list_impl::List::Item::previous()|   +14|
94   |  NEW|                      |pw::metric::TypedMetric<>::~TypedMetric()      |   +14|
95   |  NEW|                      |__aeabi_atexit                                 |   +12|
96   +-----+----------------------+-----------------------------------------------+------+
97   |     |RAM                   |                                               |     0|
98   |     |                      |[section .stack]                               |   -32|
99   |  NEW|                      |group_foo                                      |   +16|
100   |  NEW|                      |metric_x                                       |   +12|
101   |  NEW|                      |[section .static_init_ram]                     |    +4|
102   +=====+======================+===============================================+======+
103   |Total|                      |                                               |    -4|
104   +-----+----------------------+-----------------------------------------------+------+
105
106Specifying a custom Bloaty config file
107--------------------------------------
108If the linker script for a target does not define memory regions, a custom
109Bloaty config can be provided using the ``-c / --custom-config`` option.
110
111.. code-block::
112
113   $ pw bloat out/pw_strict_host_clang_debug/obj/pw_status/test/status_test -c targets/host/linux.bloaty
114
115    ▒█████▄   █▓  ▄███▒  ▒█    ▒█ ░▓████▒ ░▓████▒ ▒▓████▄
116     ▒█░  █░ ░█▒ ██▒ ▀█▒ ▒█░ █ ▒█  ▒█   ▀  ▒█   ▀  ▒█  ▀█▌
117     ▒█▄▄▄█░ ░█▒ █▓░ ▄▄░ ▒█░ █ ▒█  ▒███    ▒███    ░█   █▌
118     ▒█▀     ░█░ ▓█   █▓ ░█░ █ ▒█  ▒█   ▄  ▒█   ▄  ░█  ▄█▌
119     ▒█      ░█░ ░▓███▀   ▒█▓▀▓█░ ░▓████▒ ░▓████▒ ▒▓████▀
120
121   +------------+---------------------+-------+
122   |  segments  |       sections      | sizes |
123   +============+=====================+=======+
124   |LOAD #3 [RX]|                     |138,176|
125   |            |.text                |137,524|
126   |            |.plt                 |    608|
127   |            |.init                |     24|
128   |            |.fini                |     20|
129   +------------+---------------------+-------+
130   |LOAD #2 [R] |                     | 87,816|
131   |            |.rela.dyn            | 32,664|
132   |            |.rodata              | 23,176|
133   |            |.eh_frame            | 23,152|
134   |            |.eh_frame_hdr        |  4,236|
135   |            |.gcc_except_table    |  1,140|
136   |            |.dynsym              |  1,008|
137   |            |.rela.plt            |    888|
138   |            |[ELF Program Headers]|    616|
139   |            |.dynstr              |    556|
140   |            |.gnu.version_r       |    116|
141   |            |.gnu.version         |     84|
142   |            |[ELF Header]         |     64|
143   |            |.note.ABI-tag        |     32|
144   |            |.gnu.hash            |     28|
145   |            |.interp              |     28|
146   |            |.note.gnu.build-id   |     28|
147   +------------+---------------------+-------+
148   |LOAD #5 [RW]|                     | 20,216|
149   |            |.bss                 | 19,824|
150   |            |.got.plt             |    328|
151   |            |.data                |     64|
152   +------------+---------------------+-------+
153   |LOAD #4 [RW]|                     | 15,664|
154   |            |.data.rel.ro         | 12,240|
155   |            |.relro_padding       |  2,872|
156   |            |.dynamic             |    464|
157   |            |.got                 |     56|
158   |            |.fini_array          |     16|
159   |            |.init_array          |     16|
160   +============+=====================+=======+
161   |Total       |                     |261,872|
162   +------------+---------------------+-------+
163
164.. _bloat-howto:
165
166------------------------------
167Defining size reports in Bazel
168------------------------------
169
170Size diff reports
171=================
172A size diff report compares the symbols present in two binaries and outputs an
173RST table snippet detailing any changes.
174
175To define a size diff, first define targets for the two binaries being compared
176using the ``pw_cc_size_binary`` rule. This rule accepts the same attributes a
177regular ``cc_binary``.
178
179.. code-block:: bazel
180
181   load("//pw_bloat:pw_cc_size_binary.bzl", "pw_cc_size_binary")
182
183   pw_cc_size_binary(
184      name = "base_without_foo",
185      srcs = ["base_without_foo.cc"],
186      deps = [
187         "//pw_bloat:bloat_this_binary",
188      ],
189   )
190
191   pw_cc_size_binary(
192      name = "with_foo",
193      srcs = ["with_foo.cc"],
194      deps = [
195         "//pw_bloat:bloat_this_binary",
196         "//pw_foo",
197      ],
198   )
199
200Then, use the ``pw_size_diff`` rule to run the size report on these binaries.
201Each size diff report outputs a single row within an RST table. To collect the
202rows from one or more reports into a final RST output, list them within a
203``pw_size_table`` target.
204
205.. code-block:: bazel
206
207   load("//pw_bloat:pw_size_diff.bzl", "pw_size_diff")
208   load("//pw_bloat:pw_size_table.bzl", "pw_size_table")
209
210   pw_size_diff(
211      name = "foo_size",
212      base = ":base_without_foo",
213      label = "Cost of linking in //pw_foo and performing several of its operations",
214      target = ":with_foo",
215   )
216
217   pw_size_table(
218      name = "foo_size_report",
219      reports = [
220         ":foo_size",
221      ],
222   )
223
224``pw_size_table`` produces an RST output, which can then be listed in the
225``srcs`` of a docs target, and included within one of its own RST files.
226
227.. code-block:: bazel
228
229   load("@rules_python//sphinxdocs:sphinx_docs_library.bzl", "sphinx_docs_library")
230
231   sphinx_docs_library(
232      name = "docs",
233      srcs = [
234         "docs.rst",
235         ":foo_size_report",
236      ],
237      prefix = "pw_foo/",
238      target_compatible_with = incompatible_with_mcu(),
239   )
240
241Then, within ``docs.rst``, simply include the generated file using the name of
242its Bazel target.
243
244.. code-block:: rst
245
246   ``pw_foo`` size report
247   ^^^^^^^^^^^^^^^^^^^^^^
248   The following table demonstrates the code size of pulling in ``pw_foo``.
249
250   .. include:: foo_size_report
251
252---------------------------
253Defining size reports in GN
254---------------------------
255
256Size diff reports
257=================
258Size reports can be defined using the GN template ``pw_size_diff``. The template
259requires at least two executable targets on which to perform a size diff. The
260base for the size diff can be specified either globally through the top-level
261``base`` argument, or individually per-binary within the ``binaries`` list.
262
263Arguments
264---------
265
266* ``base``: Optional default base target for all listed binaries.
267* ``source_filter``: Optional global regex to filter labels in the diff output.
268* ``data_sources``: Optional global list of datasources from bloaty config file
269* ``binaries``: List of binaries to size diff. Each binary specifies a target,
270  a label for the diff, and optionally a base target, source filter, and data
271  sources that override the global ones (if specified).
272
273
274.. code-block::
275
276   import("$dir_pw_bloat/bloat.gni")
277
278   executable("empty_base") {
279     sources = [ "empty_main.cc" ]
280   }
281
282   executable("hello_world_printf") {
283     sources = [ "hello_printf.cc" ]
284   }
285
286   executable("hello_world_iostream") {
287     sources = [ "hello_iostream.cc" ]
288   }
289
290   pw_size_diff("my_size_report") {
291     base = ":empty_base"
292     data_sources = "symbols,segments"
293     binaries = [
294       {
295         target = ":hello_world_printf"
296         label = "Hello world using printf"
297       },
298       {
299         target = ":hello_world_iostream"
300         label = "Hello world using iostream"
301         data_sources = "symbols"
302       },
303     ]
304   }
305
306A sample ``pw_size_diff`` reStructuredText size report table can be found
307within module docs. For example, see the :ref:`pw_checksum-size-report`
308section of the ``pw_checksum`` module for more detail.
309
310Single binary size reports
311==========================
312Size reports can also be defined using ``pw_size_report``, which provides
313a size report for a single binary. The template requires a target binary.
314
315Arguments
316---------
317* ``target``: Binary target to run size report on.
318* ``data_sources``: Optional list of data sources to organize outputs.
319* ``source_filter``: Optional regex to filter labels in the output.
320* ``json_key_prefix``: Optional prefix for key names in json size report.
321* ``full_json_summary``: Optional boolean to print json size report by label
322*  level hierarchy. Defaults to only use top-level label in size report.
323* ``ignore_unused_labels``: Optional boolean to remove labels that have size of
324*  zero in json size report.
325
326.. code-block::
327
328   import("$dir_pw_bloat/bloat.gni")
329
330   executable("hello_world_iostream") {
331     sources = [ "hello_iostream.cc" ]
332   }
333
334  pw_size_report("hello_world_iostream_size_report") {
335    target = ":hello_iostream"
336    data_sources = "segments,symbols"
337    source_filter = "pw::hello"
338    json_key_prefix = "hello_world_iostream"
339    full_json_summary = true
340    ignore_unused_labels = true
341  }
342
343Example of the generated ASCII table for a single binary:
344
345.. code-block::
346
347   ┌─────────────┬──────────────────────────────────────────────────┬──────┐
348   │segment_names│                      symbols                     │ sizes│
349   ├═════════════┼══════════════════════════════════════════════════┼══════┤
350   │FLASH        │                                                  │12,072│
351   │             │pw::kvs::KeyValueStore::InitializeMetadata()      │   684│
352   │             │pw::kvs::KeyValueStore::Init()                    │   456│
353   │             │pw::kvs::internal::EntryCache::Find()             │   444│
354   │             │pw::kvs::FakeFlashMemory::Write()                 │   240│
355   │             │pw::kvs::internal::Entry::VerifyChecksumInFlash() │   228│
356   │             │pw::kvs::KeyValueStore::GarbageCollectSector()    │   220│
357   │             │pw::kvs::KeyValueStore::RemoveDeletedKeyEntries() │   220│
358   │             │pw::kvs::KeyValueStore::AppendEntry()             │   204│
359   │             │pw::kvs::KeyValueStore::Get()                     │   194│
360   │             │pw::kvs::internal::Entry::Read()                  │   188│
361   │             │pw::kvs::ChecksumAlgorithm::Finish()              │    26│
362   │             │pw::kvs::internal::Entry::ReadKey()               │    26│
363   │             │pw::kvs::internal::Sectors::BaseAddress()         │    24│
364   │             │pw::kvs::ChecksumAlgorithm::Update()              │    20│
365   │             │pw::kvs::FlashTestPartition()                     │     8│
366   │             │pw::kvs::FakeFlashMemory::Disable()               │     6│
367   │             │pw::kvs::FakeFlashMemory::Enable()                │     6│
368   │             │pw::kvs::FlashMemory::SelfTest()                  │     6│
369   │             │pw::kvs::FlashPartition::Init()                   │     6│
370   │             │pw::kvs::FlashPartition::sector_size_bytes()      │     6│
371   │             │pw::kvs::FakeFlashMemory::IsEnabled()             │     4│
372   ├─────────────┼──────────────────────────────────────────────────┼──────┤
373   │RAM          │                                                  │ 1,424│
374   │             │test_kvs                                          │   992│
375   │             │pw::kvs::(anonymous namespace)::test_flash        │   384│
376   │             │pw::kvs::(anonymous namespace)::test_partition    │    24│
377   │             │pw::kvs::FakeFlashMemory::no_errors_              │    12│
378   │             │borrowable_kvs                                    │     8│
379   │             │kvs_entry_count                                   │     4│
380   ├═════════════┼══════════════════════════════════════════════════┼══════┤
381   │Total        │                                                  │13,496│
382   └─────────────┴──────────────────────────────────────────────────┴──────┘
383
384
385Size reports are typically included in reStructuredText, as described in
386`Documentation integration`_. Size reports may also be printed in the build
387output if desired. To enable this in the GN build
388(``pigweed/pw_bloat/bloat.gni``), set the ``pw_bloat_SHOW_SIZE_REPORTS``
389build arg to ``true``.
390
391Collecting size report data
392===========================
393Each ``pw_size_report`` target outputs a JSON file containing the sizes of all
394top-level labels in the binary. (By default, this represents "segments", i.e.
395ELF program headers.) If ``full_json_summary`` is set to true, sizes for all
396label levels are reported (i.e. default labels would show size of each symbol
397per segment). If a build produces multiple images, it may be useful to collect
398all of their sizes into a single file to provide a snapshot of sizes at some
399point in time --- for example, to display per-commit size deltas through CI.
400
401The ``pw_size_report_aggregation`` template is provided to collect multiple size
402reports' data into a single JSON file.
403
404Arguments
405---------
406* ``deps``: List of ``pw_size_report`` targets whose data to collect.
407* ``output``: Path to the output JSON file.
408
409.. code-block::
410
411   import("$dir_pw_bloat/bloat.gni")
412
413   pw_size_report_aggregation("image_sizes") {
414      deps = [
415        ":app_image_size_report",
416        ":bootloader_image_size_report",
417      ]
418      output = "$root_gen_dir/artifacts/image_sizes.json"
419   }
420
421.. _module-pw_bloat-docs:
422
423-------------------------
424Documentation integration
425-------------------------
426Bloat reports are easy to add to documentation files. All ``pw_size_diff``
427and ``pw_size_report`` targets output a file containing a tabular report card.
428This file can be imported directly into a reStructuredText file using the
429``include`` directive.
430
431For example, the ``simple_bloat_loop`` and ``simple_bloat_function`` size
432reports under ``//pw_bloat/examples`` are imported into this file as follows:
433
434.. code-block:: rst
435
436   Simple bloat loop example
437   ^^^^^^^^^^^^^^^^^^^^^^^^^
438   .. include:: examples/simple_bloat_loop
439
440   Simple bloat function example
441   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
442   .. include:: examples/simple_bloat_function
443
444Resulting in this output:
445
446Simple bloat loop example
447=========================
448.. TODO: b/388905812 - Re-enable the size report.
449.. .. include:: examples/simple_bloat_loop
450.. include:: ../size_report_notice
451
452Simple bloat function example
453=============================
454.. TODO: b/388905812 - Re-enable the size report.
455.. .. include:: examples/simple_bloat_function
456.. include:: ../size_report_notice
457
458.. _module-pw_bloat-sources:
459
460------------------------------
461Additional Bloaty data sources
462------------------------------
463`Bloaty McBloatface <https://github.com/google/bloaty>`_ by itself cannot help
464answer some questions which embedded developers frequently face such as
465understanding how much space is left. To address this, Pigweed provides Python
466tooling (``pw_bloat.bloaty_config``) to generate bloaty configuration files
467based on the final ELF files through small tweaks in the linker scripts to
468expose extra information.
469
470See the sections below on how to enable the additional data sections through
471modifications in your linker script(s).
472
473As an example to generate the helper configuration which enables additional data
474sources for ``example.elf`` if you've updated your linker script(s) accordingly,
475simply run
476``python -m pw_bloaty.bloaty_config example.elf > example.bloaty``. The
477``example.bloaty``  can then be used with bloaty using the ``-c`` flag, for
478example
479``bloaty -c example.bloaty example.elf --domain vm -d memoryregions,utilization``
480which may return something like:
481
482.. code-block::
483
484   84.2%  1023Ki    FLASH
485     94.2%   963Ki    Free space
486      5.8%  59.6Ki    Used space
487   15.8%   192Ki    RAM
488    100.0%   192Ki    Used space
489    0.0%     512    VECTOR_TABLE
490     96.9%     496    Free space
491      3.1%      16    Used space
492    0.0%       0    Not resident in memory
493      NAN%       0    Used space
494
495.. _module-pw_bloat-utilization:
496
497``utilization`` data source
498===========================
499The most common question many embedded developers face when using ``bloaty`` is
500how much space you are using and how much space is left. To correctly answer
501this, section sizes must be used in order to correctly account for section
502alignment requirements.
503
504The generated ``utilization`` data source will work with any ELF file, where
505``Used Space`` is reported for the sum of virtual memory size of all sections.
506``Padding`` captures the amount of memory that is utilized to enfore alignment
507requirements. Tracking ``Padding`` size can help monitor application growth
508for changes that are too small to force realignment.
509
510In order for ``Free Space`` to be reported, your linker scripts must include
511properly aligned sections which span the unused remaining space for the relevant
512memory region with the ``unused_space`` string anywhere in their name. This
513typically means creating a trailing section which is pinned to span to the end
514of the memory region.
515
516For example imagine this partial example GNU LD linker script:
517
518.. code-block::
519
520   MEMORY
521   {
522     FLASH(rx) : \
523       ORIGIN = PW_BOOT_FLASH_BEGIN, \
524       LENGTH = PW_BOOT_FLASH_SIZE
525     RAM(rwx) : \
526       ORIGIN = PW_BOOT_RAM_BEGIN, \
527       LENGTH = PW_BOOT_RAM_SIZE
528   }
529
530   SECTIONS
531   {
532     /* Main executable code. */
533     .code : ALIGN(4)
534     {
535       /* Application code. */
536       *(.text)
537       *(.text*)
538       KEEP(*(.init))
539       KEEP(*(.fini))
540
541       . = ALIGN(4);
542       /* Constants.*/
543       *(.rodata)
544       *(.rodata*)
545     } >FLASH
546
547     /* Explicitly initialized global and static data. (.data)*/
548     .static_init_ram : ALIGN(4)
549     {
550       *(.data)
551       *(.data*)
552       . = ALIGN(4);
553     } >RAM AT> FLASH
554
555     /* Zero initialized global/static data. (.bss) */
556     .zero_init_ram (NOLOAD) : ALIGN(4)
557     {
558       *(.bss)
559       *(.bss*)
560       *(COMMON)
561       . = ALIGN(4);
562     } >RAM
563   }
564
565Could be modified as follows to enable ``Free Space`` reporting:
566
567.. code-block::
568
569   MEMORY
570   {
571     FLASH(rx) : ORIGIN = PW_BOOT_FLASH_BEGIN, LENGTH = PW_BOOT_FLASH_SIZE
572     RAM(rwx) : ORIGIN = PW_BOOT_RAM_BEGIN, LENGTH = PW_BOOT_RAM_SIZE
573
574     /* Each memory region above has an associated .*.unused_space section that
575      * overlays the unused space at the end of the memory segment. These
576      * segments are used by pw_bloat.bloaty_config to create the utilization
577      * data source for bloaty size reports.
578      *
579      * These sections MUST be located immediately after the last section that is
580      * placed in the respective memory region or lld will issue a warning like:
581      *
582      *   warning: ignoring memory region assignment for non-allocatable section
583      *      '.VECTOR_TABLE.unused_space'
584      *
585      * If this warning occurs, it's also likely that LLD will have created quite
586      * large padded regions in the ELF file due to bad cursor operations. This
587      * can cause ELF files to balloon from hundreds of kilobytes to hundreds of
588      * megabytes.
589      *
590      * Attempting to add sections to the memory region AFTER the unused_space
591      * section will cause the region to overflow.
592      */
593   }
594
595   SECTIONS
596   {
597     /* Main executable code. */
598     .code : ALIGN(4)
599     {
600       /* Application code. */
601       *(.text)
602       *(.text*)
603       KEEP(*(.init))
604       KEEP(*(.fini))
605
606       . = ALIGN(4);
607       /* Constants.*/
608       *(.rodata)
609       *(.rodata*)
610     } >FLASH
611
612     /* Explicitly initialized global and static data. (.data)*/
613     .static_init_ram : ALIGN(4)
614     {
615       *(.data)
616       *(.data*)
617       . = ALIGN(4);
618     } >RAM AT> FLASH
619
620     /* Defines a section representing the unused space in the FLASH segment.
621      * This MUST be the last section assigned to the FLASH region.
622      */
623     PW_BLOAT_UNUSED_SPACE(FLASH)
624
625     /* Zero initialized global/static data. (.bss). */
626     .zero_init_ram (NOLOAD) : ALIGN(4)
627     {
628       *(.bss)
629       *(.bss*)
630       *(COMMON)
631       . = ALIGN(4);
632     } >RAM
633
634     /* Defines a section representing the unused space in the RAM segment. This
635      * MUST be the last section assigned to the RAM region.
636      */
637     PW_BLOAT_UNUSED_SPACE(RAM)
638   }
639
640The preprocessor macro ``PW_BLOAT_UNUSED_SPACE`` is defined in
641``pw_bloat/bloat_macros.ld``. To use these macros include this file in your
642``pw_linker_script`` as follows:
643
644.. code-block::
645
646   pw_linker_script("my_linker_script") {
647     includes = [ "$dir_pw_bloat/bloat_macros.ld" ]
648     linker_script = "my_project_linker_script.ld"
649   }
650
651Note that linker scripts are not natively supported by GN and can't be provided
652through ``deps``, the ``bloat_macros.ld`` must be passed in the ``includes``
653list.
654
655.. _module-pw_bloat-memoryregions:
656
657``memoryregions`` data source
658=============================
659Understanding how symbols, sections, and other data sources can be attributed
660back to the memory regions defined in your linker script is another common
661problem area. Unfortunately the ELF format does not include the original memory
662regions, meaning ``bloaty`` can not do this today by itself. In addition, it's
663relatively common that there are multiple memory regions which alias to the same
664memory but through different buses which could make attribution difficult.
665
666Instead of taking the less portable and brittle approach to parse ``*.map``
667files, ``pw_bloat.bloaty_config`` consumes symbols which are defined in the
668linker script with a special format to extract this information from the ELF
669file: ``pw_bloat_config_memory_region_NAME_{start,end}{_N,}``.
670
671These symbols are defined by the preprocessor macros ``PW_BLOAT_MEMORY_REGION``
672and ``PW_BLOAT_MEMORY_REGION_MAP`` with the right address and size for the
673regions. To use these macros include the ``pw_bloat/bloat_macros.ld`` in your
674``pw_linker_script`` as follows:
675
676.. code-block::
677
678   pw_linker_script("my_linker_script") {
679     includes = [ "$dir_pw_bloat/bloat_macros.ld" ]
680     linker_script = "my_project_linker_script.ld"
681   }
682
683These symbols are then used to determine how to map segments to these memory
684regions. Note that segments must be used in order to account for inter-section
685padding which are not attributed against any sections.
686
687As an example, if you have a single view in the single memory region named
688``FLASH``, then you should include the following macro in your linker script to
689generate the symbols needed for the that region:
690
691.. code-block::
692
693   PW_BLOAT_MEMORY_REGION(FLASH)
694
695As another example, if you have two aliased memory regions (``DCTM`` and
696``ITCM``) into the same effective memory named you'd like to call ``RAM``, then
697you should produce the following four symbols in your linker script:
698
699.. code-block::
700
701   PW_BLOAT_MEMORY_REGION_MAP(RAM, ITCM)
702   PW_BLOAT_MEMORY_REGION_MAP(RAM, DTCM)
703
704------------------------------------------
705Preventing unwanted compiler optimizations
706------------------------------------------
707Compilers can often be very effective at detecting and removing code that does
708not have an observable effect. For example, if attempting to measure two methods
709that are the inverse of each other, some compilers may recognize the object they
710are being called on will always return to its original state and remove both
711calls. This is desirable when trying to create small and fast code, but not when
712the goal is to actually measure the code size impact of those methods.
713
714To help counteract these unwanted optimizations, this module provides a few
715macros that can conditionally execute statements depending on the value of a
716``mask`` variable. Size report authors can use a ``volatile`` variable to ensure
717the compiler cannot assume which calls will or will not be executed,
718
719.. doxygendefine:: PW_BLOAT_COND
720.. doxygendefine:: PW_BLOAT_EXPR
721