0xDEADBEEF

RSS odkazy
««« »»»

PHP refcount jako optimalizace

18. 5. 2023 #PHP #optimalizace

Refcount mechanismus v PHP se dá použít k optimalizacím.

Třeba taková funkce unpack pro parsování binárních dat musí vrátit pole (z jakéhosi důvodu indexované od jedničky) i když parsuje jen jeden int. V důsledku toho jednoduché unpack('v', $str)[1] trvá 75 ns, což je ostudné. Ve své podstatě jde o tři instrukce: cmp + jb pro kontrolu jestli je ve stringu dost bajtů a jeden mov. To by nemělo trvat 75 ns ale jeden takt.

Nicméně to můžu trochu optimalizovat. Když využiju fakt, že je pole je by-value typ, můžu implementovat takhle (pseudokódem, šlo by o nativní funkci):

function unpack($str) {
  static $arr1 = new array [1 => null];

  if (refcount($arr) > 1) {
    $arr1 = new array [1 => null];
  }

  $arr1[1] = chomp2Bytes($str);
  return $arr1;
}

Funkce unpack vždy drží jednu referenci na pole, které opakovaně používá jako výsledek.

Můžou nastat dvě situace:

  1. Volající kód pole změní. To nám nevadí, protože pole je by-value a program takové objekty může změnit in-place jen když mají refcount 1 (viz makro SEPARATE_ARRAY). A protože unpack vždy drží jednu referenci a volající kód druhou, musí dojít ke kopírování pole a změněna bude až kopie. Verze kterou drží unpack zůstane zachována.
  2. Volající kód si vrácené pole uloží do proměnné. To v příštím volání unpack detekujeme přímo, protože najednou refcount je vyšší než 1 a jednoduše alokujeme nové pole. Tohle se stává ale jen velice zřídka.

S touhle optimalizací unpack('v', $str)[1] trvá 50 ns (časy měřeny v interpreteru, JIT vypnutý). O třetinu lepší, ale stále ostudně pomalé.

Hlavní problém s funkcí unpack je její složitá sémantika, kdy musí parsovat vzorový string (v mém případě jen 'v', ale může to být i komplikovanější jako třeba 'Vid/Vdate/Ccount/V*children') a pak v gigantickém switchi skákat na těch pár instrukcí, které interpretují daný počet bajtů jako int nebo float dané délky, dané znaménkovosti a dané endianovosti. Tahle logika zabere dobrých 25 ns.

To je nakonec důvod, proč tohle píšu jako článek a ne jako patch pro PHP. I s vypětím všech sil se stejně nemůžu dostat do čísel, za které bych se nemusel stydět.

???

píše k47 (@kaja47, k47)