|RFC-0132: FIDL table size limit|
This RFC limits FIDL tables to at most 64 entries.
|Date submitted (year-month-day)||2021-09-20|
|Date reviewed (year-month-day)||2021-10-04|
This RFC limits FIDL tables to at most 64 members.
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.
Who has a stake in whether this RFC is accepted?
Reviewers: firstname.lastname@example.org, email@example.com, firstname.lastname@example.org
Consulted: email@example.com, firstname.lastname@example.org, email@example.com
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.
This will require changes to the FIDL compiler as well as each of the FIDL bindings.
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:
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:
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.
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.
This RFC makes it more difficult to use FIDL because it is now necessary to take a limit into consideration.
This RFC breaks backwards compatibility with tables with over 64 entries.
This has no security implications.
This has no privacy implications.
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.
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.