Programování

Proč efektivní paralelní programování musí zahrnovat přidělení škálovatelné paměti

Vícejádrový procesor? Ano.

Psát program, který běží paralelně? Ano.

Pamatovali jste si použít Scalable Memory Allocator? Ne? Pak si přečtěte ...

Podle mých zkušeností je často přehlíženým prvkem dobrého fungování paralelního programu zajistit, aby „alokace paměti“ programu byla připravena na paralelismus. Mohu vám ukázat neuvěřitelně snadný způsob, jak zjistit, zda je to problém kompilovaného programu (C, C ++, Fortran atd.) - a také jak to opravit.

Kritickou součástí jakéhokoli paralelního programu je škálovatelné přidělení paměti, které zahrnuje použitíNovýstejně jako explicitní volání namalloc, calloc nebo realloc. Mezi možnosti patří TBBmalloc (Intel Threading Building Blocks), jemalloc a tcmalloc. TBBmalloc má novou funkci „proxy“, která usnadňuje vyzkoušení libovolného kompilovaného programu za méně než 5 minut.

Výhody výkonu při použití škálovatelného alokátoru paměti jsou významné. TBBmalloc byl jedním z prvních široce používaných škálovatelných alokátorů paměti, v nemalé míře, protože byl zdarma s TBB, aby pomohl zdůraznit význam zahrnutí úvah o alokaci paměti do jakéhokoli paralelního programu. Dnes zůstává extrémně populární a stále je jedním z nejlepších škálovatelných alokátorů paměti, které jsou k dispozici.

Snadné řešení bez jakýchkoli změn kódu

Pomocí metod proxy můžeme globálně nahradit Nový/vymazat a malloc/calloc/realloc/volný, uvolnit/atd. rutiny s technikou nahrazení dynamického paměťového rozhraní. Tento automatický způsob nahrazení výchozích funkcí pro dynamické přidělování paměti je zdaleka nejpopulárnějším způsobem použití TBBmalloc. Je to snadné a dostačující pro většinu programů.

Podrobnosti mechanismu použitého v každém operačním systému se trochu liší, ale čistý efekt je všude stejný.

Naši pětiminutovou zkušební verzi zahajujeme stažením a instalací Threading Building Blocks (zdarma z //threadingbuildingblocks.org; je také součástí produktů Intel Parallel Studio).

Použijte proxy v Linuxu

V systému Linux můžeme provést náhradu buď načtením knihovny proxy v době načítání programu pomocí LD_PRELOAD proměnná prostředí (beze změny spustitelného souboru) nebo propojením hlavního spustitelného souboru s knihovnou proxy (-ltbbmalloc_proxy). Zavaděč programů pro Linux musí být schopen najít knihovnu proxy a knihovnu škálovatelného alokátoru paměti v době načítání programu. Za tímto účelem můžeme zahrnout adresář obsahující knihovny v LD_LIBRARY_PATH proměnnou prostředí nebo ji přidat /etc/ld.so.conf.

Zkuste takto:

čas ./a.out (nebo jak se náš program nazývá)

exportovat LD_PRELOAD = libtbbmalloc_proxy.so.2

čas ./a.out (nebo jak se náš program nazývá)

Použijte proxy v systému macOS

V systému macOS můžeme provést náhradu buď načtením knihovny proxy v době načítání programu pomocí DYLD_INSERT_LIBRARIES proměnná prostředí (beze změny spustitelného souboru) nebo propojením hlavního spustitelného souboru s knihovnou proxy (-ltbbmalloc_proxy). Zavaděč programu macOS musí být schopen najít knihovnu proxy a knihovnu škálovatelného alokátoru paměti v době načítání programu. K tomu můžeme zahrnout adresář obsahující knihovny v DYLD_LIBRARY_PATH proměnná prostředí.

Zkuste takto:

čas ./a.out (nebo jak se náš program nazývá)

export DYLD_INSERT_LIBRARIES = $ TBBROOT / lib / libtbbmalloc_proxy.dylib

čas ./a.out (nebo jak se náš program nazývá)

Použijte proxy ve Windows

Ve Windows musíme upravit náš spustitelný soubor. Můžeme buď vynutit načtení knihovny proxy přidáním #include "tbb / tbbmalloc_proxy.h" v našem zdrojovém kódu nebo pomocí určitých možností linkeru při vytváření spustitelného souboru:

Pro win32:

            tbbmalloc_proxy.lib / INCLUDE: "___ TBB_malloc_proxy"

Pro win64:

            tbbmalloc_proxy.lib / INCLUDE: "__ TBB_malloc_proxy"

Zavaděč programu Windows musí být schopen najít knihovnu proxy a knihovnu škálovatelného alokátoru paměti v době načítání programu. K tomu můžeme zahrnout adresář obsahující knihovny v CESTA proměnná prostředí. Vyzkoušejte to pomocí nástroje Visual Studio „Performance Profiler“ k načasování programu s možností zahrnutí nebo propojení a bez ní.

Testování využití naší proxy knihovny pomocí malého programu

Doporučuji vám vyzkoušet si vlastní program, jak je popsáno výše. Běh s proxy serverem i bez něj a uvidíte, jaké výhody vaše aplikace získá. Aplikace se spoustou paralelismu a velkým množstvím alokací paměti často zaznamenají 10-20% zvýšení (také jsem jednou viděl 400% zvýšení), zatímco programy s malým paralelismem nebo malým počtem přidělení nemusí mít vůbec žádný účinek. Rychlé testy popsané výše s knihovnou proxy vám řeknou, ve které kategorii je vaše aplikace.

Také jsem napsal krátký program, který ilustruje efekty a poskytuje snadný způsob, jak zkontrolovat, zda jsou věci nainstalovány a fungují podle očekávání. Můžeme vyzkoušet proxy knihovnu s jednoduchým programem:

#zahrnout

#include "tbb / tbb.h"

pomocí oboru názvů tbb;

const int N = 10 000 000;

int main () {

dvojitý * a [N];

parallel_for (0, N-1, [&] (int i) {a [i] = nový dvojitý;});

parallel_for (0, N-1, [&] (int i) {smazat [i];});

návrat 0;

}

Můj ukázkový program využívá hodně místa v zásobníku, takže „ulimit - je neomezený„(Linux / macOS) nebo„/ STACK: 10000000„(Visual Studio: Vlastnosti> Vlastnosti konfigurace> Propojovač> Systém> Velikost rezervy zásobníku) bude důležité, aby nedocházelo k okamžitým pádům.

Po kompilaci jsou různé způsoby, jak jsem spustil svůj malý program, abych viděl rychlost s knihovnou proxy a bez ní.

Spuštění a načasování tbb_mem.cpp na čtyřkolce virtuální Stroj Linux, viděl jsem následující:

% času ./tbb_mem

skutečné 0m0.160s

uživatel 0m0.072s

sys 0m0.048s

%

% exportLD_PRELOAD = $ TBBROOT / lib / libtbbmalloc_proxy.dylib

%

% času ./tbb_mem

skutečné 0m0,043s

uživatel 0m0.048s

sys 0m0.028s

Při spuštění a načasování tbb_mem.cpp na čtyřjádrovém iMacu (macOS) jsem viděl následující:

% času ./tbb_mem

skutečné 0m0,046s

uživatel 0m0.078s

sys 0m0.053s

%

% export DYLD_INSERT_LIBRARIES = $ TBBROOT / lib / libtbbmalloc_proxy.dylib

%

% času ./tbb_mem

skutečné 0m0,019s

uživatel 0m0.032s

sys 0m0.009s

Ve Windows jsem pomocí Visual Studio „Performance Profiler“ na quadcore Intel NUC (Core i7) viděl časy 94ms bez škálovatelného profilovače paměti a 50ms s ním (přidání #include "tbb / tbbmalloc_proxy.h"do ukázkového programu).

Úvahy o kompilaci

Osobně jsem neměl problém s kompilátory provádějícími „optimalizace malloc“, ale technicky bych navrhl, aby při kompilaci s programy byla tato kompilátorová „optimalizace malloc“ deaktivována. Může být moudré zkontrolovat dokumentaci kompilátoru vašeho oblíbeného kompilátoru. Například u kompilátorů Intel nebo gcc je nejlepší předat následující příznaky:

-fno-builtin-malloc (ve Windows: / Qfno-builtin-malloc)

-fno-builtin-calloc (ve Windows: / Qfno-builtin-calloc)

-fno-builtin-realloc (ve Windows: / Qfno-builtin-realloc)

-fno-builtin-free (ve Windows: / Qfno-builtin-free)

Pokud tyto příznaky nepoužijete, nemusí to způsobit problém, ale není to špatný nápad být v bezpečí.

souhrn

Použití škálovatelného alokátoru paměti je základním prvkem v jakémkoli paralelním programu. Ukázal jsem, že TBBmalloc lze snadno injektovat bez nutnosti změn kódu (ačkoli přidání „zahrnutí“ do Windows je moje oblíbené řešení Windows). Můžete vidět pěkné zrychlení s pouhými 5 minutami práce a můžete jej snadno použít na více aplikací. V systémech Linux a macOS můžete dokonce zrychlit programy, aniž byste museli mít zdrojový kód!

Kliknutím sem si stáhnete bezplatnou 30denní zkušební verzi Intel Parallel Studio XE.

$config[zx-auto] not found$config[zx-overlay] not found