RFC-0132: FIDL table size limit

RFC-0132: FIDL table size limit
StatusAccepted
Areas
  • FIDL
Description

This RFC limits FIDL tables to at most 64 entries.

Gerrit change
Authors
Reviewers
Date submitted (year-month-day)2021-09-20
Date reviewed (year-month-day)2021-10-04

Summary

This RFC limits FIDL tables to at most 64 members.

See also:

Motivation

The user-mode performance cost of sending a FIDL table (building, encode and decode) is a function of the maximum set ordinal in the table body. This behavior isn't obvious or intuitive to users and can have negative performance consequences if misused. This RFC proposes a limit to prevent egregious behavior in the near term, act as a stop-gap solution to push FIDL authors to rethink their design and encourage the FIDL team to provide a better longer-term answer if FIDL authors start running into the limit.

Stakeholders

Who has a stake in whether this RFC is accepted?

Facilitator: pascallouis@google.com

Reviewers: pascallouis@google.com, yifeit@google.com, mkember@google.com

Consulted: ianloic@google.com, azaslavsky@google.com, abarth@google.com

Socialization: N/A

Design

Tables will be limited to at most 64 ordinals. Specifically:

  • The FIDL compiler MUST emit an error if an ordinal value is above 64.
  • Bindings MUST NOT error when an ordinal higher than 64 is received. They MAY ignore ordinals higher than 64.

Additionally, if the 64th ordinal is non-reserved it must contain another table, as a mechanism to ensure that the message continues to be extensible. Specifically, the FIDL compiler MUST emit an error if the 64-th ordinal is non-reserved and assigned a non-table type.

Implementation

This will require changes to the FIDL compiler as well as each of the FIDL bindings.

Performance

All measurements in this section are in nanoseconds and were recorded on a NUC with a Intel Core i5-7300U CPU @ 2.60GHz.

The following shows the total (build + encode + decode) user-mode time needed for 1-way communication, measured for LLCPP:

Total user-mode time for 1-way communication

Both the cases where only the last field is set and all fields are set are very close to linear, with slopes of 14.7 ns/field and 63.7 ns/field respectively. This means an unset or reserved field costs approximately 14.7 ns while a set field costs approximately 63.7 ns.

When the maximum ordinal is 64, the last field set time is 3234.1 ns and the all field set time is 6294.2 ns.

Note that these times may change as the binding implementation changes.

The following shows the current distribution of max non-reserved ordinal in FIDL table definitions in the Fuchsia system:

Distribution of max non-reserved ordinals in table definitions

The highest ordinal in a table definition is 56 with the next highest being 26. The table with 56 fields has many fields that are unnecessarily marked reserved and can be restructured to be a more compact table. This implies that current tables will generally not reach the 64 ordinal limit for some time.

Smaller allocations

Some bindings, like LLCPP, calculate the maximum buffer size needed for a message and use this information for sizing allocations. If tables are no longer unbounded in size, it will be possible to decrease the size of the allocations in some cases which may improve performance.

Ergonomics

This RFC makes it more difficult to use FIDL because it is now necessary to take a limit into consideration.

Backwards Compatibility

This RFC breaks backwards compatibility with tables with over 64 entries.

Security considerations

This has no security implications.

Privacy considerations

This has no privacy implications.

Testing

GIDL tests will validate that the wire format is unchanged and decode of tables larger than 64-entries continues to work. Unit tests will check compiler-level changes.

Documentation

The FIDL language documentation will need to be updated to indicate this limit.

Drawbacks, alternatives, and unknowns

Why is 64 the limit?

The limit of 64 is arbitrary but it was chosen for several reasons:

  • It is larger than what should be needed for the vast majority of use cases. There will be outliers, but they can use alternative structures to represent the data. If the limit were 32 instead, it would be much closer to the table sizes commonly used today.

  • If the limit were larger than 64, then there may be situations in which users are surprised by degraded performance. If it is discovered that higher limits are more commonly needed, there is still a possibility of raising the limit again through another RFC.

  • 64 is the number of bits in a 64-bit integer. This makes it possible for bindings to potentially use bit flags to mark presence or absence. Similarly, bit masks can be used to locate ordinals as in the rejected RFC RFC-0016.

Alternatives for large tables

A number of alternative structures can be used in place of large tables. A vector of unions is one such option - it is similarly extensible as a table but has no limit on the number of union fields. It also has a representation that may be more suitable for cases with sparse usage of fields.

Sparse table layout

A previous rejected RFC explored an alternative layout for tables that enables a sparser representation: RFC-0116: Wire format support for sparser FIDL tables

If tables used a sparser representation, then there may be less of a need for a size limit.