Pekelný assembler – C / C++ – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Pekelný assembler – C / C++ – Fórum – Programujte.comPekelný assembler – C / C++ – Fórum – Programujte.com

 

Sefiros0
Návštěvník
19. 10. 2013   #1
-
0
-

Nazdar,

moh by mi někdo vysvětlit proč proboha není rychlejší specializovaná instrukce X86 procesoru (movs) na přesunutí řetězce bajtů než její opis pomocí cyklu a prostého přesunutí jednotlivých prvků pomocí instrukce mov? Opravdu to nechápu ... Když je to specializovaná instrukce, tak snad by měla bejt rychlejší ne ... Asi ne. Dole zmiňuji kód na kterém jsem měřil rychlost.

#include <iostream>

int main()
{
    using namespace std;
    int one[5] = {10,20,30,40,50};
    int two[5] = {0};
    for (register int i=0;i<1000000000;++i)
    {
        /*for (register int i=0;i<5;++i)
        {
            two[i] = one[i];
        }*/
        asm(
            ".intel_syntax noprefix;"
            "mov rsi , %0;"
            "mov rdi , %1;"
            "mov rcx , 5;"
            "rep movsd;"
            ".att_syntax noprefix;"
            :
            : "r"(one), "r"(two)
            : "rcx","rsi","rdi"
        );
    }
    for (int i=0;i<5;++i)
        cout << one[i] << " ,";
    cout << endl;
    for (int i=0;i<5;++i)
        cout << two[i] << " ,";
    return 0;
}
// ASM -> 8,722 s
// Cyklus ->10,399 s
// Cyklus s register counterem --> 5,022 s !!! WHY !!!

Zde je kód v ASM funkce main s cyklem :

0x4009c0	push   rbp
0x4009c1	mov    rbp,rsp
0x4009c4	push   r12
0x4009c6	push   rbx
0x4009c7	sub    rsp,0x40
0x4009cb	mov    DWORD PTR [rbp-0x30],0xa
0x4009d2	mov    DWORD PTR [rbp-0x2c],0x14
0x4009d9	mov    DWORD PTR [rbp-0x28],0x1e
0x4009e0	mov    DWORD PTR [rbp-0x24],0x28
0x4009e7	mov    DWORD PTR [rbp-0x20],0x32
0x4009ee	mov    QWORD PTR [rbp-0x50],0x0
0x4009f6	mov    QWORD PTR [rbp-0x48],0x0
0x4009fe	mov    DWORD PTR [rbp-0x40],0x0
0x400a05	mov    r12d,0x0
0x400a0b	jmp    0x400a2e <main()+110>
0x400a0d	mov    ebx,0x0
0x400a12	jmp    0x400a25 <main()+101>
0x400a14	movsxd rax,ebx
0x400a17	mov    edx,DWORD PTR [rbp+rax*4-0x30]
0x400a1b	movsxd rax,ebx
0x400a1e	mov    DWORD PTR [rbp+rax*4-0x50],edx
0x400a22	add    ebx,0x1
0x400a25	cmp    ebx,0x4
0x400a28	jle    0x400a14 <main()+84>
0x400a2a	add    r12d,0x1
0x400a2e	cmp    r12d,0x3b9ac9ff
0x400a35	jle    0x400a0d <main()+77>
0x400a37	mov    DWORD PTR [rbp-0x14],0x0
0x400a3e	jmp    0x400a66 <main()+166>
0x400a40	mov    eax,DWORD PTR [rbp-0x14]
0x400a43	cdqe
0x400a45	mov    eax,DWORD PTR [rbp+rax*4-0x30]
0x400a49	mov    esi,eax
0x400a4b	mov    edi,0x601080
0x400a50	call   0x400820 <_ZNSolsEi@plt>
0x400a55	mov    esi,0x400bb1
0x400a5a	mov    rdi,rax
0x400a5d	call   0x400880 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x400a62	add    DWORD PTR [rbp-0x14],0x1
0x400a66	cmp    DWORD PTR [rbp-0x14],0x4
0x400a6a	jle    0x400a40 <main()+128>
0x400a6c	mov    esi,0x4008a0
0x400a71	mov    edi,0x601080
0x400a76	call   0x400890 <_ZNSolsEPFRSoS_E@plt>
0x400a7b	mov    DWORD PTR [rbp-0x18],0x0
0x400a82	jmp    0x400aaa <main()+234>
0x400a84	mov    eax,DWORD PTR [rbp-0x18]
0x400a87	cdqe
0x400a89	mov    eax,DWORD PTR [rbp+rax*4-0x50]
0x400a8d	mov    esi,eax
0x400a8f	mov    edi,0x601080
0x400a94	call   0x400820 <_ZNSolsEi@plt>
0x400a99	mov    esi,0x400bb1
0x400a9e	mov    rdi,rax
0x400aa1	call   0x400880 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x400aa6	add    DWORD PTR [rbp-0x18],0x1
0x400aaa	cmp    DWORD PTR [rbp-0x18],0x4
0x400aae	jle    0x400a84 <main()+196>
0x400ab0	mov    eax,0x0
0x400ab5	jmp    0x400abf <main()+255>
0x400ab7	mov    rdi,rax
0x400aba	call   0x4008c0 <_Unwind_Resume@plt>
0x400abf	add    rsp,0x40
0x400ac3	pop    rbx
0x400ac4	pop    r12
0x400ac6	pop    rbp
0x400ac7	ret

Zde je ASM kód funkce main s mnou vložením řešením pomocí specializované instrukce :

0x4009c0	push   rbp
0x4009c1	mov    rbp,rsp
0x4009c4	push   rbx
0x4009c5	sub    rsp,0x48
0x4009c9	mov    DWORD PTR [rbp-0x30],0xa
0x4009d0	mov    DWORD PTR [rbp-0x2c],0x14
0x4009d7	mov    DWORD PTR [rbp-0x28],0x1e
0x4009de	mov    DWORD PTR [rbp-0x24],0x28
0x4009e5	mov    DWORD PTR [rbp-0x20],0x32
0x4009ec	mov    QWORD PTR [rbp-0x50],0x0
0x4009f4	mov    QWORD PTR [rbp-0x48],0x0
0x4009fc	mov    DWORD PTR [rbp-0x40],0x0
0x400a03	mov    ebx,0x0
0x400a08	jmp    0x400a24 <main()+100>
0x400a0a	lea    rax,[rbp-0x30]
0x400a0e	lea    rdx,[rbp-0x50]
0x400a12	mov    rsi,rax
0x400a15	mov    rdi,rdx
0x400a18	mov    rcx,0x5
0x400a1f	rep movs DWORD PTR es:[rdi],DWORD PTR ds:[rsi]
0x400a21	add    ebx,0x1
0x400a24	cmp    ebx,0x3b9ac9ff
0x400a2a	jle    0x400a0a <main()+74>
0x400a2c	mov    DWORD PTR [rbp-0x14],0x0
0x400a33	jmp    0x400a5b <main()+155>
0x400a35	mov    eax,DWORD PTR [rbp-0x14]
0x400a38	cdqe
0x400a3a	mov    eax,DWORD PTR [rbp+rax*4-0x30]
0x400a3e	mov    esi,eax
0x400a40	mov    edi,0x601080
0x400a45	call   0x400820 <_ZNSolsEi@plt>
0x400a4a	mov    esi,0x400ba1
0x400a4f	mov    rdi,rax
0x400a52	call   0x400880 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x400a57	add    DWORD PTR [rbp-0x14],0x1
0x400a5b	cmp    DWORD PTR [rbp-0x14],0x4
0x400a5f	jle    0x400a35 <main()+117>
0x400a61	mov    esi,0x4008a0
0x400a66	mov    edi,0x601080
0x400a6b	call   0x400890 <_ZNSolsEPFRSoS_E@plt>
0x400a70	mov    DWORD PTR [rbp-0x18],0x0
0x400a77	jmp    0x400a9f <main()+223>
0x400a79	mov    eax,DWORD PTR [rbp-0x18]
0x400a7c	cdqe
0x400a7e	mov    eax,DWORD PTR [rbp+rax*4-0x50]
0x400a82	mov    esi,eax
0x400a84	mov    edi,0x601080
0x400a89	call   0x400820 <_ZNSolsEi@plt>
0x400a8e	mov    esi,0x400ba1
0x400a93	mov    rdi,rax
0x400a96	call   0x400880 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
0x400a9b	add    DWORD PTR [rbp-0x18],0x1
0x400a9f	cmp    DWORD PTR [rbp-0x18],0x4
0x400aa3	jle    0x400a79 <main()+185>
0x400aa5	mov    eax,0x0
0x400aaa	jmp    0x400ab4 <main()+244>
0x400aac	mov    rdi,rax
0x400aaf	call   0x4008c0 <_Unwind_Resume@plt>
0x400ab4	add    rsp,0x48
0x400ab8	pop    rbx
0x400ab9	pop    rbp
0x400aba	ret

Měření efektivity bylo prováděno bez závěrečného vypsání obou polí.

Nahlásit jako SPAM
IP: 80.188.252.–
Ovrscout
~ Anonymní uživatel
113 příspěvků
22. 10. 2013   #2
-
0
-

#1 Sefiros

Nejsem extra odborník ale vidím to takto:

Krátká odpověď:

rep movs bude tím efektivnější čím více toho bude kopírovat. Pokud snížíte počet průchodů prvního cyklu a zvětšíte počet kopírovaných položek (například tisíckrát nebo milionkrát) měl by být čas s for cykly delší a s rep movs kratší.

Dlouhá odpověď:

Program s for cykly má všechnu režiji(z obou cyklů) strčenou ještě před začátek prvního cyklu.
Do registrů se načtou adresy polí a počty opakování. V samotných cyklech se už jen projíždí cykly a kopíruje paměť. žádné zbytečné operace. Sice se určuje adresa přístupu do paměti při čtení i zápisu ale je to v rámci instrukce přístupu do paměti, takže si stím procesor zřejmně poradí rychle.
Díky tomu že je kód malý a vejde se do chashe procesoru a díky dalším vlastnostem proseoru(jako předvídání skoků atp)  tak může program proběhnout rychle.

V druhém případě je pak v každém průchodu prvního cyklu prováděna kompletní inicializace pro druhý cyklus. To jest: Výpočet adres (2*LEA + 2*MOV) aby se pak spustila optimalizovaná verze for cyklu(rep movs)

rep movs totiž není nic jiného než provádění cyklu, jen to není napsáno v několika instrukcích, takže procesor ušetří čas s jejich dekódováním. Všechny ty inkrementace adres ,dekremantace počítadel, porovnání na konec cyklu a kopírování paměti se ale tak jako tak provádějí.
Nastavení výchozí stavu cyklu ale několik instrukcí stojí. Ten počet instrukcí je víceméně pevný a při několika stovkách nabo ticíci průchodeh je proti ušetřenému času zanedbatelný. Pokud ale použijete tuto funkci(rep movs) pro (v extrémním případě) zkopírování jednoho bajtu bude režije pro inicializaci větší než co uspoříte.
Je to podobné jako mít for cyklus pro kopírování (v extrémním případě) jednoprvkového pole.
Jednoduché přiřazení bude prostě rychlejší.

Bylo by zajímavé znát čas zpracování pokud by se podařilo přesunout lea instrukce před první cyklus.
Možná pomohlo zapnout nějakou drastickou optimalizaci, která by to mohla zvládnout, ale asi by se musel celý cyklus přepsat do asm.

Nahlásit jako SPAM
IP: 193.165.79.–
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 39 hostů

Podobná vlákna

Assembler — založil Michal21

Assembler 86 — založil dDesmondD

C++ vs Assembler — založil Dodo

ASSEMBLER — založil JONNY

Assembler pomoc — založil pontiac

Moderátoři diskuze

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý