Faktory ovlivňující rychlost vykonávání programového kódu.

• State of the Art schopností procesorů

 CISC instrukce se překládají na mikrokód, aby i procesory s CISCovou instrukční sadou mohly těžit z výhod RISCové architektury

 Vykonávání instrukcí mimo pořadí

 Přejmenovávání registrů

 Spekulativní vykonávání kódu dopředu

 Odhadování výsledků podmínek skoků

 Ve výsledku může jedno jádro procesoru vykonávat celé instrukce, nebo alespoň části instrukcí, paralelně

Tj. co programátor píše jako kód jednoho vlákna, se ve skutečnosti vykonává paralelně

Co bývalo výhodné paralelizovat, to dnes může rychleji spočítat „sériový kód“

Dobrý překladač může vytvořit takový strojový kód, který umí využít paralelizačních schopností procesoru

Proto se liší výkonnost kódu v závislosti na překladači a zvolené míře optimalizace

Ale ani ten nejlepší překladač neumí odhadnout vše

Proto je třeba mu umět pomoci takovým zápisem kódu, ze kterého toho pozná co nejvíce

A proto je třeba znát, jak to vypadá z pohledu procesoru

Low-level techniky, pokud pro to není zvláštní důvod, se vyplatí nechat na překladači

Ale algoritmy na vyšší úrovni jsou záležitosti pro programátora

Základní myšlenky

Co lze, to se vypočítá pouze jednou

Co lze, to se vypočítá paralelně

Je však třeba zvolit správnou granularitu výpočtu

Paralelizace totiž není vždy výhodná

V některých případech je sériový kód rychlejší, má menší režii – nevytváří a nesynchronizuje vlákna

Paměť se alokuje co nejméně, využívá se již alokovaná paměť

Program se píše tak, aby operační systém co nejméně swappoval

Redukovat náklady na vytvoření a synchronizaci vláken

Běžet co nejvíce v uživatelském adresovém prostoru

Ale hlavně, psát efektivní kód už samotného vlákna

Paralelizovaný neefektivní kód bude s největší pravděpodobností pomalejší než efektivně napsaný sériový kód

Eliminace skoků má zásadní vliv na zvýšení výkonu (jump je hodně náročnej)

Využit instrukce cmov – bytecode pro to nemá ekvivalent

Cílem je uspořádat podmínky, aby si procesor správně tipnul, která instrukce bude další

Při adresování paměti přes pointery *m musí překladač předpokládat, že *m může ukazovat kamkoli a nemá moc možností, jak optimalizovat. Proto vzhledem k optimalizacím je dobré použít zápis přes indexy, kdy takový zápis obsahuje jakousi nápovědu pro překladač, jak to celé optimalizovat.

Eliminace nepotřebných sekvencí Store-Load

Používání dočasných proměnných, které mohou být realizovány s pomocí registru

Programátor by měl pomoci překladači jejich použitím – namísto co nejkratšího zápisu kódu

Konverze operandů

Nemíchat operandy různé velikosti, konverze to zpomaluje

Nápověda pro překladač s autovektorizací

V nejhorším dojde k většímu využití pipelines procesoru

Podmínky jsou obvykle vyhodnocovány ve zkrácené formě – cílem je seřadit podmínky tak, aby při jejich vyhodnocování bylo zapotřebí provést co nejméně úkonů, tzn. Bylo co nejrychleji vyřazeno co nejvíce možností a aby byly co nejmenší nároky na vyhodnocení podmínky.

Sekvence AND končí prvním FALSE, sekvence OR končí prvním TRUE.

Branch prediction – předpovídání skoků

procesor obsahuje tzv. Branch prediction, kdy spekulativně vykonává kód dopředu podle toho, jaký předpokládá výsledek skoku. Uvedená konverze nemění stav branch-prediction, tj. Neovlivňuje urychlování volající funkce, a kdyby se alokovala paměť, např. Pro nový string, tak už to stav branch-prediction ovlivní.

Kopírování paměti

kopírování celého bloku paměti místo prvek po prvku

způsobuje náhlé, nedeterministické vytěžování systému

jinak než kritickou sekcí, např. Pomocí InterlockedIncrement apod. Kritická sekce má velkou režii.
