|
Základní koncepty Vybavenost nástroji, umožňujícími tvorbu vlastních programů - aplikací, je jedním z důležitých kriterií při hodnocení výpočetních systémů. Z tohoto pohledu je linuxový systém THUNDER více než uspokojující. K dispozici je obrovské množství jazyků skriptovacích (viz dále) i jazyků kompilovaných. Prakticky pro každý jazyk podchycený normou existuje interpreter nebo překladač, obvykle mnohem kvalitnější, než poskytují komerční firmy pro platformu DOS/Windows. Díky jejich GNU původu je také snadno dostupná dokumentace a zdrojové kódy. Rozsáhlá základna vývojářů a uživatelů představuje záruku včasného odhalení a opravy potenciálních chyb. To, co obvykle nazýváme programováním, je zápis algoritmu pomocí jazyka s přesně (často normou) definovanými lexikálními strukturami a syntaxí. Stejný problém (například výpočet faktoriálu) lze uchopit rozdílnými algoritmy (například rekurzivním a iterativním) a ty dále zapsát pomocí různých programovacích jazyků (například C, Pascal, Fortran, Basic, bc, Perl a další). Tento takzvaný "zdrojový text/kód" (source code) lze zpracovat překladačem (compiler) na spustitelný program v případě kompilovaných jazyků (C, Pascal, Fortran) nebo vykonávat "řádku po řádce" interpretem v případě jazyků interpretovaných/skriptovacích (Basic). K mnoha programovacím jazykům existuje překladač i interpreter, ale je preferováno použití jednoho z nich, například kvůli rychlosti, přenositelnosti a podobně. Hranice mezi jazyky interpretovanými a kompilovanými je neostrá. Mnoho interpretů ve skutečnosti překládá zdrojový text do jakéhosi mezikódu v paměti a ten posléze provádí (Perl). Pro jeden jazyk mohou existovat v systému různé překladače nebo interprety. Rychlost výsledné aplikace (programu) závisí na cestě, kterou vznikla. Rozhodující je většinou algoritmus, avšak pro stejný algoritmus hraje důležitou roli i volba jazyka a překladače. Výběr jazyka by měl sledovat kompromis mezi "obtížností" programování a potřebnou rychlostí programu. Pokud doba běhu programu bude typicky sekundy, je i 500%-ní rozdíl v rychlosti pro různé jazyky a překladače prakticky irelevantní. Pro výpočet trvající typicky hodiny a více je už rozdíl řádově desítek procent podstatný. Také druh aplikace hraje roli při výběru programovacího jazyka. Pro práci s textem a například CGI skripty se mnohem více hodí Perl, než C. Pro numerické výpočty je naopak vhodnější jazyk C, případně Fortran nebo Pascal. K symbolickým manipulacím se zase více hodí funkcionální jazyky, například Scheme. Vzhledem k předpokládanému využití serveru THUNDER k numerickým výpočtům, se budeme dále až na výjimky věnovat trojici kompilovaných jazyků: C, Fortran, Pascal. Imperativní kompilované jazyky - C, Fortran, Pascal Volba překladače jazyků C, Fortran a Pascal je v linuxových GNU systémech prakticky jednoznačná. Program gcc (GNU Compiler Collection) zde přestavuje základní prostředek vývoje. Spolu s různými standardními parsery dokáže překládat zdrojové texty v jazycích C, C++, Objective C, Java, CHILL a Fortran. Volitelné parsery rozšiřují množinu jazyků o Pascal, Ada95 a další. Viz dokumentaci programu GCC. Další existující překladače (vyjma klonů GCC) zmíněných jazyků obvykle nedosahují kvality GCC, mohou však poskytovat jiné výhody. Příkladem je překladač Pascalu `ppc386' zachovávající vysoký stupeň kompatibility s Borland TURBO Pascal mutací jazyka Pascal. Rozpětí podporovaných jazyků je dáno koncepcí systému GCC, jenž obsahuje pouze malou část (parser) jazykově závislou provádející lexikální analýzu příslušného jazyka a jeho převod do mezikódu RTL (register transfer language). Všechny další operace a optimalizace jsou již jazykově nezávislé. RTL má charakter seznamů, vzdáleně připomíná Lisp. Teprve až v posledních krocích zpracování se rozhoduje o fyzickém umístění proměnných v paměti a manipulaci s registry. Ukázky RTL mezikódu, stručný popis optimalizací, ukázky generovaného assembleru a srovnání s jinými kompilátory lze nalézt například na adrese http://www.gnu.cz/gcc.html. Předchozí diskuse o parserech nás nutně přivádí k otázce norem a verzí implementovaných jazyků. Zhruba řečeno, GCC nabízí až na poslední verze standardů jazyků kompletní podporu. Poslední verze jsou obvykle podporovány částečně. Navíc jsou obvykle podporována různá nestandardizovaná rozšíření, třeba GNU rozšíření. Například pro jazyk C jsou podporovány následující standardy: částečně traditional (pre-ISO) C, ANSI C standard (X3.159-1989), respektive ISO/IEC 9899:1990 (C89/C90), AMD1 1990 (C94/C95) a částečně ISO/IEC 9899:1999 (C9X/C99). Pro numerické programování může být zajímavá podpora koplexních proměnných a funkcí (dle C9X/C99). Podobně pro jazyk Fortran jsou podporovány normy: kompletně ANSI FORTRAN 77, částečně ANSI FORTRAN 90, některá rozšíření populární mezi uživateli UNIXového `f77' a konvertoru `f2c', některá rozšíření populární mezi uživateli dalších překladačů, například Digital Fortran a některá GNU rozšíření. Podrobnosti viz INFO dokumentace k příkazu `g77'. Pro úplnost doplňme podporované jazykové standardy pro Pascal: kompletně Pascal standard (ISO 7185:1990, ANSI/IEEE 770X3.160-1989), částečně Extended Pascal standard (ISO/IEC 10206:1991), částečně UCSD Pascal, Borland Pascal 7 (včetně mnoha unitů), Pascal-SC a některá GNU rozšíření. Pro podrobnosti nejen o podporovaných standardech viz INFO dokumentaci ke GNU Pascalu `gpc' a domovskou stránku GNU Pascal. Tolik GNU Compiler Collection. Jiné překladače mohou poskytovat jinou jazykovou podporu. Například Free Pascal Compiler `ppc386' (Portable Pascal Compiler) udává kompatibilitu s Turbo Pascal a Delphi (2.0). Příslušná dokumentace je v adresáři `/usr/share/doc/fp-docs'. Viz Dokumentace, literatura, vyhledávání souborů.
Všechny zmíněné překladače gcc, g77,
gpc, ppc386 a další pracují podobným
způsobem, v podobných fázích. První předloží zdrojový text
ldd example libc.so.6 => /lib/libc.so.6 (0x40018000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)Informace o druhu binárního souboru lze podobně zjistit příkazem file...
file example
example: ELF 32-bit LSB executable, Intel 80386, version 1,
dynamically linked (uses shared libs), stripped
Pro úplnost poznamenejme, že často je před vlastním překladem (parsováním) prováděno jakési předzpracování, preprocessing. Například zdrojový text v jazyku C může obsahovat, a také často obsahuje, instrukce pro překladač. Například definice konstant, maker, pokyny pro podmíněný překlad a další informace. Preprocesor jazyka C zpracuje tyto instrukce a teprve následně probíhá vlastní překlad. Překlad C, Fortranu a Pascalu; Srovnání Pro demostraci předchozích informací a srovnání jednotlivých jazyků ukážeme v tomto odstavci překlad, jednoduché druhy optimalizačních parametrů a měření doby běhu programu paralelně pro stejný algoritmus zapsaný v C, Fortranu a Pascalu.
Jako ukázku jsem napsal dvojitý cyklus 100000x10000 průběhů, který
provádí jednoduché celočíselné operace sčítání, odčítání a násobení,
avšak některé mezivýsledky a finální součet ukládá do reálné proměnné,
pro niž jsem zvolil nejvyšší přesnost v daném jazyce (o které vím).
Nevylučuji, že například fortran disponuje nejakou větší přesností,
než je
#include <stdio.h>
int main (void)
{
int i, j, a[10000];
long double x, y, z, sum=0.0L;
a[0] = 0;
for (i=1;i<=100000;i++)
for (j=1;j<=10000;j++)
{
z = a[0]*10000;
a[j-1] = i*j;
x = i + j;
y = i - j;
sum += a[j-1] + x + y + z;
}
printf ("%Lf\n",sum);
return 0;
}
... jazykem fortran...
integer i, j
integer a(10000)
double precision x, y, z, sum;
sum = 0.0;
a(1) = 0;
loop1: do i = 1,100000
loop2: do j = 1,10000
z = a(1) * 10000
a(j) = i * j
x = i + j
y = i - j
sum = sum + a(j) + x + y + z;
end do loop2
end do loop1
write (*, 100) sum
100 format (f26.6)
end
... a jazykem pascal...
program example (input,output);
var
i, j : longint;
a : array [1..10000] of longint;
x, y, z : double;
sum : double;
begin
sum := 0.0;
a[1] := 0;
for i:=1 to 100000 do
for j:=1 to 10000 do
begin
z := a[1] * 10000;
a[j] := i * j;
x := i + j;
y := i - j;
sum := sum + a[j] + x + y + z;
end;
writeln(sum);
end.
Předcházející zdrojové kódy jsou uloženy v souborech
example.c, example.f, example.pas.
Spustitelné programy vytvoříme pomocí příkazů...
gcc -o example_c -Wall example.c
gcc -o example_c_opt -Wall -O6 -ffast-math -fexpensive-optimizations
-march=pentiumpro -malign-double -fomit-frame-pointer -funroll-loops
-finline-functions -fmove-all-movables example.c
g77 -o example_f -Wall example.f
g77 -o example_f_opt -Wall -O6 -ffast-math -fexpensive-optimizations
-march=pentiumpro -malign-double -fomit-frame-pointer -funroll-loops
-finline-functions -fmove-all-movables example.f
gpc -o example_pas -Wall example.pas
gpc -o example_pas_opt -Wall -O6 -ffast-math -fexpensive-optimizations
-march=pentiumpro -malign-double -fomit-frame-pointer -funroll-loops
-finline-functions -fmove-all-movables example.pas
ppc386 -oexample_pas_ppc example.pas
ppc386 -oexample_pas_ppc_opt -O3 -Op3 example.pas
Pomocí GNU Compiler Collection jsme získali programy
strip example_*Nyní se můžeme podívat na zmíněné délky. -rw-r--r-- 1 nathan users 324 Feb 21 21:04 example.c -rw-r--r-- 1 nathan users 435 Feb 21 21:02 example.f -rw-r--r-- 1 nathan users 383 Feb 21 21:10 example.pas -rwxr-xr-x 1 nathan users 3316 Feb 21 21:52 example_c -rwxr-xr-x 1 nathan users 3428 Feb 21 21:52 example_c_opt -rwxr-xr-x 1 nathan users 30732 Feb 21 21:52 example_f -rwxr-xr-x 1 nathan users 30860 Feb 21 21:52 example_f_opt -rwxr-xr-x 1 nathan users 111448 Feb 21 21:52 example_pas -rwxr-xr-x 1 nathan users 111320 Feb 21 21:52 example_pas_opt -rwxr-xr-x 1 nathan users 34500 Feb 21 21:52 example_pas_ppc -rwxr-xr-x 1 nathan users 34484 Feb 21 21:52 example_pas_ppc_opt Vidíme, že rozdíl v délce mezi programy odpovídající zdrojovým textům v jazyku C a jazyku fortran je řádový. Rozdíl mezi fortranem a pascalem je téměř čtyřnásobný. Jazyk C se tedy v tomto konkrétním srovnání jeví jako (délkově) nejvýhodnější. Obrovskou délku programu přeloženého z textu zapsaného pascalem si vysvětluji tím, že pascal (dle ISO norem) provádí v běžícím programu mnoho kontrol, například kontroly na nepřekročení meze polí a podobně. Tento nadbytečný kód samozřejmě zabírá místo. Navíc nemohu vyloučit různý objem textu přilinkovaného (linkerem) z knihoven. Pro přesný rozbor obsahu, a také rychlosti, jednotlivých programů by bylo nutné si nechat vygenerovat prekladačem také zdrojový text v assembleru. Dodejme pro úplnost, že assembler je jednoduše řečeno symbolický zápis binárního kódu programu, tedy symbolický zápis instrukcí pro procesor počítače. Překladač Free Pascal Compiler generuje kratší (a také rychlejší) programy, než gpc. Vzhledem k tomu, že pascal je po parsování do mezikódu RTL překládán v GNU Compiler Collection stejným způsobem jako C, GNU Compiler Collection je podle testů jedním z nejefektivnějších kompilátorů a dokumentace k Free Pascal Compiler _neuvádí_ kompatibilitu s ISO normou, ale pouze Borland Pascal pseudonormou, usuzuji, že Free Pascal Compiler prostě obchází některé neefektivity pascalu (vyplývající z jeho definice) a to mu umožnuje produkovat kratší a rychlejší programy. Následující sekvence příkazů vypíše jméno programu a následně ho spustí a změří dobu jeho běhu...echo example_c: time ./example_c echo example_c_opt: time ./example_c_opt echo example_f: time ./example_f echo example_f_opt: time ./example_f_opt echo example_pas: time ./example_pas echo example_pas_opt: time ./example_pas_opt echo example_pas_ppc from ppc386: time ./example_pas_ppc echo example_pas_ppc_opt from ppc386: time ./example_pas_ppc_opt Uvedená sekvence vyprodukovala výstup uvedený v prvním sloupci následující tabulky. Další dva sloupce jsou vytvořeny opětovným spuštěním předchozích příkazů. Na UNIXovém serverovém systému mohou totiž z důvodu mnoha démonů a na pozadí běžících aplikací mírně kolísat přidělované systémové zdroje. example_c: example_c: example_c: 750132500250000000.000000 750132500250000000.000000 750132500250000000.000000 real 1m28.711s real 1m28.422s real 1m28.424s user 1m28.460s user 1m28.420s user 1m28.330s sys 0m0.020s sys 0m0.000s sys 0m0.100s example_c_opt: example_c_opt: example_c_opt: 750132500250000000.000000 750132500250000000.000000 750132500250000000.000000 real 0m13.704s real 0m13.693s real 0m13.695s user 0m13.710s user 0m13.690s user 0m13.690s sys 0m0.000s sys 0m0.000s sys 0m0.000s example_f: example_f: example_f: 750132500249889536.000000 750132500249889536.000000 750132500249889536.000000 real 0m53.080s real 0m53.059s real 0m53.070s user 0m53.070s user 0m53.060s user 0m53.070s sys 0m0.010s sys 0m0.000s sys 0m0.000s example_f_opt: example_f_opt: example_f_opt: 750132500249562624.000000 750132500249562624.000000 750132500249562624.000000 real 0m22.764s real 0m22.772s real 0m22.766s user 0m22.760s user 0m22.770s user 0m22.760s sys 0m0.000s sys 0m0.000s sys 0m0.000s example_pas: example_pas: example_pas: 7.501325002498895e+17 7.501325002498895e+17 7.501325002498895e+17 real 2m21.205s real 2m21.228s real 2m21.261s user 2m21.170s user 2m21.230s user 2m21.260s sys 0m0.020s sys 0m0.000s sys 0m0.000s example_pas_opt: example_pas_opt: example_pas_opt: 7.501325002497242e+17 7.501325002497242e+17 7.501325002497242e+17 real 2m4.742s real 2m4.743s real 2m4.746s user 2m4.720s user 2m4.740s user 2m4.730s sys 0m0.020s sys 0m0.000s sys 0m0.020s example_pas_ppc example_pas_ppc example_pas_ppc from ppc386: from ppc386: from ppc386: 7.501325002498895E+017 7.501325002498895E+017 7.501325002498895E+017 real 0m36.737s real 0m36.746s real 0m36.755s user 0m36.740s user 0m36.750s user 0m36.760s sys 0m0.000s sys 0m0.000s sys 0m0.000s example_pas_ppc_opt example_pas_ppc_opt example_pas_ppc_opt from ppc386: from ppc386: from ppc386: 7.501325002498895E+017 7.501325002498895E+017 7.501325002498895E+017 real 0m35.088s real 0m35.104s real 0m35.084s user 0m35.090s user 0m35.100s user 0m35.080s sys 0m0.000s sys 0m0.000s sys 0m0.000s
První zhodnotíme rychlost. Důležité jsou pro nás optimalizované verze programů.
Srovnání neoptimalizavaných verzí hodnotí jednak spíš optimalizační schopnosti
parserů, ale především "nulovou" hladinu prováděných optimalizací,
která může být u různých překladačů různá.
V tomto konkrétním případě vykazuje jazyk C téměř dvakrát větší rychlost
než jazyk fortran a třikrát větší rychlost než jazyk pascal kompilovaný překladačem
Free Pascal Compiler. Jazyk pascal přeložený systémem GNU Compiler Collection je
řádově pomalejší než jazyk C.
Je možné, že fortran bude pro jiný příklad nebo na jiné platformě efektivnější
- buď jako jazyk C, nebo více. To samé lze však stěží říci o jazyku pascal.
Ten je navržen jako výukový vysokoúrovňový jazyk, z principu nevhodný
k numerickým výpočtům.
Dalším zajímavým srovnáním je vlastní výsledek výpočtu. Asi díky vysoké přesnosti
(18 platných cifer, viz soubor
#include <stdio.h>
#include "gmp.h"
int main (void)
{
long int i, j, a[10000];
long int final;
mpz_t sum;
a[0] = 0;
mpz_init (sum);
for (i=1;i<=100000;i++)
for (j=1;j<=10000;j++)
{
final = i*j + 2*i + a[0]*10000;
a[j-1] = i*j;
if (final>=0)
mpz_add_ui (sum, sum, (unsigned long int)final);
if (final<0)
{
final *= -1;
mpz_sub_ui (sum, sum, (unsigned long int)final);
}
}
mpz_out_str (stdout, 10, sum);
printf ("\n");
mpz_clear (sum);
return 0;
}
uložíme do souboru example.gmp.c, přeložíme příkazem
gcc -o example_gmp_opt -Wall -O6 -ffast-math -fexpensive-optimizations
-march=pentiumpro -malign-double -fomit-frame-pointer -funroll-loops
-finline-functions -fmove-all-movables example.gmp.c -lgmp
a spustíme time ./example_gmp_opt
example_gmp_opt: example_gmp_opt: example_gmp_opt: 750132500250000000 750132500250000000 750132500250000000 real 1m12.933s real 1m12.765s real 1m12.764s user 1m12.810s user 1m12.760s user 1m12.760s sys 0m0.020s sys 0m0.010s sys 0m0.010s Pro úplnost dodejme, že všechny prezentované výsledky byly získány na serveru THUNDER. Byl použit systém GNU Compiler Collection verze 2.95.2 (Debian GNU/Linux), a systém Free Pascal Compiler verze 0.99.13. Na jiné hardwarové architektuře nebo pro jiné verze překladačů mohou být výsledky odlišné. To ukážeme pro dvouprocesorový server Alpha 21064 firmy DEC s operačním systémem Digital UNIX V4.0D
bash$ cc -o example_c_opt -O5 example.c
Warning: Type long double has the same representation as type double
on this platform and is treated as a synonym for type double
in this compilation mode.
bash$ time ./example_c_opt
750132500249889540.000000
real 93.4 # asi 1.56 min
user 91.8
sys 0.2
bash$ f90 -o example_f_opt -O5 example.f
bash$ time ./example_f_opt
750132500220702080.000000
real 111.5 # asi 1.86 min
user 109.4
sys 0.2
bash$ f90 -o example_f_opt -O5 -double_size 128 example.f
bash$ time ./example_f_opt
750132500250000000.000000
real 2372.5 # asi 39.5 min
user 2352.2
sys 3.2
a pracovní stanici Apollo 9000/715 firmy HP s operačním systémem HP-UX 10.20
pro typ LONG DOUBLE: cc -o example_c_opt -Ae +O4 example.c time ./example_c_opt 750132500250000000.000000 real 4:36:35.5 # asi 4 a půl hodiny user 4:33:22.2 sys 6.8 pro typ DOUBLE: cc -o example_c_opt -Ae +O4 example.c time ./example_c_opt 750132500249889536.000000 real 3:34.5 # asi 3.5 min user 3:31.2 sys 0.1 pro Fortran a typ DOUBLE PRECISION: f90 -o example_f_opt +O3 +Oall example.f time ./example_f_opt 750132500220702080.000000 real 3:34.3 # asi 3.5 min user 3:31.0 sys 0.1
Z předchozích výsledků usuzuji, že v systému ALPHA
(a podobně APOLLO) chybí hardwarově podporovaný typ
|