Portál AbcLinuxu, 5. května 2025 23:01
/usr/lib/jvm/java-6-sun-1.6.0.07/jre/bin/java: ELF 64-bit LSB executable, x86-64Tak ti nevím...
jo, jo. To je ono. Vyzkouším, zda to s tím pojede. Díky
The following i386 packages will be installed: libcurl3 Installing libraries ... The following i386 packages will be installed: libnss3-1d Installing libraries ... The following i386 packages will be installed: libnspr4-0d Installing libraries ... “Installing Flash Player 10“
64bit Java browser plugin existuje uz pomerne davno a ako prvy sa objavil vo/pre FreeBSD
qemu-i386
a kqemu?
QEMU je úúúúžasně rychléTo je fakt, to už asi radši i ten swfdec nebo gnash, ale jde to a to je hlavní.
a KQEMU je pouze pro x86.Aha.
ale jde to a to je hlavní.Po pravdě řečeno si chůzi představuju jinak, než že v Linuxu na PowerPC budu emulovat i386, na kterém spustím Windows, do kterých si nainstaluji Flash a Operu, ve kterých se budu dívat na web. Jeden snímek videa nebo hry za dvě minuty mě vážně neuspokojuje.
No tak ono se do těch 4GB adresového prostoru počítá jak RAM, tak i paměť grafické karty a podobné věci.Ne tak úplně. Paměť grafické karty (po té změně) a podobné věci se musí vejít do 1GB (virtuálního) adresového prostoru. Společně s tím se tam musí vejít i paměť, kterou jádro spotřebovává samo pro sebe. U 256MB na grafice je to možná v pohodě, ale u 2×512MB ve SLI už zase tak v pohodě není.
Tou obezličkou myslíš PAE?V popisu toho API je to popsáno jako využití horní paměti - tipl bych si, že PAE se přitom používá, ale neručím za to.
Vsadím se, že "potenciální" nárůst výkonu zdaleka nevyrovná čas strávený rozcházením 32bitových aplikací a restartováním firefoxu :)Hmm, u mne je jedinou 32bit aplikaci Skype. A tomu stacilo jen dat potrebne 32bit knihovny a napsat wrapper, co mu pri startu zapne mikrofon a pri ukonceni ho opravdu ukonci.
Swfdec je v pohodě, přehraje téměř všechno a rychlost je jen o něco slabší, než u Flash playeru.Kéž bych s tebou mohl souhlasit. U mě to tvé "jen o něco slabší" znamenalo více než trojnásobné zpomalení (25% vs 87%).
aneb co je horší - když to pojede pomalu nebo když to nepojede vůbec?Sice nevím, jak OSS implementace flashe, ale je celkem běžné, že programy, které se projevují tím, že jsou hrozně pomalé, zároveň žerou šílené systémové zdroje - potom může být lepší, když to nejede vůbec
char *d1, *d2, *d3; //ukazatele na char[KONSTANTA] for (a = 0; a < KONSTANTA;a++) { d3[a] = d1[a] ^ d2[a]; }vs. tohle:
quint64 a, i1, i2, y; //quint64 je neznaménkový 64bitový int char *d1, *d2, *d3; for (a = 0; a < KONSTANTA;) { // KONSTANTA je dělitelná nejméně 8 i1 = *((quint64 *)(d1+a)); i2 = *((quint64 *)(d2+a)); y = i1 ^ i2; *((quint64 *)(d3+a)) = y; a+=sizeof(quint64); }To první vypadá hezky a naprosto jasně je vidět, co to dělá, to druhé vypadá podivně, zběsile se tam přetypovává, je to delší a běží to sedmkrát rychleji, protože místo 8bitového AL se při počítání využije celý 64bitový RAX.
A bude to rychlejší třeba i na 32bitovém DSP?Přelož to pro 32bitový DSP a podívej se sám. Zkoušel jsem to pro 32bit i386, ale nějak se mi to nepodařilo přeložit. I tak bych ale řekl, že to rychlejší bude, pokud bude slušný překladač. XOR nemá žádné přenosy mezi bity, takže zpracovat 64bit slovo znamená zpracovat postupně 2 32bit slova. Furt by to mělo být o něco rychlejší, než brát to po 1 bytu.
Je to opravdu prasárna, protože výsledek optimalizace závisí na typu cílového procesoru.Radši budu provozovat programy, které obsahují takovouhle prasárnu, ale poběží rychle, než abych tu měl pomalé šmejdy, které mají čistý a úhledný kód. V tomto konkrétním případě bych navíc rád viděl cílový procesor, kde ten výsledek optimalizace bude horší, než původní varianta.
Zkuste místo quint64 použít size_t, na 32 bit architektuře by to mělo být lepší než quint64, ale samozřejmě záleží na překladači.Co se týče řídící proměnné toho cyklu, tak tam určitě (při tom testu jsem to přehodil). Pokud jde o ty výpočetní proměnné, tak tam to tak žhavé není.
Pokud vyvíjíte pro amd64, tak ještě rychlejší to uděláte tím, že použijete SSE2, prefetch a sfence, ale to by muselo být opravdu kritické, a to není, že joNení a beztak nevím jak. (Chtělo by to něco jako SSE snadno a rychle)
Další optimalizace by byla přičítat ve smyčce i d1, d2 a d3.Jako takhle?
quint64 a, i1, i2, y; //quint64 je neznaménkový 64bitový int char *d1, *d2, *d3; for (a = 0; a < KONSTANTA;) { // KONSTANTA je dělitelná nejméně 8 i1 = *((quint64 *)(d1)); i2 = *((quint64 *)(d2)); y = i1 ^ i2; *((quint64 *)(d3)) = y; a+=sizeof(quint64); d1+=sizeof(quint64); d2+=sizeof(quint64); d3+=sizeof(quint64); }Je to jedno, vygenerovaný kód je v obou případech stejný:
0x0000000000401310 <checksum+0>: xor %r8d,%r8d 0x0000000000401313 <checksum+3>: nopl 0x0(%rax,%rax,1) 0x0000000000401318 <checksum+8>: mov (%rsi,%r8,1),%rax 0x000000000040131c <checksum+12>: xor (%rdi,%r8,1),%rax 0x0000000000401320 <checksum+16>: mov %rax,(%rdx,%r8,1) 0x0000000000401324 <checksum+20>: add $0x8,%r8 0x0000000000401328 <checksum+24>: cmp $0x1000,%r8 0x000000000040132f <checksum+31>: jne 0x401318 <checksum+8> 0x0000000000401331 <checksum+33>: mov %rcx,%rax 0x0000000000401334 <checksum+36>: retqV obou případech dojde na adresování s offsetem, kde offset je zároveň řídící proměnná.
Chtělo by to něco jako SSE snadno a rychleTo chce zkusit, uvidíte, že na tom nic není
static inline void xor128(void* dest, const void* src) { __m128i t = _mm_loadu_si128(&((__m128i *)src)[0]); _mm_storeu_si128(&((__m128i *)dest)[0], _mm_xor_si128(t)); }Místo _mm_storeu_si128() lze použít lepší instrukce a místo _mm_loadu_si128() taky. Výhoda tohoto zápisu je ta, že vám to poběží jak na 32 bitech, tak na 64 bitech a nebudete mít problém ani s překladačem (gcc, msvc, icc bez problémů). Navíc MSVC při generování kódu pro x64 už neumožňuje asm{}, takže toto je jediná možnost.
Pokud jde o ty výpočetní proměnné, tak tam to tak žhavé neníOno asi hodně záleží na překladači. Pokud se udělá jen XOR, tak by to teoreticky na 32 bit architektuře měl rozložit na 2 instrukce (což je de fakto jemný loop unrolling), ale věřím, že existují překladače, které z toho těch instrukcí udělají víc;)
V obou případech dojde na adresování s offsetem, kde offset je zároveň řídící proměnnáV tom lepším případě by to tak mělo být, ale já jsem si nějak navykl nevěřit překladači, a tyto věci dělám už jen ručně
Něco takového vám udělá 128bitový XOR:Nějak se mi nepodařilo vygooglit, jak zajistit, aby _m128i nebyl pro gcc neexistující typ.
Ono asi hodně záleží na překladači. Pokud se udělá jen XOR, tak by to teoreticky na 32 bit architektuře měl rozložit na 2 instrukce (což je de fakto jemný loop unrolling), ale věřím, že existují překladače, které z toho těch instrukcí udělají víc;)Což byl důvod, proč jsem se pouštěl do disasemblování výsledku...
V tom lepším případě by to tak mělo být, ale já jsem si nějak navykl nevěřit překladači, a tyto věci dělám už jen ručněNo když vidím, co občas překladač je schopen vymyslet, tak se nedivím, u jednočipů to dost často dělám taky tak.
_m128i nebyl pro gcc neexistující typPozor
PozorJasně, špatně jsem to sem opsal. Ve zdrojáku to bylo dobře.je to __m128i (2 podtržítka)
a je potřeba includovat soubor <emmintrin.h>.To jsem hledal. Bohužel jsem hledal v
/usr/include
a ono je to někde v /usr/lib/.../include
, takže jsem nenašel.
Pokud chcete dokumentaci, tak docela dobrá se dá najít na MSDN.Koukám, ten příklad nahoře nešel přeložit a dokumentace na MSDN bylo první, co z Googlu vypadlo, když jsem mu zadal jméno té funkce.
Pokud budete mít problémy, klidně se ozvěte přes PM ať to tu nespamujem :)Nevykat, děkuji
__m128i t1, t2; unsigned int a; for (a = 0; a < BLOCKSIZE/sizeof(__m128i); ) { t1 = _mm_loadu_si128(&((__m128i *)d1)[a]); t2 = _mm_loadu_si128(&((__m128i *)d2)[a]); _mm_storeu_si128(&((__m128i *)d3)[a], _mm_xor_si128(t1, t2)); a += 1; }Funguje, trvá pouze 75% času oproti variantě uvedené výše, tedy zpracování po 64bitech. Hezké, děkuji. (Hm, to, že něco funguje teď, neznamená, že to bude fungovat za všech okolností. Proto se radši ptám, nedělám takhle něco špatně?)
static size_t mymin(size_t a, size_t b) { return a < b ? a : b; } static void xorarray( const uint8_t* d1, const uint8_t* d2, uint8_t* d3, size_t size) { if (!size) return; // sse2 registers __m128i t1, t2; // loop register (ideally ecx/rcx) size_t i; // align to 128 bits if ((size_t)d3 & 15) { i = mymin((size_t)d3 & 15, size); size -= i; do { *d3++ = *d1++ ^ *d2++; } while(--i); } // 128 bits per time for (i = size/16; i; i--, d1 += 16, d2 += 16, d3 += 16) { t1 = _mm_loadu_si128((__m128i *)d1); t2 = _mm_loadu_si128((__m128i *)d2); _mm_stream_si128((__m128i *)d3, _mm_xor_si128(t1, t2)); } // tail < 128 bits for (i = size&15; i; i--) { *d3++ = *d1++ ^ *d2++; } // cleanup from SSE2 code _mm_sfence(); }PS: Napsal jsem to v prohlížeči, takže tam může být nějaká drobnost :) PPS: To vykání je prostě zvyk :)
static size_t mymin(size_t a, size_t b) { return a < b ? a : b; } static void xorarray( const uint8_t* d1, const uint8_t* d2, uint8_t* d3, size_t size) { if (!size) return; // sse2 registers __m128i t1_0; __m128i t2_0; __m128i t1_1; __m128i t2_1; // loop register (ideally ecx/rcx) size_t i; // align to 128 bits if ((size_t)d3 & 15) { i = mymin((size_t)d3 & 15, size); size -= i; do { *d3++ = *d1++ ^ *d2++; } while(--i); } // 512 bits per time for (i = size/64; i; i--, d1 += 64, d2 += 64, d3 += 64) { t1_0 = _mm_loadu_si128((__m128i *)(d1 + 0)); t2_0 = _mm_loadu_si128((__m128i *)(d2 + 0)); t1_1 = _mm_loadu_si128((__m128i *)(d1 + 16)); t2_1 = _mm_loadu_si128((__m128i *)(d2 + 16)); _mm_stream_si128((__m128i *)(d3 + 0 ), _mm_xor_si128(t1_0, t2_0)); _mm_stream_si128((__m128i *)(d3 + 16), _mm_xor_si128(t1_1, t2_1)); t1_0 = _mm_loadu_si128((__m128i *)(d1 + 32)); t2_0 = _mm_loadu_si128((__m128i *)(d2 + 32)); t1_1 = _mm_loadu_si128((__m128i *)(d1 + 48)); t2_1 = _mm_loadu_si128((__m128i *)(d2 + 48)); _mm_stream_si128((__m128i *)(d3 + 32), _mm_xor_si128(t1_0, t2_0)); _mm_stream_si128((__m128i *)(d3 + 48), _mm_xor_si128(t1_1, t2_1)); } // 128 bits per time for (i = (size&63)/16; i; i--, d1 += 16, d2 += 16, d3 += 16) { t1_0 = _mm_loadu_si128((__m128i *)(d1 + 0)); t2_0 = _mm_loadu_si128((__m128i *)(d2 + 0)); _mm_stream_si128((__m128i *)(d3 + 0 ), _mm_xor_si128(t1_0, t2_0)); } // tail < 128 bits for (i = size&15; i; i--) { *d3++ = *d1++ ^ *d2++; } // cleanup from SSE2 code _mm_sfence(); }
Největší zrychlení se ale koná na starších procesorech, které umí jen MMX, popřípadě 3dNow (tam je to zrychlení fakt paráda).Takovej tu jeden mám, ale nepředpokládám, že bych pro něj ještě někdy něco psal.
PS: Ještě mě napadlo toto:To mi funguje pomaleji. Tipuju, že na překladač už je to příliš složité...
Tiskni
Sdílej:
ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.