Homebrew (Wikipedie), správce balíčků pro macOS a od verze 2.0.0 také pro Linux, byl vydán ve verzi 4.5.0. Na stránce Homebrew Formulae lze procházet seznamem balíčků. K dispozici jsou také různé statistiky.
Byl vydán Mozilla Firefox 138.0. Přehled novinek v poznámkách k vydání a poznámkách k vydání pro vývojáře. Řešeny jsou rovněž bezpečnostní chyby. Nový Firefox 138 je již k dispozici také na Flathubu a Snapcraftu.
Šestnáctý ročník ne-konference jOpenSpace se koná 3. – 5. října 2025 v Hotelu Antoň v Telči. Pro účast je potřeba vyplnit registrační formulář. Ne-konference neznamená, že se organizátorům nechce připravovat program, ale naopak dává prostor všem pozvaným, aby si program sami složili z toho nejzajímavějšího, čím se v poslední době zabývají nebo co je oslovilo. Obsah, který vytvářejí všichni účastníci, se skládá z desetiminutových
… více »Richard Stallman přednáší ve středu 7. května od 16:30 na Technické univerzitě v Liberci o vlivu technologií na svobodu. Přednáška je určená jak odborné tak laické veřejnosti.
Jean-Baptiste Mardelle se v příspěvku na blogu rozepsal o novinkám v nejnovější verzi 25.04.0 editoru videa Kdenlive (Wikipedie). Ke stažení také na Flathubu.
TmuxAI (GitHub) je AI asistent pro práci v terminálu. Vyžaduje účet na OpenRouter.
Byla vydána nová verze R14.1.4 desktopového prostředí Trinity Desktop Environment (TDE, fork KDE 3.5, Wikipedie). Přehled novinek i s náhledy v poznámkách k vydání. Podrobný přehled v Changelogu.
Bylo vydáno OpenBSD 7.7. Opět bez písničky.
V Tiraně proběhl letošní Linux App Summit (LAS) (Mastodon). Zatím nesestříhané videozáznamy přednášek jsou k dispozici na YouTube.
Tímto reaguji na tento zajímavý blogpost. V diskusi zaznělo, že by bylo dobré udělat benchmark. Jenže kdo by ho měl udělat? Tak jsem se nakonec rozhodl, že to zkusím. Myslím si, že následující údaje stojí za přečtení a zamyšlení.
Zajímala mě rychlost fungování různých typů kopírování dat v paměti. Chtěl jsem zjistit, jaký vliv má optimalizace. Nešlo mi o maximální možnou přesnost měření. Spíš jsem chtěl v rozumném čase sestavit a provést jednoduchý a pokud možno zajímavý benchmark.
Všechny testy jsem spouštěl ve stejné situaci, pokud jde o zatížení systému a ostatní procesy. Vypnul jsem náročné aplikace. Během testu jsem se zdržel veškerého uživatelského vstupu. X-server a KDE jsem ponechal v provozu. Zajímal mě standardní výkon v naprosto běžné situaci. Špičkové výkony za uměle nastolených ideálních podmínek jsem netestoval. Frekvenci procesoru jsem po dobu testu pevně nastavil na maximální hodnotu.
Můj výtečný stroj. Je to notebook Asus M2400N. Má procesor Pentium M na 1600 MHz a 512 MB RAM na 266 MHz. Použil jsem nastavení Tickless System (CONFIG_NO_HZ
). Standardní frekvenci časovače mám na 300 Hz. Ještě by mohly být důležité volby CONFIG_PREEMPT=y
a CONFIG_PREEMPT_BKL=y
.
Udělal jsem malý a ošklivý prográmek na testování. Sestává z testovací knihovny, která umí měřit čas, a z vlastní definice testovacích funkcí. Dám sem všechny soubory, aby bylo případně možné je rovnou stáhnout a zkompilovat:
Makefile
#CXX=icpc #CXXFLAGS=-Wall -O3 -xB -pipe #CXXFLAGS=-Wall -O0 #CXX=g++ #CXXFLAGS=-Wall -O3 -march=pentium-m -pipe #CXXFLAGS=-Wall -O0 all: bench.o test.o $(CXX) $(CXXFLAGS) bench.o test.o -o test clean: rm -rf bench.o test.o testZde je tedy jasně vidět, jaké kompilátory a jaké flagy jsem použil pro kompilaci testů.
bench.h
typedef void ( * memcpy_type )( void * target, void * source, size_t bytes ); struct memcpy_test { char * test_name; memcpy_type memcpy_function; }; int test_alloc( size_t size ); void test_free( void ); void test_run( struct memcpy_test * tests, size_t size, unsigned int repeat );Zde je definováno rozhraní a datové typy pro měření času. Funkci
test_run()
se předá pole testů délky size
. Předávaná struktura obsahuje pro každý test jeho název a pointer na funkci provádějící kopírování. Protože z jednoho měření nelze vyvodit závěry, určí se parametrem repeat
počet opakovaných volání funkce, z nichž se pak dělá průměr. Je opakovaně využívána pořád tatáž oblast paměti.
bench.cpp
#include<iostream> #include<iomanip> #include<cstdlib> #include<sys/timeb.h> #include"bench.h" static const char * const DELIMITER = "-------------"; static size_t bytes; static void * source; static void * target; int test_alloc( size_t size ) { source = malloc( size ); target = malloc( size ); bytes = size; return target && source; } void test_free( void ) { free( source ); free( target ); } void test_run( struct memcpy_test * tests, size_t size, unsigned int repeat ) { struct memcpy_test * end; unsigned int elapsed; unsigned int sum; unsigned int i; struct timeb time_before, time_after; end = tests + size; do { sum = 0; std::cout << DELIMITER << std::endl; std::cout << "Running test: " << tests->test_name << std::endl; std::cout << DELIMITER << std::endl; for ( i = 0; i < repeat; ++i ) { ftime( &time_before ); tests->memcpy_function( target, source, bytes ); ftime( &time_after ); elapsed = 1000 * ( time_after.time - time_before.time ); elapsed += time_after.millitm - time_before.millitm; sum += elapsed; std::cout << "Iteration " << i << " time: " << elapsed << std::endl; } puts( DELIMITER ); std::cout.precision( 2 ); std::cout << "Average time: " << std::setprecision( 2 ) << std::fixed << (double) sum / repeat << std::endl; std::cout << DELIMITER << std::endl << std::endl; } while ( ++tests < end ); }Implementace spouštění testovacích funkcí a měření času.
test.cpp
#include<cstring> #include"bench.h" #define func_type( F, T ) (memcpy_type) (void(*)(T*,T*,size_t)) F< T > static size_t MEMSIZE = 100000000u; static void std_memcpy( void * target, void * source, size_t bytes ) { memcpy( target, source, bytes ); } template< typename T > static void pluscpy( T * target, T * source, size_t bytes ) { bytes /= sizeof( T ); while ( bytes-- ) { *( target++ ) = *( source++ ); } } template< typename T > static void endcpy( T * target, T * source, size_t bytes ) { void * end; bytes /= sizeof( T ); end = target + bytes; while ( target != end ) { *( target++ ) = *( source++ ); } } template< typename T > static void spccpy( T * target, T * source, size_t bytes ) { bytes /= sizeof( T ); if ( !bytes ) return; switch ( bytes % 8 ) { case 0: do { *target++ = *source++; case 7: *target++ = *source++; case 6: *target++ = *source++; case 5: *target++ = *source++; case 4: *target++ = *source++; case 3: *target++ = *source++; case 2: *target++ = *source++; case 1: *target++ = *source++; } while ( ( bytes -= 8 ) > 0 ); } } int main( void ) { struct memcpy_test tests[ 10 ]; tests[ 0 ].test_name = "Standard memcpy() test"; tests[ 0 ].memcpy_function = std_memcpy; tests[ 1 ].test_name = "Offset-driven copy test (bytes)"; tests[ 1 ].memcpy_function = func_type( pluscpy, char ); tests[ 2 ].test_name = "Offset-driven copy test (ints)"; tests[ 2 ].memcpy_function = func_type( pluscpy, int ); tests[ 3 ].test_name = "Offset-driven copy test ('long long's)"; tests[ 3 ].memcpy_function = func_type( pluscpy, long long ); tests[ 4 ].test_name = "Pointer-driven copy test (bytes)"; tests[ 4 ].memcpy_function = func_type( endcpy, char ); tests[ 5 ].test_name = "Pointer-driven copy test (ints)"; tests[ 5 ].memcpy_function = func_type( endcpy, int ); tests[ 6 ].test_name = "Pointer-driven copy test ('long long's)"; tests[ 6 ].memcpy_function = func_type( endcpy, long long ); tests[ 7 ].test_name = "Special 'modulo' copy test (bytes)"; tests[ 7 ].memcpy_function = func_type( spccpy, char ); tests[ 8 ].test_name = "Special 'modulo' copy test (ints)"; tests[ 8 ].memcpy_function = func_type( spccpy, int ); tests[ 9 ].test_name = "Special 'modulo' copy test ('long long's)"; tests[ 9 ].memcpy_function = func_type( spccpy, long long ); if ( !test_alloc( MEMSIZE ) ) { return 1; }; test_run( tests, 10, 10 ); test_free(); return 0; }Konkrétní test s konkrétními funkcemi a daty. Pro všechny výsledky uváděné v tomto blogpostu jsem použil právě toto nastavení, tj. 10 druhů testu, 10 opakování každého testu a kopírování 100 MB dat v každém opakování. Záměrně jsem zkoušel k datům přistupovat přes různé datové typy. Ve výsledcích je jasně vidět, že to za jistých okolností hraje roli. Všechny výsledky testů jsou pouze finální zprůměrované hodnoty. Celý výpis z tohoto programu je poměrně dlouhý — kdo ho chce, ať si udělá taky benchmark.
Jak už jsem psal, jde vždy o průměry z deseti po sobě jdoucích měření za výše popsaných podmínek. Všechny údaje jsou v milisekundách. Důležité je, jaký kompilátor byl použit:
g++ -O0
(verze 4.1.2)
g++ -O3 -march=pentium-m
(verze 4.1.2)
icpc -O0
(verze 9.1)
icpc -O3 -xB
(verze 9.1)
g++ (1) | g++ (2) | icpc (3) | icpc (4) | |
std_memcpy() | 97,90 | 96,70 | 97,80 | 64,60 |
pluscpy< char >() | 745,40 | 206,10 | 590,90 | 191,70 |
pluscpy< int >() | 245,20 | 192,20 | 219,40 | 191,40 |
pluscpy< long long >() | 205,10 | 191,80 | 202,20 | 191,60 |
endcpy< char >() | 862,50 | 195,30 | 544,50 | 192,20 |
endcpy< int >() | 243,60 | 191,40 | 211,40 | 191,40 |
endcpy< long long >() | 200,90 | 191,70 | 201,70 | 191,50 |
spccpy< char >() | 716,70 | 194,40 | 533,50 | 198,50 |
spccpy< int >() | 230,80 | 191,40 | 210,90 | 191,60 |
spccpy< long long >() | 201,60 | 191,60 | 198,40 | 192,10 |
Nelze si nevšimnout několika základních faktů. Ne každému se chce podrobně prohlížet celou tabulku, proto bych je tu rád shrnul.
Knihovní funkce memcpy()
prostě rulezzz. Ta nemá konkurenci.
Kompilátor Intel je sice v některých ohledech mírně lepší, ale zázraky dělat neumí. V několika případech dopadl dokonce hůř. Jediná oblast, kde jasně vede, je knihovní funkce memcpy()
. Též se mu výrazně lépe daří při špatném kódu a vypnuté optimalizaci, ale to se nepočítá.
Při vypnuté optimalizaci hraje roli množství najednou adresované paměti. Větší datový typ přenáší data rychleji. Se zapnutou optimalizací už jsou rozdíly minimální. Optimalizace tedy v tomto konkrétním případě zvýšila toleranci vůči některým prasárnám.
Trik se skokem do smyčky sice nepřináší světovou revoluci, ale v některých případech funguje. Mírný rozdíl je patrný při vypnuté optimalizaci. Nicméně v zájmu přehlednosti kódu není rozumné zrovna takto kopírovat pole... Se zapnutou optimalizací toto vylepšení ztrácí smysl a za určitých podmínek přináší i zpomalení.
Kdyby někdo z vás měl trochu času nazbyt a mohl by něco podobného jen tak pro zajímavost vyzkoušet na jiné architektuře, popřípadě s kompilátorem Sun, jistě by to nebylo na škodu. Nebo se můžete pochlubit nějakým hustým strojem, který dosáhne srovnatelných čísel s desetkrát větším kopírovaným blokem. Tak co vy na to?
Snad tento benchmark aspoň aspoň zčásti odpovídá na otázky kolem tohoto blogpostu.
Tiskni
Sdílej:
To sice jo, ale i dávno vyřešené věci někdy neuškodí prodiskutovat znova. Právě proto, že se řešily dávno.
pocitac: IBM p550-v lparu je dedikovan 1 dualcorovy p5+ procesor suse-tftp:/tmp/memtest # cat /proc/cpuinfo processor : 0 cpu : POWER5+ (gs) clock : 1648.350000MHz revision : 3.1 (pvr 003b 0301) processor : 1 cpu : POWER5+ (gs) clock : 1648.350000MHz revision : 3.1 (pvr 003b 0301) timebase : 512365000 machine : CHRP IBM,9133-55A suse-tftp:/tmp/memtest # cat /etc/SuSE-release SUSE Linux Enterprise Server 10 (ppc) VERSION = 10 g++ optimalizace: -Wall -O3 -pipe Average time: 33.70 bez optimalizace: Average time: 160.10
G++ (bez optimalizace) ----------------------- Standard memcpy() Average time: 45.90 Offset-driven copy test (bytes) Average time: 1713.40 Offset-driven copy test (ints) Average time: 583.30 Offset-driven copy test ('long long's) Average time: 218.60 Pointer-driven copy test (bytes) Average time: 1206.90 Pointer-driven copy test (ints) Average time: 265.40 Pointer-driven copy test ('long long's) Average time: 156.60 Special 'modulo' copy test (bytes) Average time: 1791.40 Special 'modulo' copy test (ints) Average time: 390.00 Special 'modulo' copy test ('long long's) Average time: 160.00 G++(-Wall -O3 -pipe) -------------------------- Standard memcpy() test Average time: 46.10 Offset-driven copy test (bytes) Average time: 250.80 Offset-driven copy test (ints) Average time: 128.30 Offset-driven copy test ('long long's) Average time: 39.20 Pointer-driven copy test (bytes) Average time: 252.10 Pointer-driven copy test (ints) Average time: 128.40 Pointer-driven copy test ('long long's) Average time: 39.20 Special 'modulo' copy test (bytes) Average time: 137.30 Special 'modulo' copy test (ints) Average time: 41.60 Special 'modulo' copy test ('long long's) Average time: 33.60
Je pro mě příjemným překvapením, že ta moje slátanina šla vůbec zkompilovat a spustit na jiné architektuře. Každopádně děkuji za velmi zajímavý výsledek. Knihovní memcpy je u Vás asi napsaná komplet v assembleru, když jí optimalizace škodí...
Pointer-driven copy test (ints) Average time: 128.40 Pointer-driven copy test ('long long's) Average time: 39.20
Promiňte mi hloupou otázku: Ten stroj je 64-bitový? Jinak si neumím vysvětlit tak velký nárůst rychlosti při použití long long...
G++ (bez optimalizace) ----------------------- Standard memcpy() Average time: 271.10 Offset-driven copy test (bytes) Average time: 867.70 Offset-driven copy test (ints) Average time: 262.10 Offset-driven copy test ('long long's) Average time: 180.90 Pointer-driven copy test (bytes) Average time: 814.60 Pointer-driven copy test (ints) Average time: 251.10 Pointer-driven copy test ('long long's) Average time: 182.20 Special 'modulo' copy test (bytes) Average time: 779.50 Special 'modulo' copy test (ints) Average time: 243.90 Special 'modulo' copy test ('long long's) Average time: 174.20
G++ (-O2 -march=athlon-xp -pipe -mcpu=i686 -fomit-frame-pointer -msse -mmmx -m3dnow -ffast-math -fprefetch-loop-arrays -finline-limit=600 -ftracer) ----------------------- Standard memcpy() Average time: 244.90 Offset-driven copy test (bytes) Average time: 998.20 Offset-driven copy test (ints) Average time: 287.40 Offset-driven copy test ('long long's) Average time: 198.60 Pointer-driven copy test (bytes) Average time: 896.50 Pointer-driven copy test (ints) Average time: 267.60 Pointer-driven copy test ('long long's) Average time: 190.10 Special 'modulo' copy test (bytes) Average time: 814.00 Special 'modulo' copy test (ints) Average time: 258.40 Special 'modulo' copy test ('long long's) Average time: 183.40
Překvapivé. U Vás není vítězem memcpy(). Jak je to možné?
To je divné. Týká se to dokonce i 32-bitových Athlonů, jak je vidět o kus níž. Jestli se používá často memcpy i v kernelu...
[andrej@xandrej linux]$ grep -R memcpy * | wc -l 9318
...tak to je potom smutné. Takže procesory AMD asi nejsou využité tak dobře, jak by mohly být.
Tak to abychom udělali vlastní fork kernelu :)
A ten by spočíval v rekurzivním průchodu stromem a nahrazení všech memcpy()
něčím jiným.
Zjistil jsem, že kernelu se případný problém netýká. Má totiž vlastní implementaci knihoven pro každou architekturu zvlášť. Kompilují se různé jejich části podle toho, jaké možnosti má cílový procesor. Je to k vidění například zde:
[andrej@popelnice linux]$ ls arch/i386/lib/mem* arch/i386/lib/memcpy.c [andrej@popelnice linux]$ ls arch/x86_64/lib/mem* arch/x86_64/lib/memcpy.S arch/x86_64/lib/memmove.c arch/x86_64/lib/memset.S
Používají se tam i poměrně nové sady instrukcí, takže uživatel může být klidný, že strhujícím výkonem jeho stroje nikdo neplýtvá
Je tu už i měření Michala Kubečka, kde memcpy()
na AMD s drtivou převahou vítězí.
1.-O0 2.-Os -march=athlon64 -msse3 -pipe 3.-O3 -march=athlon64 -msse3 -pipe 4.-O3 -march=athlon64 -mtune=athlon64 -msse3 -pipe -falign-functions=4 -fprefetch-loop-arrays -fomit-frame-pointer 1 2 3 4 Standard memcpy() test 192.80 150.60 56.30 54.90 Offset-driven copy test (bytes) 755.40 257.70 206.80 224.60 Offset-driven copy test (ints) 222.70 108.80 94.20 73.40 Offset-driven copy test ('long long's) 132.50 88.30 71.40 70.30 Pointer-driven copy test (bytes) 707.80 207.20 204.30 224.60 Pointer-driven copy test (ints) 213.30 96.00 97.80 68.30 Pointer-driven copy test ('long long's) 128.30 76.20 73.20 66.40 Special 'modulo' copy test (bytes) 671.00 141.70 146.30 146.10 Special 'modulo' copy test (ints) 206.20 87.40 83.90 83.60 Special 'modulo' copy test ('long long's) 124.80 75.00 71.50 70.80
Těch 10 běhů je asi málo.
Taky se tu nesnažíme o nějakou velkou přesnost. Funkce
test_run()
má parametr repeat
, kterým lze počet běhů nastavit. Taky jsem musel vypnout ondemand.
Překvapuje mě, že na AMD64 není memcpy()
vítězem. Není tam náhodou 32-bitový kernel nebo alespoň 32-bitové knihovny? To by bylo jediné možné vysvětlení, proč může být tento kód rychlejší než memcpy()
.
ldd test libstdc++.so.6 => /usr/lib/gcc/x86_64-pc-linux-gnu /4.1.2/libstdc++.so.6 (0x00002b3c41d78000) libm.so.6 => /lib/libm.so.6 (0x00002b3c41f76000) libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00002b3c420cb000) libc.so.6 => /lib/libc.so.6 (0x00002b3c421d9000) /lib64/ld-linux-x86-64.so.2 (0x00002b3c41c5b000)
1.-O0 2.-O2 -march=athlon-xp -pipe -fomit-frame-pointer -msse -mmmx -m3dnow -ffast-math -fprefetch-loop-arrays -finline-limit=600 -ftracer 3.-Os -march=athlon-xp -pipe 4.-O3 -march=athlon-xp -pipe 1 2 3 4 Standard memcpy() test 220.70 163.90 169.10 164.10 Offset-driven copy test (bytes) 964.70 319.50 288.20 266.60 Offset-driven copy test (ints) 288.20 127.00 174.90 185.40 Offset-driven copy test ('long long's) 218.90 145.70 144.00 145.70 Pointer-driven copy test (bytes) 915.90 286.50 296.90 266.50 Pointer-driven copy test (ints) 274.60 133.60 176.40 165.60 Pointer-driven copy test ('long long's) 217.70 145.20 163.90 145.00 Special 'modulo' copy test (bytes) 868.50 242.10 226.70 227.40 Special 'modulo' copy test (ints) 258.00 163.60 164.40 156.60 Special 'modulo' copy test ('long long's) 218.70 144.30 143.00 144.30
Ale tohle je 32-bitový stroj, že jo? Takže to s tím memcpy()
je fakt záhada. Připadá mi, jako by tvůrci knihoven věnovali víc pozornosti Intelu na úkor AMD. Ani v jednom případě není memcpy()
vítězem. To je do očí bijící rozdíl. V procesorech AMD se skrývá nějaký tajemný nevyužitý potenciál.
CXXFLAGS='-march=k8 -m64 -O3 -fomit-frame-pointer'
) je na Athlon64 3500+ memcpy()
zřetelně nejrychlejší (kolem 40), pak následují všechny verze používající typ long long
(77-78).
Nejspíš má tedy problém jen některá verze na některých strojích. Nechtělo se mi věřit, že by byla opravdu memcpy()
obecně pro AMD pomalá. Už přece musely proběhnout tisíce benchmarků, mnohem podrobnějších a přesnějších než ten můj. (A kdyby se na něco takového přišlo, bylo by to už před lety v knihovnách opraveno.) I tak jsou výsledky zajímavé.
Hádejte, kdy ten můj benchmark hodí segmentation fault!
Stane se to tehdy, když uděláte na Intelu spccpy< long double >()
. Napřed se mi to zdálo podivné, ale počítač má vždycky pravdu:
Jest totiž sizeof( long double ) == 12
. (Pentium M, Linux, GCC) Dále jest MEMSIZE / 12 == 8333333
, což zjevně není násobkem osmi. Proto v tom while cyklu podteče proměnná bytes
do velkých čísel. Je totiž bezznaménková.
Jsou dvě možnosti řešení:
Nastavit si MEMSIZE = 120000000u
. Pak bude MEMSIZE / 12
násobkem 8
.
Nikdy nepoužívat unsigned proměnnou jako řídící proměnnou cyklu. Tuto poučku jsem stokrát slyšel, stokrát porušil a stokrát jsem si nabil nos.
Blogpost raději ponechávám v původní podobě, protože většina lidí nebude chtít testovat dvanáctibytové datové typy. Navíc bych tím znehodnotil výsledky, které mi tu už někteří z vás ochotně napsali.
Testoval jsem důkladně rychlost kopírování v plovoucí rádové čárce. Zdá se mi, že na procesorech Intel v tom vůbec není rozdíl. Jediné, co hraje roli, je velikost proměnné. Procesory Intel totiž mají univerzální registry pro různé typy dat. Možná by ale na jiném procesoru byla situace jiná. S upraveným MEMSIZE mám takovouhle funkci main():
int main( void ) { struct memcpy_test tests[ 19 ]; tests[ 0 ].test_name = "Standard memcpy() test"; tests[ 0 ].memcpy_function = std_memcpy; tests[ 1 ].test_name = "Offset-driven copy test (bytes)"; tests[ 1 ].memcpy_function = func_type( pluscpy, char ); tests[ 2 ].test_name = "Offset-driven copy test (ints)"; tests[ 2 ].memcpy_function = func_type( pluscpy, int ); tests[ 3 ].test_name = "Offset-driven copy test ('long long's)"; tests[ 3 ].memcpy_function = func_type( pluscpy, long long ); tests[ 4 ].test_name = "Pointer-driven copy test (bytes)"; tests[ 4 ].memcpy_function = func_type( endcpy, char ); tests[ 5 ].test_name = "Pointer-driven copy test (ints)"; tests[ 5 ].memcpy_function = func_type( endcpy, int ); tests[ 6 ].test_name = "Pointer-driven copy test ('long long's)"; tests[ 6 ].memcpy_function = func_type( endcpy, long long ); tests[ 7 ].test_name = "Special 'modulo' copy test (bytes)"; tests[ 7 ].memcpy_function = func_type( spccpy, char ); tests[ 8 ].test_name = "Special 'modulo' copy test (ints)"; tests[ 8 ].memcpy_function = func_type( spccpy, int ); tests[ 9 ].test_name = "Special 'modulo' copy test ('long long's)"; tests[ 9 ].memcpy_function = func_type( spccpy, long long ); tests[ 10 ].test_name = "Offset-driven copy test (floats)"; tests[ 10 ].memcpy_function = func_type( pluscpy, float ); tests[ 11 ].test_name = "Offset-driven copy test (doubles)"; tests[ 11 ].memcpy_function = func_type( pluscpy, double ); tests[ 12 ].test_name = "Offset-driven copy test ('long double's)"; tests[ 12 ].memcpy_function = func_type( pluscpy, long double ); tests[ 13 ].test_name = "Pointer-driven copy test (floats)"; tests[ 13 ].memcpy_function = func_type( endcpy, float ); tests[ 14 ].test_name = "Pointer-driven copy test (doubles)"; tests[ 14 ].memcpy_function = func_type( endcpy, double ); tests[ 15 ].test_name = "Pointer-driven copy test ('long double's)"; tests[ 15 ].memcpy_function = func_type( endcpy, long double ); tests[ 16 ].test_name = "Special 'modulo' copy test (floats)"; tests[ 16 ].memcpy_function = func_type( spccpy, float ); tests[ 17 ].test_name = "Special 'modulo' copy test (doubles)"; tests[ 17 ].memcpy_function = func_type( spccpy, double ); tests[ 18 ].test_name = "Special 'modulo' copy test ('long doubles's)"; tests[ 18 ].memcpy_function = func_type( spccpy, long double ); if ( !test_alloc( MEMSIZE ) ) { return 1; }; test_run( tests, 19, 10 ); test_free(); return 0; }
Nemyslím si, že požívat unsigned
proměnnou v řídící části cyklu je hřích. Naopak, ve chvíli, kdy přičítáte, my přijde jako velice vhodné přičítat do unsigned
. Při odčítání je to ale jiná káva.
Linux album 2.6.21-gentoo-r2 #1 PREEMPT Fri May 25 11:39:18 CEST 2007 i686 AMD Duron(tm) processor AuthenticAMD GNU/Linux gcc (GCC) 4.1.2 (Gentoo 4.1.2) 1. g++ -Wall -O0 2. g++ -Wall -march=athlon-tbird -O3 -pipe -fomit-frame-pointer 1. 2. Standard memcpy() test 660.30 386.80 Offset-driven copy test (bytes) 1882.60 736.00 Offset-driven copy test (ints) 688.90 377.30 Offset-driven copy test ('long long's) 671.00 352.60 Pointer-driven copy test (bytes) 1849.40 734.00 Pointer-driven copy test (ints) 795.90 378.70 Pointer-driven copy test ('long long's) 637.10 365.00 Special 'modulo' copy test (bytes) 1790.80 698.80 Special 'modulo' copy test (ints) 795.10 366.40 Special 'modulo' copy test ('long long's) 667.40 363.50Není to tak zřetelné, ale memcpy také propadá.