Code Size Analysis#

pw_string: Efficient, easy, and safe string manipulation

Save code space by replacing snprintf#

The C standard library function snprintf is commonly used for string formatting. However, it isn’t optimized for embedded systems, and using it will bring in a lot of other standard library code that will inflate your binary size.

Size comparison: snprintf versus pw::StringBuilder#

The fixed code size cost of pw::StringBuilder is smaller than that of std::snprintf. Using only pw::StringBuilder’s << and append methods instead of snprintf leads to significant code size reductions.

However, there are cases when the incremental code size cost of pw::StringBuilder is similar to that of snprintf. For example, each argument to pw::StringBuilder’s << method expands to a function call, but one or two pw::StringBuilder appends may still have a smaller code size impact than a single snprintf call. Using pw::StringBuilder error handling will also impact code size in a way that is comparable to snprintf.

Label

Segment

Delta

Total StringBuilder cost when used alongside snprintf

FLASH

+60

[section .code]

-4

main

NEW

+694

__udivmoddi4

NEW

+242

pw::string::IntToString<>()

NEW

+204

pw::tokenizer::EncodeArgs()

NEW

+160

pw::string::internal::kPowersOf10

NEW

+158

__aeabi_d2f

NEW

+80

pw::string_internal::InitializeStringBuffer<>()

NEW

+76

pw::StringBuilder::append()

NEW

+70

pw::StringBuilder::ResizeAndTerminate()

NEW

+68

pw::string::DecimalDigitCount()

NEW

+50

pw::StringBuilder::StringBuilder()

NEW

+48

pw::StringBuffer<>::StringBuffer()

NEW

+48

pw_varint_Encode64

NEW

+44

pw::StringBuilder::operator<< <>()

NEW

+42

_pw_log_tokenized_EncodeTokenizedLog

NEW

+34

pw::span<>::subspan()

NEW

+32

pw::sys_io::WriteBytes()

NEW

+28

pw::string::ClampedCString()

NEW

+28

pw::tokenizer::EncodedMessage<>::EncodedMessage()

NEW

+28

pw_tokenizer_EncodeInt64()

NEW

+26

pw::string::internal::ClampedLength()

NEW

+24

pw::StringBuilder::NullTerminate()

NEW

+24

pw::StringBuilder::operator<<()

NEW

+20

pw::sys_io::WriteByte()

NEW

+20

pw_assert_HandleFailure

NEW

+18

pw::StringBuilder::HandleStatusWithSize()

NEW

+18

pw::span<>::operator[]()

NEW

+14

pw::StringBuffer<>::operator<< <>()

NEW

+8

pw_log_tokenized_HandleLog

NEW

+6

pw::ToString<>()

NEW

+4

__aeabi_idiv0

NEW

+4

__aeabi_memmove

+2,376

StringBuilder cost when completely replacing snprintf

FLASH

DEL

-504

_svfprintf_r

+56

[section .code]

-4

quorem

DEL

-184

__ssputs_r

DEL

-104

snprintf

DEL

-92

_realloc_r

-4

main

DEL

-16

_malloc_usable_size_r

+4

p05.0

NEW

+694

__udivmoddi4

NEW

+242

pw::string::IntToString<>()

NEW

+204

pw::tokenizer::EncodeArgs()

NEW

+160

pw::string::internal::kPowersOf10

NEW

+158

__aeabi_d2f

NEW

+80

pw::string_internal::InitializeStringBuffer<>()

NEW

+76

pw::StringBuilder::append()

NEW

+70

pw::StringBuilder::ResizeAndTerminate()

NEW

+68

pw::string::DecimalDigitCount()

NEW

+50

pw::StringBuilder::StringBuilder()

NEW

+48

pw::StringBuffer<>::StringBuffer()

NEW

+48

pw_varint_Encode64

NEW

+44

pw::StringBuilder::operator<< <>()

NEW

+42

_pw_log_tokenized_EncodeTokenizedLog

NEW

+34

pw::span<>::subspan()

NEW

+32

pw::sys_io::WriteBytes()

NEW

+28

pw::string::ClampedCString()

NEW

+28

pw::tokenizer::EncodedMessage<>::EncodedMessage()

NEW

+28

pw_tokenizer_EncodeInt64()

NEW

+26

pw::string::internal::ClampedLength()

NEW

+24

pw::StringBuilder::NullTerminate()

NEW

+24

pw::StringBuilder::operator<<()

NEW

+20

pw::sys_io::WriteByte()

NEW

+20

pw_assert_HandleFailure

NEW

+18

pw::StringBuilder::HandleStatusWithSize()

NEW

+18

pw::span<>::operator[]()

NEW

+14

pw::StringBuffer<>::operator<< <>()

NEW

+8

pw_log_tokenized_HandleLog

NEW

+6

pw::ToString<>()

NEW

+4

__aeabi_idiv0

NEW

+4

__aeabi_memmove

+1,472

Incremental cost relative to snprintf for 10 strings

FLASH

-48

[section .code]

-196

main

+4

quorem

+8

pw::string::IntToString<>()

+46

pw::StringBuilder::operator<< <>()

-12

OUTLINED_FUNCTION_0

+6

pw::ToString<>()

NEW

+24

pw::StringBuilder::operator<<()

-168

Size comparison: snprintf versus pw::string::Format#

The pw::string::Format functions have a small, fixed code size cost. However, relative to equivalent std::snprintf calls, there is no incremental code size cost to using pw::string::Format.

Label

Segment

Delta

Format instead of snprintf once, return size

FLASH

-4

quorem

DEL

-104

snprintf

-24

pw::string::OutputStringsToBuffer()

-2

pw::tokenizer::EncodedMessage<>::EncodedMessage()

NEW

+88

_vsnprintf_r

NEW

+52

pw::string::FormatVaList()

NEW

+28

vsnprintf

NEW

+22

pw::string::Format()

+56

Format instead of snprintf 10 times, handle errors

FLASH

-68

pw::string::OutputStringsToBuffer()

DEL

-104

snprintf

-2

pw::tokenizer::EncodedMessage<>::EncodedMessage()

+2

OUTLINED_FUNCTION_2

DEL

-10

OUTLINED_FUNCTION_4

NEW

+88

_vsnprintf_r

NEW

+52

pw::string::FormatVaList()

NEW

+28

vsnprintf

NEW

+22

pw::string::Format()

+8

Format instead of snprintf 50 times, no error handling

FLASH

-4

quorem

DEL

-104

snprintf

-2

DefaultFaultHandler

NEW

+88

_vsnprintf_r

NEW

+52

pw::string::FormatVaList()

NEW

+28

vsnprintf

NEW

+22

pw::string::Format()

+80