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