Avatar
Caster
Člen
Avatar
Caster:11. května 21:16

Z C++ volám funkci v x64 assembleru, kde mám data definována tabulkou:

tabulka                 DD              0, 10000, 20000, 30000, 40000, 50000, 60000, 70000, 80000, 90000
                        DD              0, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000
                        DD              0, 100, 200, 300, 400, 500, 600, 700, 800, 900
                        DD              0, 10, 20, 30, 40, 50, 60, 70, 80, 90
                        DD              0, 1, 2, 3, 4, 5, 6, 7, 8, 9

Pro načtení dat použiji příkaz:

add r10d, tabulka[rax]

Překlad mi ale hlásí chybu:

Error LNK2017 'ADDR32' relocation to 'tabulka' invalid without /LARGEADDRESSA­WARE:NO

Pokud v Linkeru nastavím: Enable Large Addresses na "/LARGEADDRES­SAWARE:NO" tak se chyba neobjeví, ale v hlavním C++ programu mi přestane fungovat alokace virtuální paměti, ptr = 0:

//* Alokujeme pamět pro celý soubor *//
        static const SIZE_T giga = 1024 * 1024 * 1024;
        static const SIZE_T size = 7 * giga;
        BYTE* ptr = static_cast<BYTE*>(VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE));
        if (ptr == nullptr) {
                std::cout << "Chyba při alokaci paměti\n";
                return 1;
        }
        std::cout << "Pamět alokována\n";

Jak upravit ASM kód funkce, aby mi to nehlásilo chybu ? Ve Visual Studiu 2017 mám nastaveno, že pracuji v x64.

 
Odpovědět 11. května 21:16
Avatar
Martin Dráb
Redaktor
Avatar
Odpovídá na Caster
Martin Dráb:11. května 23:45

Můžeš zkusit rozepsat třeba do instrukcí:

lea rcx, [tabulka]
add r10d, [rcx + 4*rax]

Je třeba si ohlídat použití těch správných registrů, abys nepřepsal hodnotu některého. Nebo se podívej, jaké všechny varianty instrukce ADD dovoluje (jestli ta tebou použitá dává rozumný smysl pro tvůj účel).

Co se týče té alokace, nech si v případě chyby vypsat chybové kód (GetLastError). Předpokládám, že máš dostatek virtuální paměti (volné), abys mohl směle alokovat 7 GB.

Nahoru Odpovědět 11. května 23:45
2 + 2 = 5 for extremely large values of 2
Avatar
Caster
Člen
Avatar
Odpovídá na Martin Dráb
Caster:12. května 2:39

Díky, vyřešil jsem to pomocí:

lea rdi, tabulka
add r10d, [rdi+rax]

S pamětí nemám problém, na notebooku mám 24 GB. Zajímám se o záhadu letu MH370 a v tabulce hledám NOAA bóje. V těch 7 GB je cca 50 mil. řádků dat. Převod GPS souřadnic ve tvaru např. 35,167 na integer číslo 35167 (aby se mi pak snadněji hledalo) trvá cca 0,8 sekundy. Načtení dat pomocí funkce ReadFile na 3x (počet byte pro čtení je bohužel jen DWORD) trvá z SSD NVMe M.2 disku (seq. čtení a zápis 1800MB/s) pár sekund.

 
Nahoru Odpovědět 12. května 2:39
Avatar
Martin Dráb
Redaktor
Avatar
Odpovídá na Caster
Martin Dráb:12. května 10:02

Aha, takže Assemblerem se snažíš dosáhnout vyššího výkonu?

Tady bych spíš šel cestou paralelizace (ten převod půjde krásně dělat vícevláknově, neb jsou to na sobě nezávislé úlohy) a asynchronními operacemi (místo ReadFile použít ReadFileEx a začít data zpracovávat ještě během načítání jejich další části).

Případně pokud bys chtěl "načíst" těch 7 GB dat najednou (je to ale spíše taková iluze), tak CreateFileMap­ping, MapViewOfFile.

Nahoru Odpovědět 12. května 10:02
2 + 2 = 5 for extremely large values of 2
Avatar
Caster
Člen
Avatar
Caster:12. května 11:32

Jasně, jde mi o maximální rychlost. Se souborem, jako externím zdrojem dat, pracuji běžně v Excelu pomocí Power Query. Načtení a vyhledání ale trvá několik minut.

Funkce, zmíněné výše, mi ale asi moc nepomohou, neumí najednout načíst více dat než DWORD (32 bit) dat, takže bych je musel také volat opakovaně (3x pro 6 201 216 875 bytů, Funkce ReadFile umí najednou načíst max. 2 501 566 399 bytů).

 
Nahoru Odpovědět 12. května 11:32
Avatar
Martin Dráb
Redaktor
Avatar
Odpovídá na Caster
Martin Dráb:12. května 12:33

Funkce, zmíněné výše, mi ale asi moc nepomohou, neumí najednout načíst více dat než DWORD (32 bit) dat, takže bych je musel také volat opakovaně (3x pro 6 201 216 875 bytů, Funkce ReadFile umí najednou načíst max. 2 501 566 399 bytů).

Jestli se dívám dobře do dokumentaci CreateFileMapping a MapViewOfFile dokáží pracovat dobře i se soubory většími než 4 GB (DWORD). V podstatě ti namapují celý soubor do paměti, takže pak s ním můžeš pracovat stejně, jako bys jej předtím do té paměti načetl manuálně přes ReadFile. Trik je v tom, že vlastní načítání do paměti provádí jádro systému, když o ta data požádáš (přistoupíš na příslušnou paměťovou oblast).

Co se týče ReadFileEx, máš pravdu v tom, že jej pořád budeš muset volat několikrát (limit na ty 2 GB). Myslel jsem to ale tak, že bys postupoval následovně:

  1. načteš 2 GB dat,
  2. zahájíš načítání dalších 2 GB dat, ale nečekáš, až bude dokončeno, jdeš hned do bodu 3),
  3. začneš pracovat s již načtenými daty (třeba převádět ty floaty na integery),
  4. jakmile se dokončí čtení těch 2 GB, goto 2).

Cíl je zaměstnat procesor i v době, kdy načítáš data z disku (a procesor tak nemá co na práci). Samozřejmě je otázka, zda-li to vzhledem k tvé úloze můžeš udělat.

Naprogramovat to správně ale není úplně jednoduché. Mám na těchto asynchronních čteních a zápisech založenou jednu moji utilitu (zatím není na GitHubu) pro práci s disky a ještě tam s tím mám nějaké problémy :-).

Nahoru Odpovědět 12. května 12:33
2 + 2 = 5 for extremely large values of 2
Avatar
Caster
Člen
Avatar
Odpovídá na Martin Dráb
Caster:12. května 12:48

Díky za tipy, podívám se na to. V C++ jsem začal programovat asi před týdnem. Před x lety mě moc bavilo programovat MOS 6502 v Commodore 64, v assembleru jsem dělal grafické funkce ;-).

Je otázkou, zda by paralerní programování věc nějak zásadně urychlilo. Pro hlavní smyčku (50 mil. řádků o délce 125 bytů) používám RCX a instrukci loop. Jako pomocné proměnné používám pouze registry i7-7500u. Z MOS 6502 a kalkulačky HP-41CV (obrácená polská logika) jsem zvyklý psát kód úsporně :-).

 
Nahoru Odpovědět 12. května 12:48
Avatar
Caster
Člen
Avatar
Caster:12. května 13:04

Našel jsem zajímavý článek Mapped Files give very fast access to huge amounts of data

 
Nahoru Odpovědět 12. května 13:04
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 8 zpráv z 8.