googlefonts / googlefonts/fontations
[read-fonts] Speed up ValueFormat size calculation
- Dominant language
- Rust
- Stars
- 826
- Forks
- 75
- Avg merge
- 22h 33m
- Merged PRs (30d)
- 75
Description
I see 0.8% in my Roboto HarfRust profile spent in `value_record.rs`:
```rust
/// Return the number of bytes required to store a [`ValueRecord`] in this format.
#[inline]
pub fn record_byte_len(self) -> usize {
self.bits().count_ones() as usize * u16::RAW_BYTE_LEN
}
```
As it happens, we're only interested in counting ones of a u8 number. In HB I optimized this by writing a custom function instead of relying on the compiler intrinsic:
```c++
/* Return the number of 1 bits in a uint8_t; faster than hb_popcount() */
static inline unsigned
hb_popcount8 (uint8_t v)
{
static const uint8_t popcount4[16] = {
0, 1, 1, 2, 1, 2, 2, 3,
1, 2, 2, 3, 2, 3, 3, 4
};
return popcount4[v & 0xF] + popcount4[v >> 4];
}
```
This is the case because unless you build for your native arch, compilers don't rely on CPU ops for popcount and generate code that takes about 10 ops (branchless). I found that this replacement speeds up measurably and reliably.
Caveat:
```
// Note: spec says skip 2 bytes per bit in the valueformat. But reports
// from Microsoft developers indicate that only the fields that are
// currently defined are counted. We don't expect any new fields to
// be added to ValueFormat. As such, we use the faster hb_popcount8
// that only processes the lowest 8 bits.
```
Contributor guide
No contributing guide indexed for this repository
Research direction
Start in value_record.rs at ValueRecord::record_byte_len and review the existing bit-counting behavior against the issue's ValueFormat caveat. Compare the proposed u8 counting approach with the current implementation, then use the Roboto HarfRust profile or an equivalent benchmark to verify the reported speedup without changing the calculated size.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- computer-graphics
- Issue type
- Refactor
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 52/100