Losowe odczyty vs losowe zapisy

0

Praktycznie zawsze uważałem, że losowe odczyty powinny być szybsze od losowych zapisów. Myślałem, że zawsze jeżeli chcę zapisać sobie jakąś wartość do RAMu to procesor najpierw musi załadować linię pamięci systemowej do pamięci podręcznej (linia to dzisiaj ok 64 bajty), podmienić stosowny bajt (czy słowo) i zapisać tą linię z powrotem do pamięci. Niestety (a może stety) okazało się, że na moim systemie (tzn oprogramowanie + sprzęt) losowe zapisy są dużo szybsze.

Programik do testowania jest tutaj: https://ideone.com/6Ddrx (WAŻNE: dodałem Mersenne Twister, poprzednie wersje używały rand(), który się do niczego nie nadaje)

Wobec tego mam małą prośbę - abyście odpalili programik, który tu zamieściłem, oraz podali wyniki, wraz z opisem CPU, RAM, systemu operacyjnego i kompilatora. Najlepiej odpalcie kilka razy i podajcie najbardziej reprezentatywne wyniki (te najbardziej powtarzalne na przykład).

Mój wynik to:

1000000
700000
787058355
3450000
-59746632
4910000

A system to:
CPU: Intel Core 2 E8400, 3.00 GHz
RAM: 8 GiB, DDR2 800 MHz, CL5, dual-channel
OS: Ubuntu 10.10 64-bit
Kompilator: GCC 4.4.4, 64-bitowa binarka wyjściowa, opcje kompilacji: -O3

Jak widać stosunek prędkości losowych zapisów do prędkości losowych odczytów jest inny niż ten na systemie wykorzystywanym przez ideone.com. Interesuje mnie jaki jest stosunek tych prędkości na różnych systemach.

Aktualizacja - wyniki na netbooku:
CPU: AMD Zacate E-350, 1.60 GHz
RAM: 4 GiB, DDR3 1066 MHz, single-channel
OS: Ubuntu 11.04 64-bit
Kompilator: GCC 4.5.2, 64-bitowa binarka wyjściowa, opcje kompilacji: -O3

1000000
2060000
787058355
20500000
-59746632
20690000
1
1000
1663
7766
1280
-24992072
1195

Intel Mobile Core 2 Duo P8700 2.53GHz
4 GiB, DDR2 800 MHz, CL6
Windows 7
wszystko co domyślne dla kompilatora w Visual Studio 2010 (/O2 /Oi /Ot /Oy- /GL)

1000
881
7766
892
-24992072
849

j/w
mingw 4.5.2 (/O3)

1000000
1063831
1702753913
2583970
-24723530
4003232

j/w
zwirtualizowany Mac OS X
gcc 4.2.1

nowa wersja:

1000
863
514176199
5486
-60018248
6186

vs2010

1000
922
514176199
5541
-60018248
8049

mingw

1

VS2010

1000
1215
7766
1168
-24992072
1134

Win7 64bit, E8400, 4GB RAM DDR2 1066MHz

G++, 4.5.1, -O3 -Wall

1000000
1580000
878354242
10960000
-24972470
10060000

OpenSUSE 11.X 32bit, Athlon [email protected], 1GB DDR2 667MHz

------- Mersenne Twister. Powtórzony pierwszy pomiar --------
main.cpp(127): warning C4244: '=' : conversion from 'unsigned long' to 'char', possible loss of data

1000
727
514176199
3891
-60018248
4617

CLOCKS_PER_SEC pod visualem raczej na niewiele się zda:

time.h z VS2010 napisał(a)
/* Clock ticks macro - ANSI version */
#define CLOCKS_PER_SEC  1000

Trzeba pewnie użyć WinApi i *PerformanceCounter*

0

OK. Chyba już wiem co jest źle w moim programie. Na Windowsie rand() generuje liczby 15-bitowe, a nie 32-bitowe i dlatego wyniki są takie zbliżone do siebie (wszystko ląduje w cache, więc nie ma się co dziwić, że jest szybciej). Postaram się to jakoś szybko naprawić.

Naprawiłem program. Teraz wyniki są nieco inne. Jeżeli potestujecie to napiszcie czy jest to wersja z Mesenne Twister (nowa) czy ta z rand() (stara).

0

Stworzyłem kolejną wersję programu. Tym razem dodałem prefetching. Uwaga: kompiluje się tylko pod GCC (ze względu na tą dodatkową instrukcję do prefetchingu). Dodatkowo, prefetching jest dostępny tylko na niestarych prockach, np na Pentiumach I chyba tego nie ma, więc jak kompilujecie, to co najmniej pod Pentium 3 (najlepiej pod własnego procka).

Kod źródłowy jest tutaj: http://pastebin.com/yM3DsrLN

Wyniki u mnie na desktopie (tym razem pod NetBeansem 6.9, profil Release):

CLOCKS_PER_SEC: 1000000
Linear write time: 790000
Random write time: 3570000
Random read time:  5380000, control value: -59606515
Random read time:  2170000, control value: -59606515, prefetch queue size: 8

RUN SUCCESSFUL (total time: 12s)

Wyniki z netbooka (NetBeans 7.0, profil Release):

CLOCKS_PER_SEC: 1000000
Linear write time: 2000000
Random write time: 21160000
Random read time:  21560000, control value: -59606515
Random read time:  10420000, control value: -59606515, prefetch queue size: 8

RUN SUCCESSFUL (total time: 55s)
0

Ostatnio wrzucony kod:

CLOCKS_PER_SEC: 1000000
Linear write time: 2800000
Random write time: 6070000
Random read time:  8530000, control value: -59606515
Random read time:  4110000, control value: -59606515, prefetch queue size: 8

Kernel 2.6.38-ARCH
Intel Core Duo2 P8400 @ 2.26 GHz
3GB RAM
gcc version 4.6.0 20110429 (prerelease)

1 użytkowników online, w tym zalogowanych: 0, gości: 1