[PA] Piešťanská spojka 2: Pomsta

Knihu Piešťanská spojka od Petra Adameckého (nedávno som o nej písal) som kúpil rovno v dvojbalení s druhým dielom s podtitulom Pomsta. Začal som čítať s veľkými očakávaniami. Prvý diel bol príjemný špionážno politický thriller s jemnou dávkou akcie a s trochu väčšou dávkou humoru. Niektoré vymyslené postavy sa až príliš podobali na reálne slovenské osobnosti politického a spoločenskej života.

20160607_053512050_iOSKniha je síce pokračovanie, no skôr také voľné. Vracajú sa staré známe postavy, ako pracovník Slovenskej tajnej Služby Vlado a jeho bývalý spolužiak a kamarát exkriminálnik Roman. Samozrejme nechýba ani kultový prezident Jano. Vodca našej krajiny  dostáva oveľa viacej priestoru a stáva sa kľúčovou postavou v deji knihy. Ten si bral veľkú inšpiráciu v Ukrajinskej “vojne” na Kryme. Samozrejme rovnako ako v predošlom dieli sú Rusi tí zlí a Američania tí dobrí. V knihe sa bojuje na južnom Slovensku. Nechcem prezrádzať veľa z fabuly, no vyvinie sa tu národnostný konflikt medzi Maďarmi a Slovákmi.

Môj hlavný problém s knihou je práve táto neznášanlivosť. Áno, obe strany sú tam vykreslené surovo a v podstate ekvivalentne. No písať o tom ako Slovenská armáda vyvraždila Maďarskú obec a ako Maďarskí separatisti pozbierali Slovákov na  juhu krajiny, mučili ich a potom obesili mi už príde trochu moc. Ako keby knihe chýbali isté hranice.

Samotný dej nie je skoro vôbec prekvapivý. Rovnako aj štýl písania je taký jednoduchší. Naproti tomu humor je veľmi dobre zvládnutý a naozaj som sa chvíľami aj smial. Čo všetko  robí z knihy celkom oddychovku. Nebyť toho námetu aj by som knihu odporučil. No téma Maďarov na južnom Slovensku je stále celkom zneužívaná rôznymi skupinami na získanie podpory. Preto si nemyslím, že je dobrý nápad ešte tomu pridávať. Jedno malé mínus dostáva kniha ešte za chýbajúce rozuzlenie, na to si čitatelia musia prečítať aj ďalší diel…

[BF] Niekedy stačí jeden slnečný lúč

Ešte minulé Vianoce som dostal túto útlu knižočku s príbehmi na zamyslenie a potešenie duše. V „návode“ ku knihe je rada, netreba ju celú prečítať za jeden večer, skôr postupne príbeh po príbehu. Vzal som si odporúčanie k srdcu. Čítal som veľmi pomaly a bohužiaľ aj nepravidelne.

20160427_054547848_iOSPríbehy sú fajn. Jedna, dve strany, ktoré poukážu na problém v súčasnej spoločnosti, ozrejmia medziľudské vzťahy, alebo jednoducho prezentujú ako byť lepším človekom. Najviac ma oslovil príbeh v podstate o tom ako žiaden majetok a peniaze nevyvážia hodnotu citu k inému človeku.

Autor Bruno Ferrero je katolícky kňaz. No nemyslím, že to má veľký vplyv na hodnoty z príbehov. Pokojne to mohol napísať aj mimozemšťan a nijak by to neubralo na ich aktuálnosti a expresívnosti.

Čo viac k tomu napísať? Kniha sa mi páčila a určite je to dobrý darček pri akejkoľvek príležitosti.

Prezentácia Modern C++

Minulý rok som pripravoval a prezentoval prezentáciu o modernom C++. Rozhodol som sa ju sprístupniť pre všetkých tu na svojom blogu. Hlavnou témou je obrovské množstvo zmien, ktoré za posledné roky C++ absorbuje. Začína to štandardom C++11. Pribudli do jazyka range based for loops (v iných jazykoch nazvané aj foreach cykly) a automatická dedukcia typov. Dostanem sa aj k rozšíreniam štandardnej knižnice a pár trikom.

first

Prezentácia sa sťiahne kliknutím na obrázok.

Chcel by som poďakovať kolegovi Jozefovi Kosoru za opravy faktických chýb a Ladislavovi Bencovi za skontrolovanie angličtiny.

Creative Commons License
Modern C++ presentation by Peter Koscelanský is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

[OSN] Kladivo na čaroděje 7: Síť přízraků

Keď niekam idem väčšinou si odtiaľ prinesiem buď fľašu miestneho vína, alebo knihu. Tá už miestna byť nemusí. Takto som si aj minulý rok v Žiline kúpil mne totálne neznámu knihu zo série Kladivo na čaroděje od autora Ondřeje Nečasa. Asi som mal zatemnenie mysle. Lebo inak si nedokážem vysvetliť, prečo som si kúpil siedmu inštaláciu v sérií a nie prvú.

20160213_150323802_iOS
Dej sa našťastie dal pochopiť aj bez predchádzajúcich znalostí miestnej mytológie. I keď nazývať to dejom je možno trochu prehnané. Taký priemerný štandard B-čkového fantasy. Udalosti knihy sú zasadené do súčasnej Prahy, kde sa okrem turistov promenádujú upíri, černokňažníci, pekelné bytosti a samozrejme zlo najväčšie motivační rečníci. Félix Jonáš je typický antihrdina. V podstate sa snaží hlavne prežiť a keď už sa musí miešať do záležitosti iných ľudí, tak sa aspoň uistí, že naprázdno neodíde.

Čím sa kniha snaží zaujať je humor. Povedal by som, že jej to aj celkom ide. V jednej časti sa spolu stretnú Félix Jonáš, Buffy premožiteľka upírov, čiernobiely Tarzan, primár Sova z Nemocnice na okraji mesta a, aby sme to mali kompletné, Benedict Cumberbatch. Viac asi ku knihe ani netreba dodávať, netreba očakávať veľa a možno budete príjemne prekvapený.

Je std::div na niečo dobrý?

V Cčkovej knižnici je od dávnych dôb funkcia div, ktorá vykoná celočíselné delenie a vráti rovno aj podiel aj zvyšok. Úvaha za tým je asi taká, že x86 procesory aj tak pri inštrukcií delenia vyrátajú obe hodnoty. Prečo nepoužiť túto vlastnosť na ušetrenie si roboty a teda zvýšenie výkonu? Nedávno som rozmýšľal rovnako a použil túto funkciu v jednom C++ projekte (samozrejme ako väčšinu štandardnej knižnice, aj túto funkciu C++ zdedilo a priviedlo do std:: namespace).

Ako vždy úvahy nestoja za nič, treba reálne merania. Nahodil som to všetko do frameworku Google Benchmark. Chvíľu som ladil kód aby kompilátor nevyoptimalizoval všetky premenné. Našťastie pár volatile slovíčok Visual Studio 2015 presvedčilo. Nasleduje benchmarkový kód a pod nim aj vygenerované inštrukcie. Použitá bola základná Release konfigurácia x64.

static void BM_StdDiv(benchmark::State& state)
{
	while (state.KeepRunning())
	{
		volatile int a = 1, b = 1;

		auto res = std::div(a, b);

		volatile auto x = res.quot;
		volatile auto y = res.rem;
	}
}
BENCHMARK(BM_StdDiv);

Z toho vygenerovaný kód:

00007FF65764334B  mov         dword ptr [a],1  
00007FF657643353  mov         dword ptr [y],1  
00007FF65764335B  mov         edx,dword ptr [b]  
00007FF65764335F  mov         ecx,dword ptr [a]  
00007FF657643363  call        qword ptr [__imp_div (07FF657646608h)]  
00007FF657643369  mov         dword ptr [b],eax  
00007FF65764336D  shr         rax,20h  
00007FF657643371  mov         dword ptr [x],eax 

Funkcia s operatórmi namiesto std::div je trochu prehľadnejšia.

static void BM_DivMod(benchmark::State& state)
{
	while (state.KeepRunning())
	{
		volatile int a = 1, b = 1;

		volatile auto q = a / b;
		volatile auto r = a % b;
	}
}
BENCHMARK(BM_DivMod);

Znovu natívny kód:

00007FF6576433DB  mov         dword ptr [a],1  
00007FF6576433E3  mov         dword ptr [r],1  
00007FF6576433EB  mov         ecx,dword ptr [b]  
00007FF6576433EF  mov         eax,dword ptr [a]  
00007FF6576433F3  cdq  
00007FF6576433F4  idiv        eax,ecx  
00007FF6576433F6  mov         dword ptr [q],eax  
00007FF6576433FA  mov         ecx,dword ptr [b]  
00007FF6576433FE  mov         eax,dword ptr [a]  
00007FF657643402  cdq  
00007FF657643403  idiv        eax,ecx  
00007FF657643405  mov         dword ptr [b],edx 

A výsledky? std::div 8 nanosekúnd, operátory / a % 6 nanosekúnd. Samozrejme zato môže fakt, že std::div je implementovaný v runtime a nenainlinuje sa, čo má za následok zbytočne volanie takejto triviálnej funkcií. Po tejto negatívnej skúsenosti som otestoval aj x86 konfiguráciu a na moje prekvapenie sa tu rozdiely zotreli a dokonca po opakovaní sa dostal std::div do vedenia v pomere 5ns ku 6ns. Prečo je to kratšie ako pri x64 neviem, no nie som si ani istý či sú nejak rozumne nieto výsledky porovnateľné.

Na záver som ešte nahradil int za long long a merania sú neintuitívne presne opačné. Na x86 je to 25ns pre std::div a 22ns pre operátory. Na x64 zase 14ns pre std::div ku 20ns, ktoré si zapýtajú operátory.

Čo teraz? Výsledky sú závislé od použitej platformy, takže ak chceme vždy maximálny výkon, tak by sme mali ifdef-ovať. Čo je ale pravdepodobne veľmi zlý nápad. Podľa mňa sú operátory čitateľnejšie a rozdiel zanedbateľný. Navyše iné kompilátory a procesory sa k tomu môžu postaviť rozdielne.

(Na internete sa spomína, že kompilátory by mohli pár operátorov / a % nahradiť za jednu idiv inštrukciu. Trochu som to skúšal a nezdá sa, že by akýkoľvek rozšírený kompilátor robil takéto transformácie.)

[AC] Vražda v End House

Nie som nejaký extra fanúšik detektívok, no občas sa ponorím do dobrodružstva hrdinu, ktorý bojuje proti zločinu hlavne mysľou. Po Sherlockovi Holmesovi je určite najznámejším detektívom Belgičan Hercule Poirot z pera Agáty Christie.

20160109_123058413_iOS

V knihe vražda v End House je Poirot na dovolenke a v podstate sa už neplánuje v živote venovať riešeniu záhad. Upútajú ho životohrozujúce „náhody“ okolo slečny Nick a rozhodne sa ju zachrániť a zistiť, kto jej usiluje o život.

Dej je taký štandardný. Na úvod sa oboznámime s postavami. V jednej kapitole je dokonca prezentovaný zoznam doterajších podozrivých. Potom sa udejú udalosti, s ktorými si nikto nevie rady. Dokonca ani Poirot. No ten nakoniec nechá pracovať svoje šedé mozgové bunky a rozsekne tento gordický uzol.

Celé dielo má okolo sto strán a číta sa veľmi príjemne. Jediný problém som mal tým, že tesne pred koncom som si spomenul, že som toto vlastne videl sfilmované a už ma záverečné rozuzlenie až tak neprekvapilo. To je asi daň za to, že detektívky sa tak ľahko sfilmujú. :)

Microbenchmark pre C++

Občas tu napíšem aj niečo o programovacom jazyku C++. Jeden takýto článok bol o meraní času na Windows-e. Konkrétne o meraní času pre potreby vyhodnocovania výkonu algoritmov. Na tento účel sú niektoré metódy vyložene nevhodné. Trochu som s tým zápasil a našiel som ako tak prijateľnú metódu. Ďalší problém je ako navrhnúť testy. Teda aký veľký vstup, koľko opakovaní, či zahodiť prvých pár výsledkov a mnohé ďalšie rozhodovania vás čakajú pri návrhu testov rýchlosti behu programu.

Nedávno som objavil malú knižnicu od Googlu s názvom Benchmark. Táto multiplatformová záležitosť ponúka celkom dobrý framework na písanie testov a prezentovanie výsledkov. Testy (čo sú vlastne funkcie s presne daným prototypom) musia dodržať istú štruktúru. Najprv musia inicializovať všetko čo potrebujú. Tento prológ sa nepočíta do samotného testu. Potom nasleduje slučka, v ktorej je samotný testovací kód. Podmienka cyklu je riadená priamo frameworkom. Pomocou nej sa rozhoduje či test ešte nechať bežať alebo nie. Takto pripravený test sa potom ešte zaregistruje aby Google benchmark s ním rátal. Podobne je to pri unit testoch gtest.

Štandardný výstup je konzola. Vo výpise je vidieť meno testu, čas ako dlho trvala jedna iterácia a koľko iterácií sa vlastne vykonalo. Alternatívne sa dá ako výstup použiť JSON, alebo CSV súbor.

Jednoduchý benchmark na push_back do vectora s rezerváciou mista a bez nej:

#include <vector>

static void BM_PushBack(benchmark::State& state)
{
	while (state.KeepRunning())
	{
		std::vector<int> v;
		benchmark::DoNotOptimize(v);

		for (int i = 0; i < state.range_x(); ++i) 
		{ 
			v.push_back(i); 
		}
	}
} 
BENCHMARK(BM_PushBack)->Arg(10)->Arg(10000)->Arg(10000000);

static void BM_PushBackReserve(benchmark::State& state)
{
	while (state.KeepRunning())
	{
		std::vector<int> v;
		benchmark::DoNotOptimize(v);

		v.reserve(state.range_x());

		for (int i = 0; i < state.range_x(); ++i) 
		{ 
			v.push_back(i); 
		}
	}
} 
BENCHMARK(BM_PushBackReserve)->Arg(10)->Arg(10000)->Arg(10000000);

BENCHMARK_MAIN();

Samozrejmosťou je podpora parametrizovania (Arg a range_x vyššie) testov. Rovnako je podporované aj vypínanie a zapínanie merania počas testu. Podľa dokumentácie by mali byť podporované aj viac vláknové testy, no to som zatiaľ neskúšal.

Ostáva teda posledná otázka a to, či je to na niečo dobré a či merania dávajú zmysel. Na Windowse vo Visual Studiu 2015 sa zisťovanie cyklov procesora deje pomocou intrinsic funkcie __rdtsc. Čo by mal byť správny spôsob ako získať čo najpresnejšiu hodnotu. Rovnako je potrebné aby všetok boilerplate zaberal čo najmenej inak to bude skresľovať výsledky. Celkom sa to podarilo, lebo autori si dali záležať aby kompilátor čo najviac donútili inlinovať kód starajúci sa o samotné meranie a spúšťanie testov. Čiže áno tento framework je celkom použiteľný na testovanie rýchlosti algoritmov.

Treba si uvedomiť, že Google benchmark nie je určený na testovanie rýchlostí aplikácií. Nato slúžia profilery a iné tooly. Toto je vyslovenie na testovanie konkrétnych malých kúskov kódu a porovnávanie ich rýchlosti na konkrétnom OS a CPU. Preto aj je dôležité venovať dostatočný čas príprave testov. Merania musia prebiehať so zapnutými optimalizáciami, inak meriame nezmysly. Kompilátory radi vyhadzujú nepotrebné časti programov. Preto sa môže stať, že celý náš test bude nahradený za nop. Optimalizátor príde nato, že vlastne nič s výsledkom nerobíme a preto môže všetko vymazať. Pozorovateľný výstup bude rovnaký a to je jediné čo musí zachovať. Framework ponúka funkciu benchmark::DoNotOptimize, ktorá sa pomocou rôznych trikov (priraďovanie do volatile) snaží zabezpečiť aby niektoré premenné neboli takto „odoptimalizované“. Bohužiaľ podľa mojich pokusov tieto techniky nie vždy fungujú a Visual Studio aj takéto premenné odstráni. Samozrejme vždy sa to dá obísť, no vyžaduje sa pri tom už trochu mozgovej aktivity a znalostí x86 inštrukcií, keďže treba pozerať vygenerovaný kód.

Nasledujúci test by mal odmerať ako dlho trvá funkcia strlen, bohužial to nefunguje, lebo vygenerovaná binárka vôbec strlen nevykoná. V tomto prípade pomôže premennú end deklarovat ako volatile.

static void BM_Strlen(benchmark::State& state)
{
	char *str = (char*)malloc(state.range_x() + 1);
	memset(str, 'a', state.range_x());
	str[state.range_x()] = '\0';

	while (state.KeepRunning())
	{
		auto end = str + strlen(str);
		benchmark::DoNotOptimize(end);
	}
}
BENCHMARK(BM_Strlen)->Arg(10)->Arg(100)->Arg(10000)->Arg(100000);

Moje merania už presúvam z vlastných riešení na Google Benchmark :).