HipHop
Školení, která pořádám
Možná už jste slyšeli zvěsti o tom, že „Facebook přepisuje PHP“. Ve skutečnosti se jedná o projekt HipHop for PHP, který vezme zdrojový kód PHP, převede ho do C++ a ten zkompiluje. Motivace tohoto postupu je jasná – zvýšení výkonnosti, které prý dosahuje až 50 %. HipHop není jediný projekt, který něco takového dělá, z konkurenčních projektů zmíním Phalanger s původem v Česku, který PHP kompiluje do .NET. HipHop je výjimečný tím, že se už teď v praxi využívá na jednom z největších serverů na Internetu.
HipHop si nedokáže poradit s libovolným kódem:
- Není podporovaná funkce eval a nejspíš i některé další konstrukce.
- Nejsou podporované všechny extenze.
- Zatím chybí podpora vlastností z PHP 5.3.
- Není k dispozici na Windows.
Z těchto důvodů ani Facebook nepoužívá HipHop exkluzivně, ale obsluhuje pomocí něj jen 90 % svých požadavků.
Obří aplikace provozované na více strojích HipHop jistě rády časem využijí (byl uvolněn jako open-source). Menší servery si vystačí s akcelerátory (např. eAccelerator), ještě menší se zaměří třeba raději na optimalizaci databáze.
Další zajímavé informace v angličtině: Facebook, Ilia Alshanetsky.
Diskuse
Emil:
Znamená to tedy, že Facebook není napsán v PHP?
Naopak. Skoro celý frontend Facebooku je v PHP, proto si napsali nástroj pro efektivnější zpracování PHP.
Emil:
Aha, takže se jedná interpret PHP..
Technicky vzato to není interpret (ten zpracovávaný kód rovnou spouští), ale převaděč. Přesně, jak je napsáno v článku.
V podstatě by neměl být problém z HipHopu a nějakého C++ kompilátoru udělat AOT PHP modul.
tomas:
Možná to je trošku OT, ale šel by třeba Nette Framework přepsat do C++ a vložit přímo do PHP?
Ano v zásadě by to šlo. Facebook také před vytvořením HipHopu přepisoval kritické části PHP kódu do PHP extenzí (napsaných v C).
U Nette by byl asi problém minimálně se šablonama, které si Nette pro větší výkon kompiluje do PHP. Ten by šel elegantně (a výkonově optimálně) řešit zmíněným AOT modulem. Jen ten proces by byl poněkud šílený: template -> PHP -> C++ -> native code.
Méně elegantní by byl nějaký skript pro vygenerování cache šablon před převodem do C++ se zhruba stejným výkonem.
Myslím, že nějaký AOT modul by byl pro hostingy optimální.
lopata:
Phalanger je o něčem jiném, ten na rozdíl od toho HipHopu (mimochodem horší název fakt vybrat nemohli) kompiluje do .NET assembly rovnou. Kdežto tohle je v podstatě převaděč PHP -> C++ a pak už je na řadě GCC.
Škoda že neudělali nějakou masivní optimalizaci/přepsání Zend Engine třeba směrem k JITu tak, aby se to dalo po čase začlenit nebo spojit s aktuálním PHP core. Jak je vidět, asi by to bylo mnohem náročnější než ten převaděč.
No nejen náročnější. Po analýze kódu je možné s ním dále pracovat několika způsoby:
* udělat konverzi do bytecode
* udělat konverzi do jiného jazyka
* zkompilovat do nativního kódu
* kompilovat do nativního kódu za běhu (JIT)
(Seřazeno podle náročnosti implementace, trošku subjektivně.)
A výkon?
* Konverzí do bytecode nebo jiného jazyka problém pouze přesouvám, výkon bude záležet na použité VM, použitém kompilátoru apod.
* Kompilace do nativního kódu obvykle poskytuje celkem slušný výkon.
* JITka může nabídnout díky dalším (runtime) optimalizacím ještě větší výkon, ale nejspíš bude vyžadovat více operační paměti. Navíc lepší výkon nastává až po určité době běhu, předtím je tu více poznat režie na kompilaci apod. O tom jsem (v souvislosti s Javou) viděl koneckonců článek od IBM.
* Využití procesorově specifických instrukcí je možné jak u JIT, tak v některých případech i u AOT (http://en.wikipedia.org/wiki/AOT_compiler). Běh aplikace na serveru je typický případ, kdy by to neměl být problém. Obecně to nebývá problém při lazy spouštění AOT compileru, což ukazuje i implementace Javy u mnoha dnešních Sony Ericssonů.
A teď k běhu PHP skriptů: skript bývá spouštěn na malou chvilku. Vícero instancí skriptu AFAIK nesdílí jakékoli prostředky. Přijde mi to jako typický případ, kdy se JIT (minimálně ve srovnání s AOT) krutě nevyplatí.
Samozřejmě, upravit PHP tak, aby třídy v paměti zůstávaly apod. by bylo možné. V praxi by si to asi vyžádalo i podporu synchronizace vláken apod. Tento přístup je vhodný spíš pro běh jednoho většího (a hlavně navštěvovanějšího) projektu, zatímco typicky u freehostingů s hodně uživateli se zpravidla ne až tolik navštěvovanými weby by byl naopak škodlivý. Na co držet v paměti něco, co je zřídkakdy využíváno?
Vzhledem k obsazení této části trhu (Java, .NET) bych moc nevěřil tomu, že investice do takového vylepšení by se někdy vrátila.
lopata:
Pěkné shrnutí, jak je vidět, muselo by se do toho hodně hrábnout aby se tam dal JIT efektivně nasadit, ale nemyslím, že by se to nevyplatilo, protože jak se ukazuje, je dost velké množství projektů právě typu "větší a hlavně navštěvovaný", které používají PHP a tohle by jistě uvítaly.
Jeden příklad za všechny je wikipedia, před nedávnem si stěžovaly na mailing listu, že je to s tou optimalizací v PHP dost bída. Uvidíme zda nasadí to facebookové řešení, tipnul bych, že se o to minimálně pokusí.
Těžko odhadovat.
Ale teď jsem studoval Google Apps Engine a narazil jsem na http://www.caucho.com/resin-3.0/quercus/tutorial/module/index.xtp , což by v tomto mohlo být řešením. Nedovedu ale v tuto chvíli posoudit použitelnost.
Navíc neznám výkon této implementace. Co jsem četl, tak sice JRuby je cca dvakrát výkonnější než běžné Ruby JRE, ale Jython je naopak pomalejší. Minimálně teď je JRE nejspíš specializované na statické jazyky (vzhledem k dominantnímu jazyku se není čemu divit). Ale je celkem možné, že se to s Javou 7 změní. Nemám o tom moc informací, ale soudím tak mj. z nové instrukce - invokedynamic.
noname:
Přiznám se, že tyhle kompilátory, převaděče či jak se jim říká mě lákají a rád bych se dozvěděl o jejich použití více, ale nevím jak je uchopit, jak s nimi začít. Nelákají mě tak ani kvůli tomu, že kód je rychlejší, ale proto, že jestli to chápu dobře, tak jsou také velmi dobrou ochranou proti tomu, aby mi někdo kód ukradl (resp. je to složitější a proti běžným kiddies to bude postačovat).
Typický příklad ze života: naprogramoval jsem klientovi aplikaci v php, ten ji chce dát na svůj hosting, já ale nechci, aby tu aplikaci mohl někde znovu použít, nebo aby se v ní mohl hrabat (bez toho, aby mi za to platil).
Tj. je možné ji takovou aplikaci takto zkompilovat a dát na jeho hosting? Jak to udělám, co k tomu potřebuji (jak u sebe, tak na hostingu klienta)?
A nebo si to představuji jako hurvínek válku? ;)
P.S.: a kdyby to šlo, šlo by takto překomilovat i třeba celý wordpress či jiný PHP CMS s mými PHP skripty (šablony, funkce, pluginy)?
anonym:
-zkompilováno do native codu to určitě bude muset mít podporu na serveru, takže na běžný hosting ani náhodou
-kompilovat lze do php "bajtkódu", na jeho spuštění stačí na serveru něco od zendu:
http://www.zend.com/en/products/guard/-nevím, jak má Wordpress řešeny licence. Ale pokud je to čitě GPL, tak na nějaké skrývání svých zdrojáků zapomeňte. Jakmile klient dostane aplikaci, JE VAŠE POVINNOST mu k tomu dát na jeho žádost zdrojové kódy a on MÁ PRÁVO si s nimi dělat co chce
Re4DeR:
Nemá právo dělat si s nimi co chce.
v6ak:
Pokud jde o aplikaci postavenou na GPL nebo alespoň využívá GPL, pak úprava musí být šířena též pod GPL a ta toto právo zajišťuje. Podobně to funguje i u mnohých jiných licencí. Existují i méně striktní licence, které například umožňují použít knihovnu a nezasáhnout tím licenci (např. LGPL, MIT).
Megaloman:
Radoval jsem se předčasně :-)
Protože se jedná o proces PHP -> CPP -> BIN, zřejmě nebudou podporovány žádné dynamické vymoženosti PHP, (jak je uvedeno) eval()em počínaje, přes proměnné proměnné, proměnné funkce a proměnné třídy až po dynamické includy a class'n'interface autoloader.
Když je FB tak posedlý výkonem, proč si to nenapíšou v Céčku? Stačilo by si napsat apache modul a jedem ;-)
Jakub Vrána :
Dynamické include a autoloader by podle mě možné být mohly.
Proč Facebook nepíšou v Céčku je popsané v odkazovaném článku – v PHP se jim vyvíjí dobře a rychle a mají pro něj spoustu programátorů, takže se jim snadno přidává nová funkčnost.
Megaloman:
To s vývojem v PHP a převodem do CPP částečně chápu.
Ale netuším, jak si statický jazyk poradí s něčím takovým:
<?php
function __autoloader($component)
{
$path = '._lib_' . strtolower($component) . '.php';
require_once strtr($path, '_', DIRECTORY_SEPARATOR);
}
?>
nebo pak
<?php
$class = 'page_' . $_GET['page'];
$page = new $class();
?>
Soubory přeci musí být nejdříve zkompilovány, potom slinkovány a až nakonec můžou být spuštěny, ale řetězce $compnent nebo $class získám až za běhu.
Netvrdím, že to nelze, ale nenapadá mě jak (moje zkušenosti C a C++ jsou na úrovni lehce pokročilého) a docela by mě zajímalo, jak by potom vypadal překlad PHP -> CPP.
Megaloman:
Jedině, že by to zkompilovalo a slinkovalo vše, co najde v podadresářích a v include_path, pak by zase nefungovalo include('../../../lib/neco.php');.
U těch dynamických tříd, proměnných proměnných a proměnných funkcí by si to mohlo držet seznam párů název_třídy/její_prototyp, u funkcí a proměnných pár název/ukazatel.
Ale to mi příjde jako brute force přístup, který má hodně omezení, přitom podle FB "...provides engineers a way to use HipHop without changing how they write PHP.", takže tudy cesta asi nevede.
Jakub Vrána :
Moje znalosti C++ jsou asi ještě menší, ale slyšel jsem něco o dynamických knihovnách, které se nahrávají až v případě potřeby. Představoval bych si to tak, že se jeden PHP skript zkompiluje do jedné knihovny a pak to něco zase poslepuje. Ale třeba to tak vůbec není.
Tigu:
Jde to řešit přes balíčky (dynamické knihovny) - Standardní C je umí za běhu loadovat i unloadovat. Dělá se s tím sice blbě, ale jde to.
U PHP kodu jde o to že se pro každý request spouští znovu a proto je dobré, když se načítají jen věci, které jsou pro daný request potřeba. Stejně to dělá i CGI ...
Kdežto třeba FastCGI eliminuje overhead spojený s inicializací kódu tím, že jede jedna aplikace a ta obsluhuje (ve smyčce, či lépe ve více vláknech) veškeré požadavky - tím, že se k DB připojuje jen jednou a že je kód načten také jednou a použit několikrát, není třeba řešit striktně autoload a autounload (pouze pro moduly, které nebudou nikdy použity). Samotné loadovaní je uvolňování je pak náročnější na prostředky, než držet aplikaci v paměťi - pokud správně funguje memory management (což je u peristantní aplikace důležité) - ale i na C jde napasovat GC.
Diskuse je zrušena z důvodu spamu.