Code size analysis#

pw_async2: Cooperative async tasks for embedded

Core async2 implementation#

The following table shows the code size cost of adding pw_async2 to a system. These size reports assume a baseline system with an RTOS which already uses a handful of core Pigweed components including HAL abstractions and pw_allocator.

The first row captures the core of pw_async2: the dispatcher, tasks, and wakers, using the pw_async2_basic dispatcher backend. This is the minimum size cost a system must pay to adopt pw_async2. The following row demonstrates the cost of adding another task to this system. Of course, the majority of the cost of the task exists within its implementation — this simply shows that there is minimal internal overhead.

The following two rows in the table deal with the pair of OnceSender and OnceReceiver types, which allow for returning a delayed result from an async function, similar to a Future type in other languages. This type is templated on its stored value, causing specialization overhead for each type sent through the sender/receiver pair. The first OnceSender row showcases the base cost of using a OnceSender and OnceReceiver; the second row adds another template specialization on top of this to demonstrate the incremental cost.

Label

Segment

Delta

Full cost of including pw_async2

FLASH

+484

[section .rodata]

+4

[section .text]

-4

__bi_84

+164

pw::async2::size_report::Measure()

-2

pw::containers::internal::IntrusiveForwardListItem::DoGetPrevious()

+16

pw::containers::internal::LegacyIntrusiveList<>::push_back()

NEW

+388

pw::async2::NativeDispatcherBase::RunOneTask()

NEW

+140

pw::async2::NativeDispatcherBase::NativeDispatcherBase()

NEW

+116

pw::async2::NativeDispatcherBase::Post()

NEW

+112

pw::async2::backend::NativeDispatcher::DoRunToCompletion()

NEW

+96

pw::async2::backend::NativeDispatcher::DoRunUntilStalled()

NEW

+92

pw::async2::NativeDispatcherBase::WakeTask()

NEW

+68

pw::async2::NativeDispatcherBase::AttemptRequestWake()

NEW

+56

pw::async2::Waker::operator=()

NEW

+56

pw::async2::size_report::MockTask::DoPend()

NEW

+52

pw::async2::internal::CloneWaker()

NEW

+48

pw::async2::size_report::MockTask::~MockTask()

NEW

+40

pw::async2::Waker::Wake()

NEW

+38

pw::async2::Task::~Task()

NEW

+36

pw::async2::Waker::InternalCloneIntoLocked()

NEW

+32

pw::async2::Waker::InsertIntoTaskWakerList()

NEW

+32

pw::async2::Waker::RemoveFromTaskWakerList()

NEW

+32

pw::async2::backend::NativeDispatcher::NativeDispatcher()

NEW

+26

pw::async2::Task::RemoveAllWakersLocked()

NEW

+24

pw::async2::NativeDispatcherBase::Wake()

NEW

+24

pw::async2::Task

NEW

+24

pw::async2::size_report::MockTask

NEW

+24

pw::async2::size_report::MockTask::DoPend()::{lambda()#1}::operator()()

NEW

+24

pw::containers::internal::IntrusiveListItemBase<>::unlist()

NEW

+22

pw::async2::NativeDispatcherBase::PopWokenTask()

NEW

+20

pw::IntrusiveForwardList<>::pop_front()

NEW

+18

pw::containers::internal::LegacyIntrusiveList<>::Item::~Item()

NEW

+16

_GLOBAL__sub_I_async2_core.cc

NEW

+16

pw::async2::Task::RemoveWakerLocked()

NEW

+16

pw::async2::Waker::InsertIntoTaskWakerListLocked()

NEW

+16

pw::async2::Waker::RemoveFromTaskWakerListLocked()

NEW

+16

pw::async2::Waker::Waker()

NEW

+16

pw::async2::Waker::~Waker()

NEW

+12

pw::async2::Dispatcher::RunToCompletion()

NEW

+12

pw::async2::Dispatcher::RunUntilStalled()

NEW

+12

pw::async2::NativeDispatcherBase

NEW

+12

pw::async2::Task::AddWakerLocked()

NEW

+12

pw::async2::backend::NativeDispatcher

NEW

+12

pw::async2::backend::NativeDispatcher::DoWake()

NEW

+12

pw::async2::internal::StoreWaker()

NEW

+8

pw::async2::size_report::MockTask::DoDestroy()

NEW

+2

pw::async2::Task::DoDestroy()

+2,492

RAM

NEW

+160

pw::async2::size_report::dispatcher

NEW

+8

pw::async2::impl::dispatcher_lock()::lock

+168

Base incremental cost of adding a task to an existing async system

FLASH

+48

pw::async2::size_report::Measure()

+48

Size of OnceSender / OnceReceiver

FLASH

+172

[section .rodata]

+84

pw::async2::size_report::Measure()

-8

vClearInterruptMaskFromISR

-6

operator delete()

+4

__bi_84

NEW

+112

pw::async2::OnceReceiver<>::Pend()

NEW

+96

pw::async2::OnceReceiver<>::OnceReceiver()

NEW

+60

pw::async2::size_report::SenderAdd()

NEW

+52

pw::async2::OnceSender<>::emplace<>()

NEW

+46

pw::async2::size_report::ReceiverTask<>::~ReceiverTask()

NEW

+44

pw::async2::OnceReceiver<>::~OnceReceiver()

NEW

+44

pw::async2::OnceSender<>::~OnceSender()

NEW

+44

pw::async2::size_report::ReceiverTask<>::ReceiverTask()

NEW

+40

_ZN2pw15internal_result12StatusOrDataIjLb1EEC2INS_6StatusETnNSt3__29enable_ifIXsr3std16is_constructibleIS4_OT_EE5valueEiE4typeELi0EEES8_

NEW

+24

pw::async2::OnceReceiver<>::Pend()::{lambda()#1}::operator()()

NEW

+24

pw::async2::size_report::ReceiverTask<>

NEW

+22

pw::async2::size_report::ReceiverTask<>::DoPend()

NEW

+20

_ZNSt3__28optionalIN2pw6ResultIjEEEC2B8nn210000INS1_6StatusETnNS_9enable_ifIXclsr22_CheckOptionalLikeCtorIT_OS8_EE17__enable_implicitIS8_EEEiE4typeELi0EEEONS0_IS8_EE

NEW

+20

std::__2::pair<>::~pair()

NEW

+14

_ZNSt3__223__optional_storage_baseIN2pw6ResultIjEELb0EE11__constructB8nn210000IJNS1_6StatusEEEEvDpOT_

NEW

+14

_ZNSt3__223__optional_storage_baseIN2pw6ResultIjEELb0EE16__construct_fromB8nn210000INS_8optionalINS1_6StatusEEEEEvOT_

NEW

+12

_ZNRSt3__28optionalIjE5valueB8nn210000Ev

NEW

+12

_ZNSt3__227__throw_bad_optional_accessB8nn210000Ev

NEW

+6

std::__2::__libcpp_verbose_abort()

+952

RAM

NEW

+8

pw::async2::sender_receiver_lock()::lock

+8

Cost of additional OnceSender / OnceReceiver template specialization

FLASH

+88

pw::async2::size_report::Measure()

+112

pw::async2::OnceReceiver<>::Pend()

+96

pw::async2::OnceReceiver<>::OnceReceiver()

+52

pw::async2::OnceSender<>::emplace<>()

+46

pw::async2::size_report::ReceiverTask<>::~ReceiverTask()

+44

pw::async2::OnceReceiver<>::~OnceReceiver()

+44

pw::async2::OnceSender<>::~OnceSender()

+44

pw::async2::size_report::ReceiverTask<>::ReceiverTask()

+24

pw::async2::OnceReceiver<>::Pend()::{lambda()#1}::operator()()

+24

pw::async2::size_report::ReceiverTask<>

+22

pw::async2::size_report::ReceiverTask<>::DoPend()

+18

std::__2::pair<>::~pair()

+4

vClearInterruptMaskFromISR

NEW

+58

pw::async2::size_report::SenderSub()

NEW

+40

_ZN2pw15internal_result12StatusOrDataIiLb1EEC2INS_6StatusETnNSt3__29enable_ifIXsr3std16is_constructibleIS4_OT_EE5valueEiE4typeELi0EEES8_

NEW

+20

_ZNSt3__28optionalIN2pw6ResultIiEEEC2B8nn210000INS1_6StatusETnNS_9enable_ifIXclsr22_CheckOptionalLikeCtorIT_OS8_EE17__enable_implicitIS8_EEEiE4typeELi0EEEONS0_IS8_EE

NEW

+14

_ZNSt3__223__optional_storage_baseIN2pw6ResultIiEELb0EE11__constructB8nn210000IJNS1_6StatusEEEEvDpOT_

NEW

+14

_ZNSt3__223__optional_storage_baseIN2pw6ResultIiEELb0EE16__construct_fromB8nn210000INS_8optionalINS1_6StatusEEEEEvOT_

NEW

+12

_ZNRSt3__28optionalIiE5valueB8nn210000Ev

+776