-
Notifications
You must be signed in to change notification settings - Fork 256
Description
Loading in bigger ttf files is noticeably slow. After using xdebug profiler it was evident that most common function being called is BinaryStream->readUInt16()
When viewing the places that call it, there seem to be many loops which just call the function multiple times in a row.
The function itself uses unpack, which allocates new array for each invocation and only the single value in it is used.
Proposal is to add a few helper functions to BinaryReader like
public function readUInt16Many($count) {
$str = $this->read(2 * $count);
return array_values(unpack("n_", $str));
}
public function readInt16Many($count) {
$str = $this->read(2 * $count);
$vals_uint16 = unpack("n_", $str);
$vals = array();
foreach ($vals_uint16 as $v)
$vals[] = $v >= 0x8000 ? $v - 0x10000 : $v;
return $vals;
}
array_values is needed because when using * for unpack, the array indexes start from 1, instead of 0.
Then the helpers could be used for example in cmap, hmtx, kern, post parsers:
$endCode = $font->readUInt16Many($segCount);
$idRangeOffset = $font->readUInt16Many($segCount);
In addition there is a generic r function in BinaryStream that accepts array with type + count, that one should also be optimized to call readUInt16Many.
Plus, the ->r(array()) cases could be even more optimized, since many of the calling places know to ask for uint16 array, so calling ->readUInt16Many($count); should also give a little boost, because it doesn't have to pass through the long switch list anymore.
When testing FreeSerif font with original code, the readUInt16() is called 76580 times, consuming 33% of the total font load time. After optimizations, the UInt16Many was called 10 times consuming 0.64% of time and readUInt16 11025 times consuming 13.21% of total time.
Also ->r() calls were reduced from ~2800 to ~500.