Hej
Przygotowałem wersję programu do przeszukiwania drzewa gry w szachach. Zadaniem
program jest zliczenie ile jest liści w pełnym drzewku na określoną głębokość Program
został wyposażony w 4 różne algorytmy. Piąta wersja będzie zoptymalizowana, szósta
wersja będzie na BOINC - ale to pod warunkiem że ktoś baaaaardzo mi pomoże
przedrzeć się przez konfigurację.
Program można uruchomić tak po prostu i sprawdzić ile jest węzłów w drzewku - to
pierwszy algorytm.
Drugi algorytm umożliwia wykorzystanie ogromnej pamięci - można zobaczyć
jakie uzyskuje się dzięki temu przyspieszenie.
Trzeci algorytm uruchamia się w wątkach - ilość wątków podaje się jako parametr.
Czwarty algorytm nie dość że uruchamia się w wątkach, to jeszcze umie wykorzystać
ogromną ilość pamięci.
Program przez długi czas będzie w wersji tylko na linux64 bity, potem może będzie
na inne systemy. W początkowym okresie będzie udostępniany tylko w wersji
binarnej, za dłuższy czas udostępnię także źródła.
Do wątków została użyta biblioteka boost::thread - można przypuszczać, że ta
biblioteka korzysta z tych samych mechanizmów na poziomie systemu co OpenMP.
Pierwsze pytanie do Was, ilu jest chętnych do przetestowania programu tak
po prostu na jednym komputerze, a ilu jest chętnych do odpalenia go na
jakimś klastrze? Program na razie nie wspomaga żadnego MPI ani BOINC, ale
podobno można tak skonfigurować klaster, żeby wykonał się na wielu
maszynach. Ciekawy jestem jakie byłyby wyniki na klastrze.
W drugim kroku, jeśli będą chętni do pomocy przy konfigurowaniu BOINC,
przejdziemy do obliczeń w tej sieci. Problem przeszukiwania drzewa gry
jest wykładniczy. Na moim kompie (6 rdzeni) najlepszy algorytm z
najlepszymi parametrami potrzebował 2315 sekund aby przejrzeć drzewko
na głębokość 9 ruchów. Znalazł w nim 2439530234167 liści. Pewnie w
przeciągu doby zejdzie do 10 ruchów, a w miesiąc do 11 ruchów. Po
optymalizacji, w jeden miesiąc może będzie dochodził do 12 ruchów.
Jakbyśmy użyli 30 komputerów to po miesiącu osiągniemy 13 ruchów - tak
można przypuszczać :)
Jak widać na tej stronice:
http://oeis.org/A048987/list
Ktoś do 13 ruchów już doszedł :) Więc jakbyśmy chcieli bić rekord, to
byśmy musieli zejść do 15-16 ruchów :) Ciekawy jestem czy będą
zainteresowani, zwłaszcza że są poważne rzeczy do obliczenia, a to
tylko zabawa.
Jak będą zainteresowani, to w następnym poście opiszę jak używać
programu :)
Pozdrawiam!
Próbowałem odpalić, ale na moim ubu woła o bibliotekę libboost_thread.so.1.46.1... Doinstalowanie libboost-thread-dev nie pomogło, a chętnie bym potestował na 4 rdzeniach (niestety, RAMu tylko 4GB).
Edit:
Mogę też w wirtualce spróbować na 8 wątkach (Xeon e-3 1230)
Z tego co napisał krzyszp wynika, że kompilowałeś dynamicznie a nie statycznie. Proponuję albo wrzucić źródła (z makefile'm) albo skompilować statycznie ;)
dlaczego libboost_thread.so.1.46.1
to stara wersja z 2011 i jeśli akurat jej potrzebujesz skompiluj statycznie
w systemie mam domyślnie 1.52 i 1.53
ale doinstalowałem 1.46.1
po uruchomieniu ./perft nic nie robi, nie obciąża CPU mimo wolnych rdzeni (Xeon E3 1230), nic nie wypisuje w konsoli, nie reaguje też na parametr --help
opisz jak powinna się zachowywać app i ewentualnie z jakimi parametrami uruchamiać
Edit:
po uwzględnieniu n/w komend app działa :)
perft 1
nodes:20 time:0
perft 2
nodes:400 time:0
perft 3
nodes:8902 time:0
perft 4
nodes:197281 time:0
perft 5
nodes:4865609 time:0
perft 6
nodes:119060324 time:20
6 już chwilkę trwało
projekt ciekawy o ile stanie na nogi :D
Cytat: krzyszp w 24 Maj 2013, 17:27
Próbowałem odpalić, ale na moim ubu woła o bibliotekę libboost_thread.so.1.46.1... Doinstalowanie libboost-thread-dev nie pomogło, a chętnie bym potestował na 4 rdzeniach (niestety, RAMu tylko 4GB).
Dzięki za zainteresowanie !
Na swoich komputerach kopiuję po prostu do /usr/lib/ i działa.
Załączam do posta moją bibliotekę i lekko ulepszony program.
Mam nadzieje że tym razem zadziała, a jak nie, to problem jakoś
się rozwiąże.
A skoro są zainteresowani, to opiszę niektóre komendy:
Uruchamiamy z linii polecenia z bieżącego katalogu bez żadnych
parametrów:
./perft
podstawowe polecenie jest takie samo jak nazwa programu:
perft depth
gdzie depth to głębokość przeszukiwania.
Przykład:
./perft
perft 1
nodes:20 time:0
perf 2
unknown command: perf
perft 3
nodes:8902 time:0
perft 4
nodes:197281 time:0
perft 5
pnodes:4865609 time:1
perft 6
nodes:119060324 time:20
quit
----------------------------------------------------------------
kolejne polecenie umie wykorzystać dodatkową pamięć:
memPerft depth mem_size mem_probe
depth - głębokość przeszukiwania
mem_size - ilość spamiętanych układów, jeden układ wymaga około 20bajtów pamięci
mem_probe - parametr do zarządzania pamięcią, optymalna wartość zwykle mieści się w przedziale od 2 do 16
Przykład:
./perft
memperft
using: memPerft depth mem_size mem_probe
memPerft 1 100000 4
nodes:20 time:0
memPerft 2 10000 4
nodes:400 time:0
memPerft 3 100000 4
nodes:8902 time:0
memPerft 4 100000 4
nodes:197281 time:0
memPerft 5 100000 4
nodes:4865609 time:0
memPerft 6 100000 4
nodes:119060324 time:6
memPerft 6 100000 8
nodes:119060324 time:6
quit
----------------------------------------------------------------
Kolejne polecenie działa na wątkach:
threadPerft depth max_thread
depth - tak samo jak poprzednio: głębokość przeszukiwania
max_thread - maksymalna ilość wątków
Przykład:
./perft
threadPerft
using: threadPerft depth max_thread
threadPerft 1 4
nodes:20 time:0
threadPerft 2 4
nodes:400 time:0
threadPerft 3 4
nodes:8902 time:0
threadPerft 4 4
nodes:197281 time:0
threadPerft 5 4
nodes:4865609 time:0
threadPerft 6 4
nodes:119060324 time:12
quit
----------------------------------------------------------------
Ostatnie polecenie z tej serii wykorzystuje wątki i pamięć.
threadMemPerft depth max_thread mem_size mem_probe forget
depth - głębokość przeszukiwania
max_thread - maksymalna ilość wątków
mem_size - ilość zapamiętanych układów (jeden układ około 20bajtów)
mem_probe - zarządzanie pamięcią, najlepsza wartość zwykle w przedziale od 2 do 16.
forget - dodatkowy parametr do zarządzania pamięcią, dobra wartość zwykle mieści się w przedziale od tysiąca do miliona.
Przykład użycia
./perft
threadMemPerft
using: threadMemPerft depth max_thread mem_size mem_probe forget
threadMemPerft 1 2 100000 4 0
nodes:20 time:0
threadMemPerft 2 2 100000 4 0
nodes:400 time:0
threadMemPerft 3 2 100000 4 0
nodes:8902 time:0
threadMemPerft 4 2 100000 4 0
nodes:197281 time:0
threadMemPerft 5 2 100000 4 0
nodes:4865609 time:1
threadMemPerft 6 2 100000 4 0
nodes:119060324 time:4
threadMemPerft 7 2 100000 4 0
nodes:3195901860 time:115
threadMemPerft 7 2 1000000 4 0
nodes:3195901860 time:58
threadMemPerft 7 2 10000000 4 0
nodes:3195901860 time:36
threadMemPerft 7 3 10000000 4 0
nodes:3195901860 time:31
threadMemPerft 7 4 10000000 4 0
nodes:3195901860 time:28
quit
------------------------------------------------------------------
Program ma dodatkową komendę
setboard. Aby jej używać, najpierw
najlepiej zainstalować program
xboard. Xboard to środowisko graficzne
w którym możemy na planszy szachowej poukładać figury. Następnie
układ z szachownicy można przekopiować do schowka i wkleić go
do konsoli programu
perft. Tym samym można przeszukać drzewko
dla dowolnego (poprawnego) układu, a nie tylko dla układu startowego.
Przykład użycia:
./perft
setBoard rn3rk1/ppp3pp/4bq2/2b1Np2/2B2P2/8/PPP1Q1PP/R1B1K2R w KQ - 0 1
perft 1
nodes:40 time:0
perft 2
nodes:1480 time:0
perft 3
nodes:56293 time:0
perft 4
nodes:2141911 time:0
memPerft
using: memPerft depth mem_size mem_probe
memPerft 4 10000 4
nodes:2141911 time:1
quit
------------------------------------------------------------------
Program ma wkompilowne 1001 układów. Można go hurtowo
przetestować na tym całym zestawie. Aby to zrobić, przed
komendami trzeba wpisać przedrostek
multi, a potem
składnia poleceń jest taka sama.
Przykład:
./perft
multiPerft 2
quit
Jak coś niezrozumiałe, to piszcie.
Pozdrawiam
Cytat: Troll81 w 24 Maj 2013, 18:10
projekt ciekawy o ile stanie na nogi :D
To tylko zliczanie węzłów, to (być może) przedsmak czegoś znacznie lepszego.
Niemniej pobawić się można tym programem. Jak będzie zainteresowanie, to z Waszym wsparciem
może stanąć na nogi :)
Pozdrawiam
U mnie program działa na Ubuntu 12.XX 64bit po zainstalowaniu biblioteki :) Muszę tylko jeszcze rozszyfrować co on dokładnie robi i jakie dane zwraca :D
Cytat: patyczak w 24 Maj 2013, 18:50
U mnie program działa na Ubuntu 12.XX 64bit po zainstalowaniu biblioteki :) Muszę tylko jeszcze rozszyfrować co on dokładnie robi i jakie dane zwraca :D
Program bada "złożoność szachów". Umie przyspieszyć obliczenia dzięki użyciu wielu
rdzeni i/albo dużej pamięci. Można wpisać np.:
./perft
perft 6
nodes:119060324 time:19
threadPerft 6 4
nodes:119060324 time:10
quit
I widać że w 4 wątkach (na kompie który ma 2 fizyczne rdzenie) program działa
dwa razy szybciej, a podaje taki sam wynik: nodes: 119060324
Przy pomyślnych wiatrach przerobimy go tak, aby umiał jeszcze wykorzystać BOINC ;-)
Pozdrawiam
To wyjaśnij jeszcze laikowi szachowemu co to jest "złożoność szachów"? Ilość możliwych rozgrywek od określonego ustawienia figur?
Cytat: patyczak w 24 Maj 2013, 19:09
To wyjaśnij jeszcze laikowi szachowemu co to jest "złożoność szachów"? Ilość możliwych rozgrywek od określonego ustawienia figur?
Raczej nie ma takiego pojęcia, napisałem je tak sobie, żeby właśnie nie wdawać się w szczegóły :)
Ściśle chodzi o procedurę która ma nazwę
perft. Etymologia to: perfection test.
Bardzo trudno jest napisać program szachowy. Programiści szukając ułatwienia wymyślili właśnie
perft. Perft polega na
przeszukaniu drzewa gry na zadaną głębokość i policzeniu ile drzewo ma
liści. Perft szuka prawie zgodnie z zasadami szachowymi - nie wiem czemu nie robi tego zgodnie w
100%. Perft nie uwzględnia reguły 50ciu posunięć i reguły trzykrotnego powtórzenia - nie pytajcie
mnie dlaczego tak jest - tak się z jakiś powodów przyjęło, a ja nie chciałem się wyłamywać.
No... to chyba wszystko :)
Pozdrawiam
Niestety. Mam problem z bibliotekami. Dasz radę skompilować z opcją -static ?
Cytat: Rysiu w 24 Maj 2013, 19:54
Niestety. Mam problem z bibliotekami. Dasz radę skompilować z opcją -static ?
Może się udało, trzeba sprawdzić. Program jest większy, więc na pewno coś dodał :D
U mnie działa na dwóch różnych kompach, mam nadzieję że u Was też zadziała.
Pozdrawiam
Cytat: Rysiu w 24 Maj 2013, 19:54
Niestety. Mam problem z bibliotekami. Dasz radę skompilować z opcją -static ?
Rysiu, przekopiuj tę bibliotekę do /usr/lib i działa :)
Odpaliłem "threadperft 16 4" - zobaczymy, ile zejdzie :)
Cytat: krzyszp w 24 Maj 2013, 20:07
Odpaliłem "threadperft 16 4" - zobaczymy, ile zejdzie :)
depth = 16 to dużo za dużo :)
Na początek lepiej spróbować:
threadPerft 8 4
Karkołomne może już być
threadPerft 10 4
Ta druga liczba (tutaj 4) to ilość wątków. Zwykle najlepiej jest dać 1-2 wątki więcej niż
ilość fizycznych rdzeni.
Pozdrawiam
Cytat: mariotti w 24 Maj 2013, 20:06
Może się udało,
Udało się :p_arr:
Cytatthreadperft 2 8
nodes:400 time:0
threadperft 3 8
nodes:8902 time:0
threadperft 4 8
nodes:197281 time:0
threadperft 5 8
nodes:4865609 time:0
threadperft 6 8
nodes:119060324 time:3
threadperft 7 8
nodes:3195901860 time:91
threadMemPerft 7 8 10000000 4 0
nodes:3195901860 time:9
Cytat
Rysiu, przekopiuj tę bibliotekę do /usr/lib i działa :)
Próbowałem ale brakowało innej biblioteki niż ta załączona.
CytatOdpaliłem "threadperft 16 4" - zobaczymy, ile zejdzie :)
Setki jak nie tysiące lat :ph34r:
Odpaliłem to na serwerze z Q6600, więc mam 4 fizyczne rdzenie, a że komp nigdy nie wyłączany/resetowany - to niech pracuje :) (chyba, że ma to rok potrwać...)
Krzyszp to może zająć nawet dziesiątki tysięcy lat. Do tego czasu nie jest pewne czy gatunek ludzki przetrwa, a Ty piszesz, że komputer nie jest restartowany :deadman:
Cytat: Rysiu w 24 Maj 2013, 20:28
Krzyszp to może zająć nawet dziesiątki tysięcy lat. Do tego czasu nie jest pewne czy gatunek ludzki przetrwa, a Ty piszesz, że komputer nie jest restartowany :deadman:
Uuuups, liczyłem na max kilka miesięcy :)
No, to jednak przerywam :)
Cytat: krzyszp w 24 Maj 2013, 20:23
Odpaliłem to na serwerze z Q6600, więc mam 4 fizyczne rdzenie, a że komp nigdy nie wyłączany/resetowany - to niech pracuje :) (chyba, że ma to rok potrwać...)
Raczej 100 milionów lat :)
Odpal na głębokość 10 wersję z pamięcią :) Wersja z pamięcią baaardzo przyspiesza, może 100-1000 razy.
Właśnie u siebie sprawdzam ile będzie się to liczyło.
Składnia polecenia:
threadMemPerft depth max_thread mem_size mem_probe forget
Przykład dla 2GB ram i 5-ciu wątków (5 wątków działa szybciej niż 4, nawet gdy są 4 rdzenie)
threadMemPerft 10 5 100000000 4 0
Przykład dla 1GB ram:
threadMemPerft 10 5 50000000 4 0
To powinno się policzyć w jakieś... nie wiem... 12-72h, strzelam że w 20h się policzy.
Pozdrawiam
Cytat: mariotti w 24 Maj 2013, 20:33
To powinno się policzyć w jakieś... nie wiem... 12-72h, strzelam że w 20h się policzy.
W 20h to nie bo Krzyszp pewnie dodaje dane klimatyczne na serwerze i jakiś dodatkowy load ma %)
@Mariotti te 100 milionów lat to jakoś oszacowałeś czy z głowy?
Cytat: Rysiu w 24 Maj 2013, 20:38
@Mariotti te 100 milionów lat to jakoś oszacowałeś czy z głowy?
Jeśli komputer Q6600 jest dwa razy szybszy od mojego i współczynnik rozgałęzienia
wynosi 30 to 73mln lat. Jeśli Q6600 jest tak samo szybki jak mój i w.r. wynosi 25 to
28mln lat.
Moze 50mln jest dokładniejszym oszacowaniem niż 100mln :)
Natomiast wersja z pamięcią
(mogę się bardzo mylić, tutaj szacowanie jest dużo trudniejsze) w jakieś 500-1000 lat by dała radę, czyli rok na 1tys maszyn. Z tego co
pobieżnie zdążyłem się zorientować, obecny rekord wynosi 13, czyli 16 by przełamało tę barierę aż o 3 poziomy!
Pozdrawiam
Czyli generalnie, walka toczy się o "14"???
Bo jeśli tak, i jeżeli możesz zrównoleglić aplikację, to BOINC aż się prosi o to :)
Edit:
Odpaliłem threadMemPerft 10 5 100000000 4 0, zobaczymy, jaki będzie czas...
Cytat: krzyszp w 24 Maj 2013, 21:10
Czyli generalnie, walka toczy się o "14"???
O ile się nie mylę, to tak. Wdziałem z wielu źródeł wyniki dla depth=12. Z raptem dwóch
źródeł dla depth=13. Dla 14 nie widziałem, ale nie powiedziane, że widziałem wszystko :)
Cytat: krzyszp w 24 Maj 2013, 21:10
Bo jeśli tak, i jeżeli możesz zrównoleglić aplikację, to BOINC aż się prosi o to :)
Spróbujemy. Jeśli rzucać się na BOINC, to wersja z pamięcią i od razu można
na kilka głębokości, np. na wszystkie od 10 do 20. Pytanie dlaczego rzucać się na
głębokości powyżej 16, jeśli to wymaga tak ogromnej mocy obliczeniowej? Odpowiedź
jest taka, że poza dokładnym obliczeniem, robi się także oszacowania. Zanim policzymy
dokładnie dla depth>15, to będziemy mieli policzone częściowo, np. 0.1% całości. Wtedy
można to co już policzone wymnożyć razy 1000 i podawać z dania na dzień dokładniejsze
oszacowania. Dla mniejszych głębokości (może dla depth<=16) w końcu się uzyska dokładny
wynik, a dla większych oszacowania też będą cieszyły. Koncepcyjnie jest to proste, w
realizacji... no cóż... wymaga dużo czasu.
Projekt jest prosty i zabawowy, ale w środowisku szachowym może wywoływać emocje :)
Cytat: krzyszp w 24 Maj 2013, 21:10
Odpaliłem threadMemPerft 10 5 100000000 4 0, zobaczymy, jaki będzie czas...
Ja odpaliłem na Phenom II 6 rdzeni:
threadMemPerft 10 8 250000000 8 1000000
Porównamy jutro(?) wyniki :D
Pozdrawiam
Wszystko pięknie, ale nie uwzględniłem jednego drobiazgu...
Otóż program odpaliłem w konsoli SSH, ale z powodu Einsteina musiałem swojego hosta zrestartować (ale Twój program na serwerze cały czas działa)... Pytanie - czy on zapisuje gdzieś wyniki? Jak nie, to ubiję go i odpalę normalnie (tzn, podczepię monitor i klawiaturę i odpalę lokalnie).
Edit:
Ok, odpaliłem jeszcze raz...
Cytat: krzyszp w 24 Maj 2013, 21:43
Ok, odpaliłem jeszcze raz...
Jedyny sposób na zapisywanie to dodatkowy skrypt, np. taki:
#!/bin/sh
(
echo threadMemPerft 1 5 100000000 4 0
echo threadMemPerft 2 5 100000000 4 0
echo threadMemPerft 3 5 100000000 4 0
echo threadMemPerft 4 5 100000000 4 0
echo threadMemPerft 5 5 100000000 4 0
echo threadMemPerft 6 5 100000000 4 0
echo threadMemPerft 7 5 100000000 4 0
echo threadMemPerft 8 5 100000000 4 0
echo threadMemPerft 9 5 100000000 4 0
echo threadMemPerft 10 5 100000000 4 0
echo quit
) | ./perft >> out.txt
A ja po ./perft otrzymuję komunikat <i>command not found</i>... :o
Cytat: krzyszp w 24 Maj 2013, 21:43
Ok, odpaliłem jeszcze raz...
Ciekawy jestem jaki masz wynik i czy program się już zakończył :)
U mnie się zakończył, ale podał błędny wynik :)
Poprawny wynik dla głębokości 10 to 69352859712417
U mnie jest: 69352859710032 i czas 63547 sekund.
Program ma dwie heurystyki, czyli coś co zwykle działa, ale nie gwarantuje
poprawnego wyniku. Muszę sprawdzić czy błędny wynik jest zwyczajnie z
powodu błędu w programie, czy te heurystyki zbyt szybko zawiodły.
Jeśli u Ciebie będzie inny wynik niż u mnie, to mamy prawie pewność, że
heurystyki nie zadziałały. Będę musiał je jakoś "wzmocnić".
Pozdrawiam
Cytat: Argento w 25 Maj 2013, 11:54
A ja po ./perft otrzymuję komunikat <i>command not found</i>... :o
Trzeba zrobić dwie rzeczy:
1) zmienić katalog bieżący na ten do którego się przekopiowało program
2) wydać komendę chmod 500 perft
potem powinno działać.
Pozdrawiam
U mnie nadal chodzi, ale jak Rysiu zauważył, komp jest dość mocno obciążony zazwyczaj, więc wynik może być później.
Cytatwydać komendę chmod 500 perft
Zapomniałem... :bad:
A teraz sytuacja jak u
RAD-Poland, czyli żadnej reakcji na
./perft. Tak z paramterami jak i bez...
Na podstawie waszych wyników zbudowałem prostą funkcję aproksymującą i takie są wyniki:
(pierwsza kolumna to głąbokość analizy, 4 kolejne to średni czas obliczeń dla trybu najprostszego, kolumna mem_mod to czas obliczeń dla trybu z pamięcią)
1 sek godz dni lat (mem mod) lat
2 0 0 0 0 0
3 0 0 0 0 0
4 0 0 0 0 0
5 1 0 0 0 0
6 20 0 0 0 0
7 529 0 0 0 0
8 14 285 4 0 0 0
9 399 975 111 5 0 0
10 11 599 272 3 222 134 0 0
11 347 978 166 96 661 4 028 11 0
12 10 787 323 140 2 996 479 124 853 342 9
13 345 194 340 466 95 887 317 3 995 305 10 939 273
14 11 391 413 235 378 3 164 281 454 131 845 061 360 972 9 024
15 387 308 050 002 837 107 585 569 445 4 482 732 060 12 273 051 306 826
16 13 555 781 750 099 300 3 765 494 930 583 156 895 622 108 429 556 802 10 738 920
Teraz widać dlaczego nikt nie policzył do 16 ;D.
Ostatnia kolumna jest prostym założeniem, wynikającym z podanych przez was wyników, że w trybie z pamięcią obliczenia są wykonywane 40 razy szybciej (patrząc na 1 wątek)
Przy "13" jeszcze idzie policzyć w realnym czasie, ale już "14" to niezła orka.
Przyjmijmy, że wydajność jednego rdzenia to średnio 6000 MIPSów, więc by przeliczyć "14" trzeba wykonać około 1700 kwintylionów FLOPów (licząc jednostki jak amerykanie). To jest, tak dla porównania, około 2 miliardów kredytów w PrimeGrid'zie. Cały zespół B@P ma mniej więcej tyle, a pewnie lwia część tego to projekty liczone na GPU.
Cytat: Argento w 25 Maj 2013, 13:24
Cytatwydać komendę chmod 500 perft
Zapomniałem... :bad:
A teraz sytuacja jak u RAD-Poland, czyli żadnej reakcji na ./perft. Tak z paramterami jak i bez...
Instrukcja i przykłady w moim drugim poście tego wątku :)
Uruchamiamy program i potem wpisujemy komendy.
-------------------------------------------------------------------------------------------------------------------------
Jeśli możesz obliczenia zostawić na dłuży czas ( rzędu 20-60h - zależnie od
szybkości komputera ) to teraz najbardziej potrzebny jest jeden określony
test. A mianowicie trzeba wpisać taki skrypt:
#!/bin/sh
(
echo threadMemPerft 1 5 100000000 4 0
echo threadMemPerft 2 5 100000000 4 0
echo threadMemPerft 3 5 100000000 4 0
echo threadMemPerft 4 5 100000000 4 0
echo threadMemPerft 5 5 100000000 4 0
echo threadMemPerft 6 5 100000000 4 0
echo threadMemPerft 7 5 100000000 4 0
echo threadMemPerft 8 5 100000000 4 0
echo threadMemPerft 9 5 100000000 4 0
echo threadMemPerft 10 5 100000000 4 0
echo quit
) | ./perft >> out.txt
Skrypt można nazwać go.sh. Skryptowi też nadajemy:
chmod 500 go.sh
i uruchamiamy
./go.sh
Potem wynik będą w pliku out.txt
--------------------------------------------------------------------------------------------------------------
TuningJeśli komputer ma 6 rdzeni, to warto jako drugi parametr podać
liczbę 8 (zamiast 5).
Jeśli komputer ma 1GB wolnej pamięci to jak trzeci parametr podajemy
liczbę 50000000 (50 milionów).
Jeśli komputer ma 2GB wolnej pamięci to jak trzeci parametr podajemy
liczbę 100000000 (100 milionów).
Jeśli komputer ma 4GB wolnej pamięci to jak trzeci parametr podajemy
liczbę 200000000 (200 milionów).
---------------------------------------------------------------------------------------------------
PS.
Na moim komputerze program podał wynik z małym błędem. Muszę znaleźć
przyczynę. Potencjalnie są... cztery przyczyny:
1) błąd sprzętu - wczoraj rano komputer włączył się i nie widział jednej kości ram, musiałem
wyjąć kości i włożyć na nowo.
2) zwyczajny błąd w kodzie
3) zbyt mała losowość funkcji skrótu (w celu przyspieszenia zapamiętuję tylko funkcję skrótu a nie cały układ)
4) za słaba CRC - nie używam blokad na dostęp do pamięci, gdyż to bardzo spowalnia. zamiast
blokad używam crc - jeśli jeden wątek popsuje dane drugiemu wątkowi, to crc powinna się nie zgadzać.
Wyniki na Waszych komputerach trochę pomogą mi ustalić co jest przyczyną błędu. Jeśli wszędzie
będzie dobry wynik, a u mnie zły to będzie wskazywało że mój komputer się rozwalił. Jeśli wszędzie
będą inne wyniki, to będzie wskazywało że mam za słabą funkcję skrótu albo za słaby crc. Jeśli wszędzie
będą takie same (ale błędne) wyniki, to prawdopodobnie mam błąd w kodzie.
Pozdrawiam
Cytat: Dario666 w 25 Maj 2013, 13:45
Ostatnia kolumna jest prostym założeniem, wynikającym z podanych przez was wyników, że w trybie z pamięcią obliczenia są wykonywane 40 razy szybciej (patrząc na 1 wątek)
Wyedtyowałem ten post, bo w świetle nowych wyników nie miał on najmniejszego sensu.
Całkiem przyzwoita funkcja aproksymująca to:
time = 400 * A ^ (depth-2) Dla algorytmu bez pamięci A wynosi prawdopodobnie 25
Dla algorytmu z pamięcią A wynosi prawdopodobnie 11
Gdy pamięci jest mało, to A przyjmuje wartość z przedziału 11-25.
Pozdrawiam
Ja liczę do 10 na Core i7 950 i 24 GB RAM. Program zaalokował ponad 22 GB pamięci.
Głębokość 8 obliczył w 106 sekund. Całkiem niezły wynik mi się wydaje. Wszystkie dotychczasowe wyniki zgadzają się z tymi w bazie oeis.org.
---- EDIT:
Obliczył właśnie do głębokości 9. Trwało to 1160 sekund. Wynik zgodny z oeis.org.
Cytat: Rysiu w 25 Maj 2013, 15:13
Ja liczę do 10 na Core i7 950 i 24 GB RAM. Program zaalokował ponad 22 GB pamięci.
Głębokość 8 obliczył w 106 sekund. Całkiem niezły wynik mi się wydaje. Wszystkie dotychczasowe wyniki zgadzają się z tymi w bazie oeis.org.
Obliczył właśnie do głębokości 9. Trwało to 1160 sekund. Wynik zgodny z oeis.org.
Zbadamy za jakiś czas jaki wpływ mają dwa ostatnie parametry. U mnie na i3 (laptop) takie
mam wyniki dla depth=8:
./perft
threadMemPerft 8 4 220000000 4 0
nodes:84998978956 time:260
threaMemPerft 8 4 220000000 4 1
unknown command: threamemperft
threadMemPerft 8 4 220000000 4 1
nodes:84998978956 time:277
threadMemPerft 8 4 220000000 4 1000
nodes:84998978956 time:275
threadMemPerft 8 4 220000000 4 1000000
nodes:84998978956 time:247
threadMemPerft 8 4 220000000 8 0
nodes:84998978956 time:246
threadMemPerft 8 4 220000000 8 1000000
nodes:84998978956 time:250
threadMemPerft 8 4 220000000 12 0
nodes:84998978956 time:268
threadMemPerft 8 4 220000000 12 1000000
quit
Najlepszy wynik 246 sekund, najgorszy 277 - czyli trochę można zyskać. Dla
większych głębokości zysk może być znacznie większy.
Pozdrawiam
Jesteś pewien, że zapamiętywanie funkcji skrótu zamiast całego układu tak istotne? O ile dobrze liczę to całą planszę można zapisać na 24-32 bajtach (w zależności od tego jak zakodujemy planszę). Nie znam algorytmu, więc ciężko mi mówić jaki to miałoby wpływ na wydajność (bo może kodowanie/dekodowanie tego by było zbyt czasochłonne).
Cytat: Karlik w 25 Maj 2013, 17:07
Jesteś pewien, że zapamiętywanie funkcji skrótu zamiast całego układu tak istotne?
Na pewno jest istotne. Jak bardzo istotne, to nie sprawdzałem. Możliwe że to
przyspiesza nawet 2-3 razy. Na pewno da się w ten sposób zapamiętać dwa
razy więcej układów, a to istotnie przyspiesza.
Cytat: Karlik w 25 Maj 2013, 17:07
O ile dobrze liczę to całą planszę można zapisać na 24-32 bajtach (w zależności od tego jak zakodujemy planszę).
w 32 bajtach na pewno można, w 20tu może też by się dało. Ale takie zapamiętanie to
nie byłoby szybkie memcpy i potem porównanie przez memcmp. Jak się zrobi planszę
jako liniowe 64/32 bajty, to z kolei wolno działają inne operacje :)
Cytat: Karlik w 25 Maj 2013, 17:07
Nie znam algorytmu, więc ciężko mi mówić jaki to miałoby wpływ na wydajność (bo może kodowanie/dekodowanie tego by było zbyt czasochłonne).
Mnie też jest trudno powiedzieć, myślę że z tą techniką działa 2-3 razy szybciej.
Pozdrawiam
Cytat: Dario666 w 25 Maj 2013, 13:45
Teraz widać dlaczego nikt nie policzył do 16 ;D.
Ostatnia kolumna jest prostym założeniem, wynikającym z podanych przez was wyników, że w trybie z pamięcią obliczenia są wykonywane 40 razy szybciej (patrząc na 1 wątek)
Przy "13" jeszcze idzie policzyć w realnym czasie, ale już "14" to niezła orka.
Przyjmijmy, że wydajność jednego rdzenia to średnio 6000 MIPSów, więc by przeliczyć "14" trzeba wykonać około 1700 kwintylionów FLOPów (licząc jednostki jak amerykanie). To jest, tak dla porównania, około 2 miliardów kredytów w PrimeGrid'zie. Cały zespół B@P ma mniej więcej tyle, a pewnie lwia część tego to projekty liczone na GPU.
Przychodzi mi do głowy tylko jedyny sensowny sposób na dokładnie oszacowanie czasu
dla algorytmu z pamięcią.
Najpierw trzeba policzyć na jakąś głębokość i zapamiętać wszystkie układy. Potem układy
powtarzające się trzeba wyrzucić, a z każdym układem zapamiętać ilość jego wystąpień. W
ten sposób otrzymamy ilość różnych układów. Różne układy mogłyby leżeć w bazie
na jakimś serwerze. Klient może pytać o układ, wykonywać dla niego obliczenia i odsyłać
wynik z powrotem na serwer. Czyli łączny czas obliczeń będzie wynosił A*N, gdzie
A to średni czas liczenia jednego układu, a N to ilość różnych układów.
Sensowna głębokość dla klienta jest w granicach 8-10. Przy głębokości 8, mogą zapchać
serwer. Przy głębokości 10 na serwerze będzie mało układów, a więc gorzej zadziała algorytm
odrzucania powtarzających się. Powiedzmy że klient będzie liczył na głębokość 9. Czyli
serwer musi sam przeszukać na głębokość 5 aby łącznie uzyskać 14. Drzewko ma 4865609 liści
przy głębokości 5 ruchów. Widzieliśmy że na głębokość 9 da się policzyć w 1160s. Powiedzmy
że program po zoptymalizowaniu policzy na głębokość 9 w 10-20sekund (kurcze, 20 sekund
nadal może zapchać serwer). Czyli 4865609*10-20s=15-30 lat - całkiem szybko, a do tego
wiele układów będzie się powtarzało.
Nie wiem ile układów będzie się powtarzało, myślę że bardzo dużo odpadnie. Strzelam że
zostanie tylko 10% układów. Czyli 10% * 4865609 * 10-20s = 1.5 - 3 lat - Na boinc to bułka
z masłem.
Jeśli przyjmiemy podstawę potęgi równą 25, to by znaczyło, że z tymi technikami w nie więcej
niż 3tys lat dojdziemy do głębokości 16 ruchów.
Obawa pozostaje jedna, czy naprawdę pozostanie tylko 10% układów po odrzuceniu powtórzeń?
To oszacowanie na pewno jest znacznie bardziej optymistyczne niż Twoje 10 738 920 lat :D
Pozdrawiam
nie można uruchomić pliku binarnego
1. chmod +x ./perft poszło
2. apt-get install ia32-lib-i386 poszło
3. apt-get libboost-thread-dev poszło
4. ściągnięcie preft + lib w wersji wymaganej poszło
i dalej nie działa :/ (debian 7 no gui)
Cytat: Szopler w 25 Maj 2013, 19:59
nie można uruchomić pliku binarnego
1. chmod +x ./perft poszło
2. apt-get install ia32-lib-i386 poszło
3. apt-get libboost-thread-dev poszło
4. ściągnięcie preft + lib w wersji wymaganej poszło
i dalej nie działa :/ (debian 7 no gui)
Program na razie nie będzie działał na linuxie 32 bitowym.
Pozdrawiam
Cytat: mariotti w 25 Maj 2013, 17:51w 32 bajtach na pewno można, w 20tu może też by się dało. Ale takie zapamiętanie to
nie byłoby szybkie memcpy i potem porównanie przez memcmp. Jak się zrobi planszę
jako liniowe 64/32 bajty, to z kolei wolno działają inne operacje :)
Akurat dowolną strukturę można spokojnie w ten sposób porównywać ;] Nie wiem jak masz to do innych operacji przedstawione, ale jak dla mnie to może być coś typu:
struct plansza{
unsigned char white[16];
unsigned char black[16];
};
Gdzie spokojnie możesz zapisać na starszych 4 bitach X, na młodszych Y, same zera dają pionek poza planszą. Wtedy masz 32 bajty, które swobodnie możesz porównać przez memcmp. Jedyny ew. mankament to pionki, które musiałbyś osobno sprawdzać, bo są traktowane indywidualnie. Inne podejście może być takie:
struct plansza{
unsigned char field[4][8];
};
wtedy masz w jednym bajcie dwa pola (możesz je traktować liniowo) - wtedy reprezentujesz sobie najstarszy bit zapisu jako kolor, pozostałe 3 jako rodzaj figury (król, królowa, goniec, koń, wieża, pion) - jedna wartość niewykorzystana. Wtedy masz bardzo wygodne porównywanie przez memcmp.
To masz wersje 32 bajtowe. Z mniejszych, gdzie ma się pełną informację na pewno wykonalna jest 28 bajtowa jeszcze.
Wydaje mi się, że koszt operowania na tak przygotowanej planszy jest mniejszy niż liczenie funkcji skrótu. W sumie to takie gdybanie, bo jak się nie widzi kodu to ciężko cokolwiek doradzić.
To teraz tak, hash ma 20 bajtów z tego co zrozumiałem. Możesz spróbować jakoś ponumerować układy po prostu. Masz maksymalnie zajęte 32 pola z 64, to masz 64 po 32 = 1,8e+18 układów zajętych pól. Masz 13 rodzajów figur (6*2+1 -> jedynka, bo może pole być puste). Więc masz 13^32 * 1,8e+18, z tego logarytm dwójkowy wychodzi ~179, więc musisz poświęcić co najmniej 23 bajty na każdy układ. Można teoretycznie zbić jeszcze to trochę, bo król może występować tylko raz, królowa tylko raz, więc zamiast 13^32 wyjdzie jakieś 13*12*11*10 (króle i królowe), dalej *9*9*8*8 (gońce), *7*7*6*6 (konie), *5*5*4*4 (wieże), *3^8 * 2^8 (pionki) * 2^30 (bo każdy może występować lub nie z wyjątkiem króli), wtedy masz te swoje upragnione 20 bajtów (158 bitów). W rzeczywistej grze liczba układów jeszcze jest mniejsza, bo niektóre sytuacje nigdy nie zajdą, ale liczenie tego to... Tak więc teoretycznie te 20 bajtów może Ci wystarczyć, ale nie zdziwiłbym się, gdyby Twoja funkcja skrótu dawała tę samą wartość dla dwóch różnych układów (zrobienie takiej idealnej nie jest wbrew pozorom takie proste).
Cytat: mariotti w 25 Maj 2013, 20:12
Cytat: Szopler w 25 Maj 2013, 19:59
nie można uruchomić pliku binarnego
1. chmod +x ./perft poszło
2. apt-get install ia32-lib-i386 poszło
3. apt-get libboost-thread-dev poszło
4. ściągnięcie preft + lib w wersji wymaganej poszło
i dalej nie działa :/ (debian 7 no gui)
Program na razie nie będzie działał na linuxie 32 bitowym.
Pozdrawiam
Ale kwas :/ przez pomyłkę ściągnąłem i zainstalowałem i386 zamiast amd64... :facepalm2:
Edit: Dobra odpaliłem go.sh...
Cytat: Szopler w 25 Maj 2013, 19:59
i dalej nie działa :/ (debian 7 no gui)
Ale 32 czy 64bit?
//Edit: Nie zauważyłem drugiej strony z odpowiedziami %)
Za to u mnie po prawie dobie wyskoczyło "Killed"... :(
Zakładam, że to z powodu braku wolnej pamięci (serwer wszedł mi ostro na swap'a).
Edit:
Spróbowałem odpalić na Virtualbox'ie skrytp, ale niestety wysypał się z komunikatem (z VB) "Guru meditation" ;)
Ciekawe jak chcesz zoptymalizować obliczenia z 1160 sekund do średnio 15 sekund, czyli przyspieszyć go 77 razy. To chyba zbytni optymizm.
Znalazłem na stronach szachowych dość obszery wywód z szacowaniem ilości możliwych rozstawień figur i wynik brzmiał 1040.
Patrząc na to, że funkcja haszująca 160-bitowa ma 1,46*1048 różnych wyników, to może się okazać zbyt mało i kolega Karlik może mieć rację, że hasze będą się powtarzać dla rózych ustawień.
Zasadnicze pytanie jest takie: po co to w ogóle mamy liczyć? Dla samego przeliczenia? Jakie jest cel i jakie dane chcemy zgromadzić, aby można je było wykorzystać do dalszych badań. Według mnie metoda z haszami nie jest trafiona, bo nie możemy z niej odczytać jakie jest rzeczywiste ustawienie figur na szachownicy.
> Akurat dowolną strukturę można spokojnie w ten sposób porównywać ;]
Nie chodzi o to że nie można, tylko oto, że dane sekwencyjne porównuje się szybciej.
> Nie wiem jak masz to do innych operacji przedstawione, ale jak dla mnie to może być coś typu:
> struct plansza{
> unsigned char white[16];
> unsigned char black[16];
> ;[/code]
> Gdzie spokojnie możesz zapisać na starszych 4 bitach X, na młodszych Y, same zera dają pionek poza planszą.
Nie chodzi o to że nie można spokojnie trzymać :) Chodzi o to, że na reprezentacji planszy trzeba wykonywać
wiele różnych operacji. Jeśli strukturę dopasujemy do jednej operacji, to będzie gorzej dopasowana do drugiej.
Poza tym ta wersja którą teraz robię, docelowo ma efektywnie działać na szachach samouczących, a nie
na teście perft. Test perft to takie zadanie epizodyczne przy okazji :)
> Wtedy masz 32 bajty, które swobodnie możesz porównać przez memcmp.
Ale np. testowanie szacha i znajdowanie ruchów trwa wolniej niż na strukturze którą
mam obecnie - tu przyspieszysz, a tam zwolni.
> Jedyny ew. mankament to pionki, które musiałbyś osobno sprawdzać, bo są traktowane indywidualnie. Inne podejście może być takie:
> struct plansza{
> unsigned char field[4][8];
> };
> wtedy masz w jednym bajcie dwa pola (możesz je traktować liniowo) - wtedy reprezentujesz sobie najstarszy bit zapisu jako
> kolor, pozostałe 3 jako rodzaj figury (król, królowa, goniec, koń, wieża, pion) - jedna wartość niewykorzystana.
> Wtedy masz bardzo wygodne porównywanie przez memcmp.
No tak, ale jak efektywnie na tym wykonywać wszystkie pozostałe operacje? Operacji jest sporo: sprawdzanie
czy jest szach, sprawdzanie czy ruch jest legalny (po ruchu nie może być szacha), sprawdzanie czy nie próbuje
się bić króla, wyszukiwanie gdzie stoi król, zliczenie ile jest w sumie figur, posortowanie ruchów począwszy
od bić, sprawdzenie czy pozycja na planszy nie powtórzyła się trzy razy, sprawdzenie czy jest remis po wykonaniu
50 ruchów bez bicia, promocji i roszady...
> To masz wersje 32 bajtowe. Z mniejszych, gdzie ma się pełną informację na pewno wykonalna jest 28 bajtowa jeszcze.
Pewnie da się jeszcze mniejszą zrobić niż 28 bajtów, ale to się nie opłaci.
> Wydaje mi się, że koszt operowania na tak przygotowanej planszy jest mniejszy niż liczenie funkcji skrótu.
Mam specjalną funkcję skrótu, jej koszt jej obliczenia to... nie wiem ile... może 1% wykonania całego programu.
Używam kluczy zobrosta, można je obliczać "przyrostowo".
> W sumie to takie gdybanie, bo jak się nie widzi kodu to ciężko cokolwiek doradzić.
A jak się widzi kod, to można jedną rzecz przyspieszyć, a 10 innych spowolni :D
> To teraz tak, hash ma 20 bajtów z tego co zrozumiałem.
Hash ma 8 bajtów. Dodatkowo jest 8 bajtów na ilość węzłów i był 1
bajt na crc. Teraz mam 8 bajtów na crc. Czyli jeden wpis to w
nowej wersji 24 bajty.
> Możesz spróbować jakoś ponumerować układy po prostu. Masz maksymalnie zajęte 32 pola z 64, to masz 64 po 32 = 1,8e+18 układów zajętych pól.
> Masz 13 rodzajów figur (6*2+1 -> jedynka, bo może pole być puste). Więc masz 13^32 * 1,8e+18, z tego logarytm dwójkowy wychodzi ~179, więc
> musisz poświęcić co najmniej 23 bajty na każdy układ. Można teoretycznie zbić jeszcze to trochę, bo król może występować tylko raz, królowa tylko raz,
> więc zamiast 13^32 wyjdzie jakieś 13*12*11*10 (króle i królowe), dalej *9*9*8*8 (gońce), *7*7*6*6 (konie), *5*5*4*4 (wieże), *3^8 * 2^8 (pionki) * 2^30 (bo każdy
> może występować lub nie z wyjątkiem króli), wtedy masz te swoje upragnione 20 bajtów (158 bitów). W rzeczywistej grze liczba układów jeszcze jest mniejsza, bo
> niektóre sytuacje nigdy nie zajdą, ale liczenie tego to... Tak więc teoretycznie te 20 bajtów może Ci wystarczyć, ale nie zdziwiłbym się, gdyby Twoja funkcja skrótu
> dawała tę samą wartość dla dwóch różnych układów (zrobienie takiej idealnej nie jest wbrew pozorom takie proste).
Najprościej i najefektywniej z wszystkich znanych mi sposób działają klucze zobrista. Używam 64bitowej funkcji skrótu, to kolosalna ilość 2^64 różnych
wartości, ale być może okaże się za mało. Mój program właśnie dał złą wartość - może to z powodu zbyt krótkiej funkcji skrótu. Jeśli okaże się za mało, to dam 128 bitów.
Wpis w hash-table z rozmiaru 24bajtów zwiększy się do 32 bajtów - czyli da się zapamiętać o 25% układów mniej - to poważny mankament, bo pamięć jest ważna, ale być
może nie ma innego wyjścia. Natomiast z powodu dłuższych kluczy zobrista program nie spowolni prawdopodobnie nawet o 1% - to naprawdę efektywna metoda.
Pozdrawiam serdecznie
Cytat: krzyszp w 25 Maj 2013, 22:22
Za to u mnie po prawie dobie wyskoczyło "Killed"... :(
Zakładam, że to z powodu braku wolnej pamięci (serwer wszedł mi ostro na swap'a).
Edit:
Spróbowałem odpalić na Virtualbox'ie skrytp, ale niestety wysypał się z komunikatem (z VB) "Guru meditation" ;)
Masakra, czyli program cały czas jest niestabilny. Jutro zapodam nową wersję.
Dzięki i pozdrawiam.
Cytat: Dario666 w 26 Maj 2013, 01:19
Ciekawe jak chcesz zoptymalizować obliczenia z 1160 sekund do średnio 15 sekund, czyli przyspieszyć go 77 razy. To chyba zbytni optymizm.
Otóż obecnie mój program wykonuje tyle ruchów ile... jakby to zgrabnie napisać... no tyle ile jest do wykonania w
danym poddrzewie - w programie szachowym tak właśnie trzeba. Ale w procedurze perft na jedną głębokość przed
liściem, czyli tam gdzie jest najwięcej obliczeń, nie trzeba wykonać ani
jednego ruchu - wystarczy zliczyć ile ruchów
jest tam dozwolonych i zrobić
return ilość_ruchów; - może się mylę, ale szacuję to na przyspieszenie
rzędu 20-40 razy. Do tego dochodzi zarządzanie pamięcią, po tej optymalizacji na ostatnim poziomie, może program tak
mocno przyspieszyć, że nie będzie sensu zapamiętywanie przedostatniego poziomu w wynikach częściowych - a więc
pamięć zostanie wolna dla większych głębokości - a podanie wyniku bez obliczeń na większych głębokościach
daje większe przyspieszenie niż podanie go na głębokościach mniejszych. Do tego mój program ma parametry
probe i forget - na razie nie wiem jakie są ich optymalne wartości. Do tego można ruchy na jednym poziomie wykonać
nie jeden raz, ale dwa razy. Po co dwa razy wykonywać to samo? Ano po to, żeby sprawdzić dla których ruchów jest
zapamiętany wynik i je od razu podać, bo jak się wykona najpierw inne, to zapamiętany wynik może zostać zamazany....
Niby takie sobie proste przeszukiwanie drzewa gry... ale technik jest dużo i każda może coś przyspieszyć. Jak mi tylko czas
pozwoli to myślę że jest realne przyspieszenie nawet do 200 razy. No i czasy do szacowań wziąłem z laptopa i3 - a to nie
jest zbyt mocny komputer :)
> Znalazłem na stronach szachowych dość obszery wywód z szacowaniem ilości możliwych rozstawień figur i wynik brzmiał 10
40.
> Patrząc na to, że funkcja haszująca 160-bitowa ma 1,46*10
48 różnych wyników, to może się okazać zbyt mało i kolega Karlik może
> mieć rację, że hasze będą się powtarzać dla rózych ustawień.
Niewykluczone że ma rację. Do tej pory nigdy się nie spotkałem z taką sytuacją, aby klucz 64bitowy był za krótki. Być może przy obliczeniach
rozproszonych będzie potrzebny klucz 128 bitowy, a może jeszcze większy - na razie tego nie wiem. Natomiast jestem pewny, że mogę
długość klucza zwiększać aż wystarczy.
> Zasadnicze pytanie jest takie: po co to w ogóle mamy liczyć? Dla samego przeliczenia?
Nie rozumiem. To czyli co? W ogóle całe zadanie? Byłem zachęcany/ponaglany żeby zrobić
jakiś projekt do obliczeń rozproszonych. Na szybko nic lepszego nie mogę zaoferować niż
to zadanie - więc głównie po to.
Taki projekt jest w jakimś małym stopniu prestiżowy, od dawna pasjonaci szachów zastanawiają
się ile jest możliwych układów. Nie da się odpowiedzieć na to pytanie w ogóle, ale można podać
ile jest układów do określonej głębokości. Wielu ludzi liczyło to do 12 ruchów i się chwaliło że
się udało. Nikt dzięki temu projektowi zdrowszy lub bogatszy nie będzie, ale szczęśliwszy może tak :)
> Jakie jest cel
Np. taki może być cel:
Podać dokładnie jaką wartość zwraca funkcja perft dla głębokości do 16 ruchów włącznie.
Podać bardzo dobre oszacowania funkcji perft do 24 ruchów włącznie.
> i jakie dane chcemy zgromadzić, aby można je było wykorzystać do dalszych badań.
Danych raczej nie chcemy gromadzić. Chcemy znać rozwiązanie i chcemy dojść do
niego w najszybszym czasie.
> Według mnie metoda z haszami nie jest trafiona, bo nie możemy z niej odczytać jakie jest rzeczywiste ustawienie figur na szachownicy.
Nie potrzeba odczytywać rzeczywistego układu, przynajmniej teraz program działa i nie odczytuje tego.
Pozdrawiam
Ja widzę dość zaawansowany problem z funkcją skrótu. Przecież nawet dając hash o długości 128 bitów lub więcej i tak masz teoretyczną szansę, że coś się powtórzy. Prawdopodobieństwo tego być może jest skrajnie niskie ale jednak jest.
Do takiego zliczania potrzebna jest aplikacja zwracająca zawsze w 100% poprawny wynik.
Chodziło mi o to, żeby można było wykorzystać w przyszłości uzyskane wyniki do obliczeń na większą głębokość, a nie liczyć znowu od początku.
Druga sprawa dotyczy hashy. NIe wiem czy spotkałeś się kiedyś z "paradoxem urodzin"... Po krótce chodzi o to, że prawdopodobieństwo znalezienia 2 osób urodzonych tego samego dnia wśród grupy 366 osób jest równe 100%. Wydawałoby się, że aby uzyskać prawdopodobieństwo równe 50% potrzeba grupy 183 osób. Nic bardziej błędnego. Do tego wystarczy grupa jedynie 23 osób!
Ten problem wykorzystywany jest do oszacowania ile można wykonać hashy kluczem o określonej długości, aby wystąpiła kolizja (ten sam hash). Przyjmuje się, że prawdopodobieństo 10-15 jest najwyższym jakie można zaakceptować, aby być pewnym, że kolizja nie wystąpi - notabene na tym bazują funkcje korekcji błędów dysków HDD, CD i DVD. Przy funkcji mieszającej 64-bitowej wystarczy wyznaczyć tylko 190 hashy, aby przekroczyć to prawdopodobieństwo!!! Przy funkcji 128-bitowej jest to 820*109, a przy 256-bitowej to 15*1030. Dlatego właśnie teraz do podpisu elektronicznego stosuje się hashe conajmniej 256-bitowe.
Myślę, że powinieneś zastanowić się na zastosowaniem hashy 256-bitowych, żeby nikt nie podważył wyniku obliczeń. Lecz to już 32 bajty i nie wiem czy nie lepiej byłoby zakodować każdą figuę (jest ich przecież tylko 6) na 3 bitach i pamiętać 64 pola po 3 bity, co daje tylko 24 bajty. Porówanie takiej struktury wymaga w SIMD tylko kilku instrukcji maszynowych.
Cytat: Rysiu w 26 Maj 2013, 10:31
Ja widzę dość zaawansowany problem z funkcją skrótu. Przecież nawet dając hash o długości 128 bitów lub więcej i tak masz teoretyczną szansę, że coś się powtórzy. Prawdopodobieństwo tego być może jest skrajnie niskie ale jednak jest.
Do takiego zliczania potrzebna jest aplikacja zwracająca zawsze w 100% poprawny wynik.
Z tego co wiem, wszyscy liczą takie zadania na funkcji skrótu. Ale skoro mnie uczulacie, to:
Po pierwsze przebadamy sprawę. Dam 40 bitów, potem 41, 42 itd. Zobaczymy jaka długość
wystarcza do jakiej głębokości. Z tego co pamiętam, 56bitów do jedno-komputerowych
zastosowań wystarczało w zupełności, ale sprawdzimy to porządnie jeszcze raz.
Po drugie zawsze może znaleźć się ktoś nieuczciwy i podesłać nam błędny wynik, więc
obliczenia trzeba weryfikować. Więc z każdym podzadaniem będziemy wysyłać inną
funkcję skrótu. Wydaje się skrajnie mało prawdopodobne, żeby na dwóch-trzech błędnych
funkcjach skrótu uzyskać dwa-trzy razy takie same wyniki.
------------------------------------------------------------------------------------------------------------------------------
Sprawdzam wpływ parametrów probe i forget na szybkość obliczeń.
Wyniki na laptopie i3:
threadMemPerft 9 4 200000000 1 0 nodes:2439530234167 time:3264
threadMemPerft 9 4 200000000 2 0 nodes:2439530234167 time:2789
threadMemPerft 9 4 200000000 3 0 nodes:2439530234167 time:2647
threadMemPerft 9 4 200000000 4 0 nodes:2439530234167 time:2598
threadMemPerft 9 4 200000000 5 0 nodes:2439530234167 time:2575
threadMemPerft 9 4 200000000 6 0 nodes:2439530234167 time:2566
threadMemPerft 9 4 200000000 7 0 nodes:2439530234167 time:2564
threadMemPerft 9 4 200000000 8 0 nodes:2439530234167 time:2564
Widzę że kombinując z tymi parametrami można uzyskać spory zysk.
Na innych platformach sprzętowych może być inny koszt odstępu do
pamięci, więc ciekawy jestem czy będzie powtarzalność wyników.
Jakby ktoś chciał pomóc, to przesyłam przykładowy skrypt. Parametry:
mem - pamięć
thr - ilość wątków
depth - głębokość przeszukiwania
Jak je ustawiać, chyba już wiadomo, jak nie, to pytajcie.
Natomiast dwa ostatnie parametry (probe i forget) trzeba
wpisać w każdym poleceniu inne. Najlepiej gdy jeden
z tych dwóch parametrów wpisujemy na stałe, a drugi
zmieniamy z jakimś skokiem.
Parametr drugi od końca ma sensowne wartości w przedziale
od 1 do około 20-30. Przyjmuje tylko wartości całkowite.
Parametr drugi może przyjmować dowolne wartości
całkowite z przedziału od 0 aż do 2^64-1.
Można np. parametr pierwszy wpisać na stałe, może równać się
powiedzmy 4, a pod parametr drugi można podstawić jakieś
mocno rozrzucone liczby.
Np.
4 0
4 1
4 5
4 25
4 125
4 625
4 10000
4 100000
4 1000000
4 10000000
Można zrobić odwrotnie, można drugi parametr pozostawić stały, a zmieniać
tylko pierwszy, np. tak:
1 1000000
2 1000000
3 1000000
4 1000000
5 1000000
6 1000000
7 1000000
8 1000000
Poniżej kod którego ja użyłem. Wyniki trafią do pliku out.txt
#!/bin/sh
mem=200000000
thr=4
depth=9
(
echo threadMemPerft $depth $thr $mem 1 0
echo quit
) | ./perft >> out.txt
(
echo threadMemPerft $depth $thr $mem 2 0
echo quit
) | ./perft >> out.txt
(
echo threadMemPerft $depth $thr $mem 3 0
echo quit
) | ./perft >> out.txt
(
echo threadMemPerft $depth $thr $mem 4 0
echo quit
) | ./perft >> out.txt
(
echo threadMemPerft $depth $thr $mem 5 0
echo quit
) | ./perft >> out.txt
(
echo threadMemPerft $depth $thr $mem 6 0
echo quit
) | ./perft >> out.txt
(
echo threadMemPerft $depth $thr $mem 7 0
echo quit
) | ./perft >> out.txt
(
echo threadMemPerft $depth $thr $mem 8 0
echo quit
) | ./perft >> out.txt
------------------------------------------------------------------------------------------------------------------------------
W załączniku najnowsza wersja programu.
Cytat: Dario666 w 26 Maj 2013, 12:43
Chodziło mi o to, żeby można było wykorzystać w przyszłości uzyskane wyniki do obliczeń na większą głębokość, a nie liczyć znowu od początku.
Teraz rozumiem. Myślałem nad tym kiedyś przez pewien czas i szukałem jakieś metody/algorytmu. Nawet znalazłem taką możliwość, ale
doszedłem do wniosku, że to się nie opłaci. Wątpię aby to było możliwe, ale jakby ktoś mi podsunął taki algorytm, to oczywiście spróbujemy.
Cytat: Dario666 w 26 Maj 2013, 12:43
Druga sprawa dotyczy hashy. NIe wiem czy spotkałeś się kiedyś z "paradoxem urodzin"...
Tak, znam termin paradoksu dnia urodzin. Pomimo tego paradoksu do tej pory nigdy nie spotkałem się z
taką sytuacją, aby klucze 64-bitowe nie zadziałały w zastosowaniach jedno-komputerowych. Nawet przy
liczeniu przez 2 tygodnie na 6 rdzeniach równolegle.
Cytat: Dario666 w 26 Maj 2013, 12:43
Po krótce chodzi o to, że prawdopodobieństwo znalezienia 2 osób urodzonych tego samego dnia wśród grupy 366 osób jest równe 100%.
Przy założeniu że do grupy trafiły losowe osoby :)
Cytat: Dario666 w 26 Maj 2013, 12:43
Wydawałoby się, że aby uzyskać prawdopodobieństwo równe 50% potrzeba grupy 183 osób. Nic bardziej błędnego. Do tego wystarczy grupa jedynie 23 osób!
No tak, ale ilość różnych wartości funkcji skrótu też rośnie wykładniczo z każdym bitem.
Może spróbujesz oszacować teoretyczną ilość bitów?
Klient musi przeszukać na głębokość powiedzmy 9 ruchów. Powiedzmy że
unikalnych węzłów jest 28*28*16^7 (wszystkich jest 210453397504). Klient może w RAM
przechować około 200mln kluczy. Ja bym to oszacował jako paradoks dnia
urodzin dla roku który ma 2^64 albo 2^128 dni, dla grupy która ma 200 mln
osób a potem w grupie jedna osoba zmienia się 28*28*16^7 razy.
Uzyskamy prawdopodobieństwo błędnego wyniku dla jednego klienta.
Cytat: Dario666 w 26 Maj 2013, 12:43
Ten problem wykorzystywany jest do oszacowania ile można wykonać hashy kluczem o określonej długości, aby wystąpiła kolizja (ten sam hash). Przyjmuje się, że prawdopodobieństo 10-15 jest najwyższym jakie można zaakceptować, aby być pewnym, że kolizja nie wystąpi - notabene na tym bazują funkcje korekcji błędów dysków HDD, CD i DVD. Przy funkcji mieszającej 64-bitowej wystarczy wyznaczyć tylko 190 hashy, aby przekroczyć to prawdopodobieństwo!!! Przy funkcji 128-bitowej jest to 820*109, a przy 256-bitowej to 15*1030. Dlatego właśnie teraz do podpisu elektronicznego stosuje się hashe conajmniej 256-bitowe.
Programy szachowe (wszystkie) działają na funkcji 64bitowej. Mój program też podaje wyniki dla głębokości 9
(powiedzmy że to 28*28*16^7 unikalnych węzłów) przy funkcji 64 bitowej.
Cytat: Dario666 w 26 Maj 2013, 12:43
Myślę, że powinieneś zastanowić się na zastosowaniem hashy 256-bitowych, żeby nikt nie podważył wyniku obliczeń.
Na pewno wezmę to pod uwagę. W poście powyżej już opisałem dokładnie jak zbadamy sprawę. Wyniki
obliczeń i tak będziemy musieli zweryfikować. Więc można dać każde zadanie do liczenia na dwóch
różnych funkcjach 128 bitowych. Jeśli wyniki będą różne, to się policzy na trzeciej funkcji skrótu. Jeśli
nadal będą różne, to się zastosuje funkcje 192 bitowe.
Cytat: Dario666 w 26 Maj 2013, 12:43
Lecz to już 32 bajty i nie wiem czy nie lepiej byłoby zakodować każdą figuę (jest ich przecież tylko 6) na 3 bitach i pamiętać 64 pola po 3 bity, co daje tylko 24 bajty. Porówanie takiej struktury wymaga w SIMD tylko kilku instrukcji maszynowych.
Instrukcji SIMD nie ma na każdej maszynie i mogą być różnice pomiędzy AMD i Intelem. Zamiana mojej szachownicy na
liniowe dane to dość skomplikowana procedura. Mniej/więcej coś takiego:
i=0;
for( j=2 ; j<10 ; j++ )
for( k=3 ; k<11 ; k++ )
lin[i++] = board[j*10+k];
lin[i++] = czy_jest_przyzwolenie_na_bicie_w_przelocie;
for( j=0 ; j<4 ; j++ )
lin[i++] = przyzwolenia_roszad[ idx[j] ];
lin[i++] = która_strona_ma_ruch
Czyli do każdego węzła dojdzie 70 pętli. Jak dane skompresujemy, to jeszcze
dojdą operację bitowe and i or. Spowolni to całość z 10-30 razy.
Istnieje jeszcze inne rozwiązanie... można trzymać dwie reprezentacje
(a właściwie trzy, bo drugą wyspecjalizowaną trzymam już w celu przyspieszenia
testów szacha) jednocześnie i aktualizować ją po każdym ruchu...
Tak czy inaczej, na pewno starannie podejdę do sprawy zapamiętywania
danych częściowych - nie możemy ryzykować błędnych wyników.
Pozdrawiam
U mnie program po kilkunastu godzinach się zakończył... przedwcześnie
#!/bin/sh
(
echo threadMemPerft 1 5 100000000 4 0
echo threadMemPerft 2 5 100000000 4 0
echo threadMemPerft 3 5 100000000 4 0
echo threadMemPerft 4 5 100000000 4 0
echo threadMemPerft 5 5 100000000 4 0
echo threadMemPerft 6 5 100000000 4 0
echo threadMemPerft 7 5 100000000 4 0
echo threadMemPerft 8 5 100000000 4 0
echo threadMemPerft 9 5 100000000 4 0
echo threadMemPerft 10 5 100000000 4 0
echo quit
) | ./perft >> out.txt
Wyniki:
nodes:20 time:2
nodes:400 time:0
nodes:8902 time:1
nodes:197281 time:1
nodes:4865609 time:1
nodes:119060324 time:2
nodes:3195901860 time:10
nodes:84998978956 time:111
nodes:2439530234167 time:2489
Cytat: Szopler w 26 Maj 2013, 14:44
U mnie program po kilkunastu godzinach się zakończył... przedwcześnie
Czyli program ma jakiś dziwny błąd, który uaktywnia się dopiero przy
głębokości 10 ruchów i to tylko na niektórych komputerach :/
Cóż, najwyraźniej czeka mnie żmudny proces debugowania.
Moja kolejna prośba odnośnie testów jest kilka postów wyżej:
http://www.boincatpoland.org/smf/przetwarzanie-rozproszone/to-co-bawimy-sie-d/msg225243/#msg225243
Jakby nie chciało Ci się czytać całego posta, to prośba zaczyna
się tam od słów: "Jakby ktoś chciał pomóc" :D
Pozdrawiam i dziękuję.
Cytat: Szopler w 26 Maj 2013, 14:44
U mnie program po kilkunastu godzinach się zakończył... przedwcześnie
Czyli program ma jakiś dziwny błąd, który uaktywnia się dopiero przy
głębokości 10 ruchów i to tylko na niektórych komputerach :/
Cóż, najwyraźniej czeka mnie żmudny proces debugowania.
Moja kolejna prośba odnośnie testów jest kilka postów wyżej:
http://www.boincatpoland.org/smf/przetwarzanie-rozproszone/to-co-bawimy-sie-d/msg225243/#msg225243
Jakby nie chciało Ci się czytać całego posta, to prośba zaczyna
się tam od słów: "Jakby ktoś chciał pomóc" :D
Pozdrawiam i dziękuję.
P.S.
Oczywiście testujemy tylko najnowszej wersji :)
Cytat: mariotti w 26 Maj 2013, 13:43Tak, znam termin paradoksu dnia urodzin. Pomimo tego paradoksu do tej pory nigdy nie spotkałem się z
taką sytuacją, aby klucze 64-bitowe nie zadziałały w zastosowaniach jedno-komputerowych. Nawet przy liczeniu przez 2 tygodnie na 6 rdzeniach równolegle.
Zauważ, że jak na razie mówisz, że tak robią programy szachowe i może to być racja, nawet do głębokości tych 9 czy nawet 13 ruchów tak funkcja skrótu może wystarczyć (chociaż ciężko to zwryfikować). Jednak nawet sam wspomniałeś o tym, że to jest drzewo i liczba węzłów rośnie wykładniczo i to bardzo szybko. Nawet jeśli na każdym kolejnym poziomie będzie 20 razy więcej węzłów to samo zapisanie tego wymaga o 5 bitów więcej, nie wspominając w ogóle o prawdopodobieństwie. Tak więc do 12 poziomu spokojnie może Ci wystarczyć 64 bity na samo zapisanie numeru układu, a gdzie tu mówić o jakimkolwiek porównywaniu? Poza tym komputer do grania nie potrzebuje wiedzy pewnej, jak przeoczy któreś ustawienie to praktycznie nic się nie dzieje, co najwyżej lekko mu spadnie możliwość wygranej, Ty bierzesz się za coś co ma być wiedzą pewną/naukową, tutaj naprawdę każda pojedyncza wartość ma znaczenie jeśli chcesz być brany poważnie (albo inaczej: żeby wyniki ciężko było podważyć).
CytatNo tak, ale jak efektywnie na tym wykonywać wszystkie pozostałe operacje? Operacji jest sporo: sprawdzanie czy jest szach, sprawdzanie czy ruch jest legalny (po ruchu nie może być szacha), sprawdzanie czy nie próbuje się bić króla, wyszukiwanie gdzie stoi król, zliczenie ile jest w sumie figur, posortowanie ruchów począwszy od bić, sprawdzenie czy pozycja na planszy nie powtórzyła się trzy razy, sprawdzenie czy jest remis po wykonaniu 50 ruchów bez bicia, promocji i roszady...
Do samych obliczeń spokojnie możesz mieć równolegle obie wersje. Zauważ, że w tej chwili bierzesz pod uwagę konieczność wydłużania funkcji hashującej w nieskończoność, więc chyba prościej zapamiętywać cały układ. Co do ostatniego to jak dla mnie zupełnie bezsensowne sprawdzenie. Żeby było 50 ruchów to musiałbyś mieć drzewko na głębokość 50, jak na razie widzę rozważamy max. 20 ruchów do przodu. Poza tym ja to proponuję jako sposób zapisu układu na potrzeby porównań (już do samego drzewka zamiast hasha - w samym hashu też przecież nie sprawdzasz położenia króla ani nic podobnego), i tak musisz docelowo tę zmianę wprowadzić w funkcji skrótu (zrobić dwa xory przykładowo), tutaj masz nawet łatwiej, bo tylko robisz proste przypisanie albo nowej wartości pola do figury (lub dwóch przy biciu lub roszadzie) albo nowej figury do dwóch pól. Uwzględnienie promocji figury w wersji black/white to może być po prostu najstarszy bit.
CytatLecz to już 32 bajty i nie wiem czy nie lepiej byłoby zakodować każdą figuę (jest ich przecież tylko 6) na 3 bitach i pamiętać 64 pola po 3 bity, co daje tylko 24 bajty.
Nie do końca, masz 12 figur (musisz osobno traktować białe i czarne), więc masz 4 bity na pole, czyli łącznie 32 bajty ;)
Cytat: Karlik w 26 Maj 2013, 15:44
Zauważ, że jak na razie mówisz, że tak robią programy szachowe i może to być racja, nawet do głębokości tych 9 czy nawet 13 ruchów tak funkcja skrótu może wystarczyć (chociaż ciężko to zwryfikować).
Wszystko się zgadza, ale żeby nasze wyniki były poważnie traktowane, to też musimy się zabezpieczyć
przed osobami, które złośliwie podeślą błędne wyniki. Więc można raz policzyć na funkcji 128
bitowej i drugi raz na zupełnie (naprawdę zupełnie) innej funkcji też o długości 128 bitów. Jeśli
wynik będzie błędny, to jest skrajnie mało prawdopodobne, że
błąd na dwóch zupełnie różnych
funkcjach skrótu będzie
taki sam. Z tą techniką (chyba) upieczemy pięć pieczeni na jednym ogniu:
1) szybkie porównywanie
2) oszczędność pamięci
3) zabezpieczenie przed nieuczciwymi osobami
4) błąd ram, błąd transferu sieci
5) jest już gotowy program, nie trzeba nic dopisywać.
Cytat: Karlik w 26 Maj 2013, 15:44
Jednak nawet sam wspomniałeś o tym, że to jest drzewo i liczba węzłów rośnie wykładniczo i to bardzo szybko.
Nawet jeśli na każdym kolejnym poziomie będzie 20 razy więcej węzłów to samo zapisanie tego wymaga o 5 bitów więcej, nie wspominając w ogóle o prawdopodobieństwie.
Jak poprawnie oszacować to prawdopodobieństwo...
Przypuśćmy że na depth=16 jest 1E+19
różnych układów, czyli 2^63.
Użyjemy 128 bitów. Czyli jeden układ przypada na 2^65 wartości
funkcji skrótu... niestety w tej chwili nie wiem jak dalej pójść tą drogą, może
ktoś dokończy?
Może inaczej: W komputerze jest zapamiętanych około 10^8 = 2^27 układów. Funkcja
skrótu ma 2^128 wartości. Czyli na jeden wpis w pamięci przypada 2^101 wartości
funkcji skrótu. Czyli prawdopodobieństwo kolizji wynosi 1 / 2^101. Prawdopodobieństwo
braku kolizji to 1 - 1 / 2^101. Chcemy znać prawdopodobieństwo braku kolizji w 2^65
prób. Czyli mamy ( 1 - 1 / 2^101 ) ^ ( 2^65 )
Wolfram twierdzi, że to dziesięć dziewiątek po przecinku.
http://www.wolframalpha.com/input/?i=%281+-+1+%2F+2^101%29^%282^65%29
Do tego każde obliczenia przeprowadzimy dwa razy na zupełnie innych funkcjach skrótu.
Proszę prześledź moje rachunki, może się gdzieś pomyliłem. Ale jak nie znajdziesz
błędu, to znaczy, że tak właśnie zrobimy i każdy będzie nas traktował poważnie.
Cytat: Karlik w 26 Maj 2013, 15:44
Tak więc do 12 poziomu spokojnie może Ci wystarczyć 64 bity na samo zapisanie numeru układu, a gdzie tu mówić o jakimkolwiek porównywaniu? Poza tym komputer do grania nie potrzebuje wiedzy pewnej, jak przeoczy któreś ustawienie to praktycznie nic się nie dzieje, co najwyżej lekko mu spadnie możliwość wygranej, Ty bierzesz się za coś co ma być wiedzą pewną/naukową, tutaj naprawdę każda pojedyncza wartość ma znaczenie jeśli chcesz być brany poważnie (albo inaczej: żeby wyniki ciężko było podważyć).
Jest jeszcze jeden powód z którego będą nas traktowali poważnie. Jeśli 128 bitów okaże się
za mało, to szybko będą wychodziły różne wyniki dla tych samych układów przy użyciu różnych
funkcji skrótu. Od razu wyjdzie że 128 bitów to za mało i zwiększymy do 196 lub 256.
Cytat: Karlik w 26 Maj 2013, 15:44
Do samych obliczeń spokojnie możesz mieć równolegle obie wersje. Zauważ, że w tej chwili bierzesz pod uwagę konieczność wydłużania funkcji hashującej w nieskończoność, więc chyba prościej zapamiętywać cały układ.
Oj nie w nieskończoność. Jeśli dobrze oszacowałem, to 128 bitów da prawdopodobieństwo 99.99999999%, że
wynik będzie poprawny. A my policzymy każdy układ na dwóch różnych funkcjach skrótu.
Cytat: Karlik w 26 Maj 2013, 15:44
Co do ostatniego to jak dla mnie zupełnie bezsensowne sprawdzenie. Żeby było 50 ruchów to musiałbyś mieć drzewko
na głębokość 50, jak na razie widzę rozważamy max. 20 ruchów do przodu.
Tak, ale mój program docelowo jest stworzony do innego zadania niż test perft. Test perft to
coś co robię tylko przy okazji, więc musi mieć zaimplementowaną (właściwie to już ma) regułę
50 ruchów. Oczywiście po ostatnich optymalizacjach zakomentuję regułę 50 posunięć i potrójne
powtórzenie. Ale struktury danych nie napiszę od nowa, tak żeby nie uwzględniała tej reguły -
po prostu nie mam na to tyle czasu.
Cytat: Karlik w 26 Maj 2013, 15:44
Poza tym ja to proponuję jako sposób zapisu układu na potrzeby porównań (już do samego drzewka
zamiast hasha - w samym hashu też przecież nie sprawdzasz położenia króla ani nic podobnego), i tak
musisz docelowo tę zmianę wprowadzić w funkcji skrótu (zrobić dwa xory przykładowo), tutaj masz
nawet łatwiej, bo tylko robisz proste przypisanie albo nowej wartości pola do figury
(lub dwóch przy biciu lub roszadzie) albo nowej figury do dwóch pól. Uwzględnienie promocji figury w
wersji black/white to może być po prostu najstarszy bit.
Zgadza się, można wprowadzić dodatkową reprezentacje specjalnie na potrzeby hash i powinno działać
szybko. Jednak wersja z xor-ową funkcją skrótu jest już gotowa - nic nie muszę robić, ewentualnie
zwiększę jej długość. Program będzie szybciej gotowy.
Cytat
Lecz to już 32 bajty i nie wiem czy nie lepiej byłoby zakodować każdą figuę (jest ich przecież tylko 6) na 3 bitach i pamiętać 64 pola po 3 bity, co daje tylko 24 bajty.Nie do końca, masz 12 figur (musisz osobno traktować białe i czarne), więc masz 4 bity na pole, czyli łącznie 32 bajty ;)
Czyli o 16 bajtów więcej niż klucz 128 bitowy ;)
16 bajtów to niby mało... ale widzę że program działa
wyraźnie szybciej z każdym, nawet małym zwiększeniem
pamięci. A weryfikować i tak i tak trzeba.
Pozdrawiam
Wcześniej odpaliłem:
threadMemPerft 10 8 250000000 8 1000000
Uzyskałem błędny wynik 69352859710032 w czasie 63547 sekund.
Do programu dodałem (chyba) lepszą funkcję skrótu (nadal 64bity) i
lepszą sumę crc (tą do sprawdzania czy wątki nie zepsuły danych).
Wydałem komendę
threadMemPerft 10 8 250000000 1 0
i uzyskałem tym razem poprawny wynik 69352859712417 w znacznie
szybszym czasie 41515 sekund.
Program u mnie nigdy się nie wywalił, zagadką jest dla mnie, dlaczego
wywala się u Was :/ Myślę że wkrótce się wyjaśni wszystko.
Teraz odpalę takie polecenie:
threadMemPerft 10 8 250000000 8 0
Zobaczymy czy wynik będzie dobry i czy coś przyspieszy
Zachęcam, odpalcie nową wersję u siebie jeszcze raz :)
Pozdrawiam
[edit]
Rozejrzałem się po sieci i widzę że ktoś to zadanie liczył na 4 komputerach w 85h,
ktoś inny w 17 dni. Mój program policzył w 12h, a jest jeszcze przed optymalizacją.
Program odpalony za pomocą Twojego skryptu wywala u mnie std:bad_alloc. Po zmniejszeniu przydzielonej pamięci (do 50000000) wystartował, aczkolwiek zakładam znaczne wydłużenie operacji.
Komputer mocno obciążony (akurat wildlife dał próbki), dodatkowo podsystem mocno obciążony operacjami dyskowymi MySQL. Przypominam, że procesor to q6600 na standardowych taktowaniach i Ubuntu64 bit.
Cytat: krzyszp w 26 Maj 2013, 20:48
Program odpalony za pomocą Twojego skryptu wywala u mnie std:bad_alloc. Po zmniejszeniu przydzielonej pamięci (do 50000000) wystartował, aczkolwiek zakładam znaczne wydłużenie operacji.
Komputer mocno obciążony (akurat wildlife dał próbki), dodatkowo podsystem mocno obciążony operacjami dyskowymi MySQL. Przypominam, że procesor to q6600 na standardowych taktowaniach i Ubuntu64 bit.
Dzięki, zobaczymy czy tym razem obejdzie się bez błędów.
Pozdrawiam
Cytat: mariotti w 26 Maj 2013, 19:08
Przypuśćmy że na depth=16 jest 1E+19 różnych układów, czyli 2^63.
Użyjemy 128 bitów. Czyli jeden układ przypada na 2^65 wartości
funkcji skrótu... niestety w tej chwili nie wiem jak dalej pójść tą drogą, może
ktoś dokończy?
Ogólnie paradoks urodzin. Nie weryfikowałem obliczeń z wikipedii (nie mam tyle czasu i chęci), ale po podstawieniu do wzoru to żeby prawdopodobieństwo powtórzenia przekroczyło 50% to dla 128-bitowej funkcji skrótu potrzeba 2e+19 układów.
Cytat: Karlik w 26 Maj 2013, 21:43
Ogólnie paradoks urodzin. Nie weryfikowałem obliczeń z wikipedii (nie mam tyle czasu i chęci), ale po podstawieniu do wzoru to żeby prawdopodobieństwo powtórzenia przekroczyło 50% to dla 128-bitowej funkcji skrótu potrzeba 2e+19 układów.
W pamięci komputera mamy jednorazowo małą pulę układów, wynosi ona np. 1E+8.
Nie może być konfliktu w ramach puli, we wszystkich mogą zdarzać się konflikty bez
szkody dla wyniku.
Pozdrawiam
Spiszmy postępy w pracach dotyczących wydajności :)
----------------------------------------------------------------------------------------
Procesor | polecenie | wynik | czas
----------------------------------------------------------------------------------------
Phenom II | threadMemPerft 10 8 250000000 8 1000000 | 69352859710032! | 63547s
Phenom II | threadMemPerft 10 8 250000000 1 0 | 69352859712417ok | 41515s
i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 0 | 69352859712417ok | 21051s
----------------------------------------------------------------------------------------
Tak więc mamy trzeci wynik dla głębokości 10 ruchów i rekordowy czas 21tys sekund.
Zważywszy że ktoś to liczył przez kilkanaście dni, to chyba niezły wynik ;-)
Program się nie wywalił, zakończył się normalnie.
Pozdrawiam
A możesz zdradzić jakie były , a jakie są teraz funkcje skrótu i CRC ;D
Wynik dla:
#!/bin/sh
mem=50000000
thr=4
depth=9
(
echo threadMemPerft $depth $thr $mem 1 0
echo quit
) | ./perft >> out.txt
(
echo threadMemPerft $depth $thr $mem 2 0
echo quit
) | ./perft >> out.txt
(
echo threadMemPerft $depth $thr $mem 3 0
echo quit
) | ./perft >> out.txt
(
echo threadMemPerft $depth $thr $mem 4 0
echo quit
) | ./perft >> out.txt
(
echo threadMemPerft $depth $thr $mem 5 0
echo quit
) | ./perft >> out.txt
(
echo threadMemPerft $depth $thr $mem 6 0
echo quit
) | ./perft >> out.txt
(
echo threadMemPerft $depth $thr $mem 7 0
echo quit
) | ./perft >> out.txt
(
echo threadMemPerft $depth $thr $mem 8 0
echo quit
) | ./perft >> out.txt
z Q6600:
nodes:2439530234167 time:6921
nodes:2439530234167 time:5976
nodes:2439530234167 time:5691
nodes:2439530234167 time:5633
nodes:2439530234167 time:5512
nodes:2439530234167 time:5551
nodes:2439530234167 time:5546
nodes:2439530234167 time:5560
Cytat: krzyszp w 27 Maj 2013, 10:11
z Q6600:
threadMemPerft $depth $thr $mem 4 0
nodes:2439530234167 time:5512
Dzięki za kolejny test :D
Czyli optymalna wartość drugiego parametru w tym teście wynosiła 4. Widzę że często najlepszą
wartością jest 4 lub 8. Mam nadzieję że to nie z powodu obciążenia komputera :)
Czy mógłbyś odpalić ten sam skrypt, ale ostatnie zera w komendzie zastąpić np. wartością 10000000 - siedem zer?
Cytat: Dario666
A możesz zdradzić jakie były , a jakie są teraz funkcje skrótu i CRC
Używam kluczy zobrista, ale wcześniej były mniej starannie generowane. Teraz
wygenerowałem całą pulę kluczy kluczy. Każdemu kluczowi dałem wartość 0x555... Czyli
w kluczach jest taka sama ilość zer i jedynek. Potem 10^7 raz zamieniałem z
sobą losowe bity (tzn losowy bit z puli a nie z jednego klucza). Mam dzięki temu
gwarancję idealnego rozkładu równomiernego - właściwie z pewnym małym wyjątkiem,
ale chyba nie ma sensu wdawać się aż w takie szczegóły. Mam pomysł jak zapewnić
aby klucze były jeszcze lepsze, ale to się sprawdzi za jakiś czas.
Funkcja do sprawdzania czy wątki nie psują sobie danych to zwykły xor (czyli tak naprawdę
nie jest to CRC, a tylko pełni taką samą rolę). Tutaj też jest lepsze rozwiązanie. Zabrzmi to
jak nonsens, ale wartość CRC (tzn jej odpowiednik) może mieć dlugość
zero bitów.
Istnieje na to pewien sposób, za jakiś czas będę go też testował i opiszę wyniki.
Dzięki i pozdrawiam
Cytat: mariotti w 27 Maj 2013, 13:58
Czy mógłbyś odpalić ten sam skrypt, ale ostatnie zera w komendzie zastąpić np. wartością 10000000 - siedem zer?
Odpaliłem, zobaczymy efekty.
Są kolejne wyniki
----------------------------------------------------------------------------------------
Procesor | polecenie | wynik | czas
----------------------------------------------------------------------------------------
Phenom II | threadMemPerft 10 8 250000000 8 1000000 | 69352859710032! | 63547s
Phenom II | threadMemPerft 10 8 250000000 1 0 | 69352859712417ok | 41515s
Phenom II | threadMemPerft 10 8 250000000 8 0 | 69352859712417ok | 30042s
i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 0 | 69352859712417ok | 21051s
i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 1000000 | 69352859712417ok | 12173s
----------------------------------------------------------------------------------------
Niby jest nowy rekord - 12tys sekund. Ciekawy jestem jaka jest losowość tych wyników.
Wątki pracują konkurencyjnie i jeden wątek czasami może zamazać ważne dane dla
drugiego wątku - ale na to też jest pewien sposób, będą kolejne benchmarki :)
Pozdrawiam
Według mnie optymalną wartością jest 5, bo pierwszy test był wykonywany dla 1, a nie dla 0. ;D
Cytat: Dario666 w 27 Maj 2013, 14:14
Według mnie optymalną wartością jest 5, bo pierwszy test był wykonywany dla 1, a nie dla 0. ;D
Racja!
Jest kolejna wersja programu. Zrobiłem eksperyment z innym algorytmem zarządzającym
pamięcią. Niestety... jak na razie nie widzę wyraźnego przyspieszenia ani spowolnienia, ale
może na większych głębokościach da się dobrać tak parametry aby lepiej działało.
Opis polecenia
Wpisujemy threadMemPerft2 i program wyświetli podpowiedź:
using: threadMemPerft2 depth max_thread cnt_packages pack_size best_size
where:
best_size<pack_size
Znaczenie parametrów:
depth - standardowo głębokość przeszukiwania
max_thread - ilość wątków
cnt_packages - ilość paczek z układami
pack_size - ilość układów w jednej paczce
best_size - ilość układów priorytetowych
Przykłady warte przetestowania dla
głębokości 9, czterech wątków i 1GB ram:
threadMemPerft2 9 4 5400000 8 1
threadMemPerft2 9 4 5400000 8 2
threadMemPerft2 9 4 5400000 8 3
threadMemPerft2 9 4 5400000 8 4
threadMemPerft2 9 4 5400000 8 5
threadMemPerft2 9 4 5400000 8 6
threadMemPerft2 9 4 5400000 8 7
threadMemPerft2 9 4 10800000 4 1
threadMemPerft2 9 4 10800000 4 2
threadMemPerft2 9 4 10800000 4 3
Dla 0.5 GB RAM można trzeci parametr zmniejszyć o połowę.
Pozdrawiam
Tak mi się teraz nasunęło: jak przechowujesz przeliczone hashe? Masz własne drzewo avl lub czerwono-czarne czy korzystasz np. z STLowego?
zapodałem na próbę na e3-1230 v2 3.3ghz:
threadMemPerft2 10 6 32400000 8 7
niech mieli...
Cytat: Karlik w 27 Maj 2013, 19:33
Tak mi się teraz nasunęło: jak przechowujesz przeliczone hashe? Masz własne drzewo avl lub czerwono-czarne czy korzystasz np. z STLowego?
Przechowywanie układów to kluczowa rzecz dla wydajności (tej liniowej, implementacyjnej).
Jest to bardzo ważne zarówno w tym programie (perft), jak i w docelowym, czyli w szachach
samouczących. Więc nie korzystam z żadnego gotowego rozwiązania - wszystko wyrzeźbiłem
ręcznie sam :D
Generalnie mam ciągłą tablicę układów. Następnie liczę adres w tej tablicy:
adres = hash % (size-probe);
Potem przeszukuję mniej/więcej tak:
for( i=0 ; i<probe ; i++ ) {
if( tablica[adres+i].key == key )
return tablica[adres+i].nodes;
Kosz tej operacji to pewnie wczytanie tego kawałka do cache, a czas pętli jest
pewnie pomijalny.
To tak w dużym uproszczeniu, bo opis ze szczegółami zająłby ze 4 strony :D
---------------------------------------------------------------------------------------------------------
W kolejnej wersji będą trzy takie tablice i w każdej inna strategia zarządzania
danymi. Strategia - czyli heurystyczne ocenienie tego, co warto pamiętać, a co
można z pamięci już usunąć.
Z niektórych oszacowań wynika, że dobra strategia zarządzania danymi dla
głębokości 16 może przyspieszyć cały proces nawet milion razy. To by znaczyło
że zadanie da się policzyć w 1 rok na 20-100 nowych komputerach. Oczywiście
mogę się mocno mylić... ale jak się nie mylę, to zaliczymy 3 rekordy pod rząd :D
Pozdrawiam
Cytat: sknd w 27 Maj 2013, 19:40
zapodałem na próbę na e3-1230 v2 3.3ghz:
threadMemPerft2 10 6 32400000 8 7
niech mieli...
Dzięki wielkie! To będzie pierwszy głęboki test nowego algorytmu :D
Pozdrawiam
U mnie też mieli.
Ciekawi mnie, że zmieniasz ilość pamięci w przedostatnim poście? Przerobiłem go.sh podając "z palca" 10800000 dla 3 dodatkowych prób...
Doszedł nowy benchmark z phenoma. Wynik poprawny, czas rekordowy jak na ten procesor.
Pomiary czasu są obarczone dużą losowością (algorytm nie jest deterministyczny), ale
raczje już widać, że korzystne wartości dla ostatniego parametru to bardzo duże liczby,
powyżej 1mln.
----------------------------------------------------------------------------------------
Procesor | polecenie | wynik | czas
----------------------------------------------------------------------------------------
Phenom II | threadMemPerft 10 8 250000000 8 1000000 | 69352859710032! | 63547s
Phenom II | threadMemPerft 10 8 250000000 1 0 | 69352859712417ok | 41515s
Phenom II | threadMemPerft 10 8 250000000 8 0 | 69352859712417ok | 30042s
i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 0 | 69352859712417ok | 21051s
i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 1000000 | 69352859712417ok | 12173s
Phenom II | threadMemPerft 10 8 250000000 8 10000000 | 69352859712417ok | 17768s
i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 10000000 | 69352859712417ok | 12092s
----------------------------------------------------------------------------------------
Pozdrawiam
P.S.
Gdy linux w poleceniu cat /proc/cpuinfo wyświetla że procesor ma 2400MHz, to co to oznacza?
Że w danej chwili procesor ma taką częstotliwość? Czy że w pełnym stresie ma tyle? Mój
Phenom był przetaktowany w dół, bo na pełnej prędkości pobierał nawet 300Wat mocy. Nie
pamiętam już, o ile go spowolniłem. Czy mogę polegać na tych 2400MHz z cpuinfo?
Cytat: krzyszp w 27 Maj 2013, 20:05
Ciekawi mnie, że zmieniasz ilość pamięci w przedostatnim poście? Przerobiłem go.sh podając "z palca" 10800000 dla 3 dodatkowych prób...
Ale kto i gdzie zmienia?
Ja mam dwa komputery, jeden mój, a drugi udostępnił mi Rysiu.
Na moim jest mniej ramu, o wpisuję 250mln układów. Na tym od Rysia jest
więcej, to wpisuję 450mln.
Są dwa algorytmy. Był threadMemPerft, a doszedł threadMemPerft2 (dwójka na końcu nazwy).
W drugim algorytmie łączna ilość układów to ilość_paczek * ilosc_układów_w_jednej_paczce.
Przykładowo:
threadMemPerft2 9 4 5400000 8 4
oznacza 5400000 * 8 = 43200000 układów = 1036800000 bajtów ram
threadMemPerft2 9 4 10800000 4 2
oznacza 10800000 * 4 = 43200000 układów = 1036800000 bajtów ram <-- tyle samo
W jednym i drugim poleceniu jest w pamięci tyle samo układów, ale mocno
zmienia się sposób zarządzania pamięcią. Chodzi o to żeby sprawdzić, czy
lepsza jest większa ilość małych paczek, czy mniejsza większych :D
Parametr ostatni decyduje o zarządzaniu w ramach jednej paczki :)
Pozdrawiam
Rozumiem. Po prostu pomyślałem, że chcesz jednym skryptem shella sprawdzić więcej parametrów na tej samej maszynie ;)
No cóż, zobaczymy, czy nie wywali się na mojej maszynie (przypominam, 4GB RAM + trochę roboty w tle).
Próbowałem jeszcze raz odpalić na wirtualce, dając 8 wątków do dyspozycji, niesety, VB się wywala... (Prawdopodobnie mam za mało pamięci, aby to sprawnie obsłużyć i jeszcze pracować na kompie).
Cytat: krzyszp w 27 Maj 2013, 20:44
Rozumiem. Po prostu pomyślałem, że chcesz jednym skryptem shella sprawdzić więcej parametrów na tej samej maszynie ;)
No cóż, zobaczymy, czy nie wywali się na mojej maszynie (przypominam, 4GB RAM + trochę roboty w tle).
Próbowałem jeszcze raz odpalić na wirtualce, dając 8 wątków do dyspozycji, niesety, VB się wywala... (Prawdopodobnie mam za mało pamięci, aby to sprawnie obsłużyć i jeszcze pracować na kompie).
Kurcze powinno działać, jak nie działa, to najbardziej sugeruje błąd w moim programie :/
Obecnie mam nadmiernie skomplikowany kod odpowiedzialny za wielowątkowość. Nie dość
że jest skomplikowany, to prawdopodobnie jest wolniejszy niż inny, całkiem prosty algorytm.
Wkrótce zaimplementuję ten prostszy - jak po tym przestanie się wywalać, to sprawa się wyjaśni, a
jak nie, to nie wiem... opracuję kolejne testy i buga w końcu znajdziemy.
Pozdrawiam
Ja jednak stawiam na problem z Virtual Box'em - przypominam, że na Q6600 pod Ubuntu, oraz u innych kolegów się nie wywala - ten problem występuje tylko pod VB...
Cytat: sknd w 27 Maj 2013, 19:40
zapodałem na próbę na e3-1230 v2 3.3ghz:
threadMemPerft2 10 6 32400000 8 7
niech mieli...
zmielił:
nodes:69352859712417 time:11709
Cytat: krzyszp w 27 Maj 2013, 22:37
Ja jednak stawiam na problem z Virtual Box'em - przypominam, że na Q6600 pod Ubuntu, oraz u innych kolegów się nie wywala - ten problem występuje tylko pod VB...
Jeśli się wywala tylko w jednym środowisku, to by dobrze wróżyło - debugowanie może
naprawdę zająć masę czasu i opóźnić start projektu.
Wkrótce wypróbujemy kolejną strategię zarządzania danymi w kliencie, czyli łącznie
sprawdzimy 3 strategie (no, chyba że mi przyjdzie do głowy kolejna). Jeśli program
nie będzie się wywalał, to sprawdzimy go jeszcze na dużej ilości różnych układów.
Jeśli nadal poda dobre wyniki i nie wywali się, to pozostanie optymalizacja. Po
optymalizacji klient będzie gotowy, a właściwie to pozostanie jeszcze przeportowanie
na windowsa.
Potem przyjdzie pora na serwer... Szacuję że serwer będzie musiał podać
100mln zadań i przyjąć tyle samo odpowiedzi. Potem drugie tyle w etapie
weryfikacji - prawdopodobnie jeden klient od razu będzie musiał pobierać
100-1000 zadań żeby nie zajeździć bazy danych na serwerze :) Przypuszczam,
że dla głębokości 14-15 serwer może być wąskim gardłem projektu, dopiero
dla głębokości 16 wąskim gardłem staną się obliczenia na klientach. Istnieje
jeszcze możliwość dostosowania serwera osobno do każdej głębokości...
Możliwości jest sporo :)
Te 100mln to na razie szacunki intuicyjne, za jakiś czas oszacuję
to metodą Monte Carlo. Po szacowaniu MC będziemy wiedzieć bardzo
dokładnie jakie będą wymagania co do serwera i ile obliczeń zajmie
cały projekt.
Małymi kroczkami da się to wydzióbać :)
Pozdrawiam
Cytat: sknd w 27 Maj 2013, 23:08
Cytat: sknd w 27 Maj 2013, 19:40
zapodałem na próbę na e3-1230 v2 3.3ghz:
threadMemPerft2 10 6 32400000 8 7
niech mieli...
zmielił:
nodes:69352859712417 time:11709
To nowy rekord :) Super, dzięki wielkie.
Uaktualniam tabelkę:
---------------------------------------------------------------------------------------------------------
Procesor | polecenie | wynik | czas | user
---------------------------------------------------------------------------------------------------------
Phenom II | threadMemPerft 10 8 250000000 8 1000000 | 69352859710032! | 63547s |
Phenom II | threadMemPerft 10 8 250000000 1 0 | 69352859712417ok | 41515s |
Phenom II | threadMemPerft 10 8 250000000 8 0 | 69352859712417ok | 30042s |
i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 0 | 69352859712417ok | 21051s |
i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 1000000 | 69352859712417ok | 12173s |
Phenom II | threadMemPerft 10 8 250000000 8 10000000 | 69352859712417ok | 17768s |
i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 10000000 | 69352859712417ok | 12092s |
e3-1230 v2 3.3ghz | threadMemPerft2 10 6 32400000 8 7 | 69352859712417ok | 11709s | sknd
--------------------------------------------------------------------------------------------------------
Czy mógłbyś sprawdzić jeszcze na tej samej maszynie takie polecenie?
threadMemPerft2 10 6 32400000 8 1
Pozdrawiam
sprawdzę, ale to już nie dziś, bo ja jednak jestem z tych, co to im szum kompa przeszkadza przy spaniu ;)
Cytat: sknd w 28 Maj 2013, 00:29
sprawdzę, ale to już nie dziś, bo ja jednak jestem z tych, co to im szum kompa przeszkadza przy spaniu ;)
Rozumiem, bo mnie też kiedyś przeszkadzał. Przyzwyczaiłem się jak sypiałem na biurku w serwerowni :)
Są dwa nowe testy.
1) Widać że nowy algorytm raczej działa gorzej (i7)
2) Zwiększanie ostatniego parametru z 10mln do 50mln nie zmieniło czasów (Phenom)
Widocznie to pierwsze podejście do zapamiętywania danych jest lepsze niż mi się wydawało :)
Ale i tak będzie jeszcze podejście trzecie.
---------------------------------------------------------------------------------------------------------
Procesor | polecenie | wynik | czas | user
---------------------------------------------------------------------------------------------------------
Phenom II | threadMemPerft 10 8 250000000 8 1000000 | 69352859710032! | 63547s |
Phenom II | threadMemPerft 10 8 250000000 1 0 | 69352859712417ok | 41515s |
Phenom II | threadMemPerft 10 8 250000000 8 0 | 69352859712417ok | 30042s |
i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 0 | 69352859712417ok | 21051s |
i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 1000000 | 69352859712417ok | 12173s |
Phenom II | threadMemPerft 10 8 250000000 8 10000000 | 69352859712417ok | 17768s |
i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 10000000 | 69352859712417ok | 12092s |
e3-1230 v2 3.3ghz | threadMemPerft2 10 6 32400000 8 7 | 69352859712417ok | 11709s | sknd
i7 950 @3.07GHz | threadMemPerft2 10 5 56250000 8 1 | 69352859712417ok | 13667s |
Phenom II | threadMemPerft 10 8 250000000 8 50000000 | 69352859712417ok | 17781s |
--------------------------------------------------------------------------------------------------------
Pozdrawiam
No to kolejny wynik, zwracam uwagę na zmiany w skrypcie startującym testy (ostatnie 3):
#!/bin/sh
mem=5400000
thr=4
depth=9
(
echo threadMemPerft2 $depth $thr $mem 8 1
echo quit
) | ./perft >> out.txt
(
echo threadMemPerft2 $depth $thr $mem 8 2
echo quit
) | ./perft >> out.txt
(
echo threadMemPerft2 $depth $thr $mem 8 3
echo quit
) | ./perft >> out.txt
(
echo threadMemPerft2 $depth $thr $mem 8 4
echo quit
) | ./perft >> out.txt
(
echo threadMemPerft2 $depth $thr $mem 8 5
echo quit
) | ./perft >> out.txt
(
echo threadMemPerft2 $depth $thr $mem 8 6
echo quit
) | ./perft >> out.txt
(
echo threadMemPerft2 $depth $thr $mem 8 7
echo quit
) | ./perft >> out.txt
(
echo threadMemPerft $depth $thr 10800000 4 1
echo quit
) | ./perft >> out.txt
(
echo threadMemPerft $depth $thr 10800000 4 2
echo quit
) | ./perft >> out.txt
(
echo threadMemPerft $depth $thr 10800000 4 3
echo quit
) | ./perft >> out.txt
Wyniki:
nodes:2439530234167 time:6921
nodes:2439530234167 time:5976
nodes:2439530234167 time:5691
nodes:2439530234167 time:5633
nodes:2439530234167 time:5512
nodes:2439530234167 time:5551
nodes:2439530234167 time:5546
nodes:2439530234167 time:5560
nodes:2439530234167 time:4355
nodes:2439530234167 time:2209
nodes:2439530234167 time:2013
nodes:2439530234167 time:2007
nodes:2439530234167 time:1963
nodes:2439530234167 time:1944
nodes:2439530234167 time:3041
nodes:2439530234167 time:2972
nodes:2439530234167 time:2110
nodes:2439530234167 time:2053
nodes:2439530234167 time:2027
nodes:2439530234167 time:2004
nodes:2439530234167 time:1981
nodes:2439530234167 time:1977
nodes:2439530234167 time:1986
nodes:2439530234167 time:5148
nodes:2439530234167 time:5140
nodes:2439530234167 time:5138
Cytat: mariotti w 27 Maj 2013, 23:25
Czy mógłbyś sprawdzić jeszcze na tej samej maszynie takie polecenie?
threadMemPerft2 10 6 32400000 8 1
zrobione
threadMemPerft2 10 6 32400000 8 1
nodes:69352859712417 time:13085
jak widac czas gorszy troche
Cytat: sknd w 28 Maj 2013, 13:19
Cytat: mariotti w 27 Maj 2013, 23:25
Czy mógłbyś sprawdzić jeszcze na tej samej maszynie takie polecenie?
threadMemPerft2 10 6 32400000 8 1
zrobione
threadMemPerft2 10 6 32400000 8 1
nodes:69352859712417 time:13085
jak widac czas gorszy troche
Dzięki. Jak na taką skalę obliczeń, to czas wiele gorszy, takie różnice
mogą zadecydować o tym, czy dożyjemy końca czy nie :D
Aktualna tabelka:
-----------------------------------------------------------------------------------------------------------------
Wersja | Procesor | polecenie | wynik | czas | user
-----------------------------------------------------------------------------------------------------------------
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 1000000 | 69352859710032! | 63547s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 1 0 | 69352859712417ok | 41515s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 0 | 69352859712417ok | 30042s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 0 | 69352859712417ok | 21051s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 1000000 | 69352859712417ok | 12173s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 10000000 | 69352859712417ok | 17768s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 10000000 | 69352859712417ok | 12092s |
0 | e3-1230 v2 3.3ghz | threadMemPerft2 10 6 32400000 8 7 | 69352859712417ok | 11709s | sknd
0 | i7 950 @3.07GHz | threadMemPerft2 10 5 56250000 8 1 | 69352859712417ok | 13667s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 50000000 | 69352859712417ok | 17781s |
0 | e3-1230 v2 3.3ghz | threadMemPerft2 10 6 32400000 8 1 | 69352859712417ok | 13085s | sknd
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 12 10000000 | 69352859712417ok | 18111s |
1 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 200 | 69352859712417ok | 25889s |
---------------------------------------------------------------------------------------------------------------
Jest nowa wersja programu. Wersji jest kilka, żeby się nie pogubić, nowa dostała numerek 1. W nowej doszło
nowe polecenie, ale z tego co widzę, raczej będzie to niewypał. Za to stare polecenie zostało zmodyfikowane,
czyli inaczej działa:
threadMemPerft depth max_thread hsize hprobe forget
Wcześniej parametr forget mógł przyjmować duże wartości, od 0 do 2^64-1 i trudno było go dobrać.
Teraz sensowe wartości są (prawdopodobnie) w mniejszym przedziale od 20 do 10000.
Na komputerze e3-1230 v2 3.3ghz warto sprawdzić nową komendę z tak dobranymi parametrami, aby
była taka sama ilość pamięci. Czyli np.:
threadMemPerft 10 259200000 8 200
threadMemPerft 10 259200000 8 150
threadMemPerft 10 259200000 8 100
Pozdrawiam i dzięki.
Cytat: krzyszp w 28 Maj 2013, 09:17
No to kolejny wynik, zwracam uwagę na zmiany w skrypcie startującym testy (ostatnie 3):
Dzięki :)
Wiążę wyniki z poleceniami tak jak poniżej widać. Czyli wygrało 8 6.
mem=5400000
thr=4
depth=9
threadMemPerft2 $depth $thr $mem 8 1 nodes:2439530234167 time:2110
threadMemPerft2 $depth $thr $mem 8 2 nodes:2439530234167 time:2053
threadMemPerft2 $depth $thr $mem 8 3 nodes:2439530234167 time:2027
threadMemPerft2 $depth $thr $mem 8 4 nodes:2439530234167 time:2004
threadMemPerft2 $depth $thr $mem 8 5 nodes:2439530234167 time:1981
threadMemPerft2 $depth $thr $mem 8 6 nodes:2439530234167 time:1977
threadMemPerft2 $depth $thr $mem 8 7 nodes:2439530234167 time:1986
threadMemPerft $depth $thr 10800000 4 1 nodes:2439530234167 time:5148
threadMemPerft $depth $thr 10800000 4 2 nodes:2439530234167 time:5140
threadMemPerft $depth $thr 10800000 4 3 nodes:2439530234167 time:5138
W tych testach było w pamięci 5400000 * 8 = 43200000 układów
Czyli odpowiednik takich komend:
threadMemPerft 9 4 43200000 8 20
threadMemPerft 9 4 43200000 8 50
threadMemPerft 9 4 43200000 8 80
threadMemPerft 9 4 43200000 8 120
threadMemPerft 9 4 43200000 8 200
threadMemPerft 9 4 43200000 8 300
Wcześniej najlepsza była piątka, więc dajmy też do testów piątkę.
Cały skrypt:
#!/bin/sh
(
echo threadMemPerft 9 4 43200000 8 20
echo quit
) | ./perft1 >> out.txt
(
echo threadMemPerft 9 4 43200000 8 50
echo quit
) | ./perft1 >> out.txt
(
echo threadMemPerft 9 4 43200000 8 80
echo quit
) | ./perft1 >> out.txt
(
echo threadMemPerft 9 4 43200000 8 120
echo quit
) | ./perft1 >> out.txt
(
echo threadMemPerft 9 4 43200000 8 200
echo quit
) | ./perft1 >> out.txt
(
echo threadMemPerft 9 4 43200000 8 300
echo quit
) | ./perft1 >> out.txt
(
echo threadMemPerft 9 4 43200000 5 20
echo quit
) | ./perft1 >> out.txt
(
echo threadMemPerft 9 4 43200000 5 50
echo quit
) | ./perft1 >> out.txt
(
echo threadMemPerft 9 4 43200000 5 80
echo quit
) | ./perft1 >> out.txt
(
echo threadMemPerft 9 4 43200000 5 120
echo quit
) | ./perft1 >> out.txt
(
echo threadMemPerft 9 4 43200000 5 200
echo quit
) | ./perft1 >> out.txt
(
echo threadMemPerft 9 4 43200000 5 300
echo quit
) | ./perft1 >> out.txt
Jeszcze raz wielkie dzięki za testy :)
Nie mam nowych pomysłów na ulepszenie zarządzania pamięcią, więc teraz spróbuję coś
ulepszyć w zarządzaniu wątkami :)
Pozdrawiam
Cytat: mariotti w 28 Maj 2013, 13:44
Jest nowa wersja programu. Wersji jest kilka, żeby się nie pogubić, nowa dostała numerek 1. W nowej doszło
nowe polecenie, ale z tego co widzę, raczej będzie to niewypał. Za to stare polecenie zostało zmodyfikowane,
czyli inaczej działa:
threadMemPerft depth max_thread hsize hprobe forget
Wcześniej parametr forget mógł przyjmować duże wartości, od 0 do 2^64-1 i trudno było go dobrać.
Teraz sensowe wartości są (prawdopodobnie) w mniejszym przedziale od 20 do 10000.
Na komputerze e3-1230 v2 3.3ghz warto sprawdzić nową komendę z tak dobranymi parametrami, aby
była taka sama ilość pamięci. Czyli np.:
threadMemPerft 10 259200000 8 200
threadMemPerft 10 259200000 8 150
threadMemPerft 10 259200000 8 100
Pozdrawiam i dzięki.
powinno być 5 parametrów, podałeś 4, zdaje się że zapomniałeś o ilości wątków. Mógłbyś mi podać przykładowe wartości tak żeby zajmowało to powiedzmy 6 giga ramu (mam 8 ) ?
aha, i w tabelce jest mały błąd - obliczenia robiłem na tym samym procku - e3-1230 v2 ;)
postaram się wieczorem zapuścić jeden a może i dwa testy zależy o której dotrę do domu...
Cytat: sknd w 28 Maj 2013, 15:16
Cytat: mariotti w 28 Maj 2013, 13:44
Jest nowa wersja programu. Wersji jest kilka, żeby się nie pogubić, nowa dostała numerek 1. W nowej doszło
nowe polecenie, ale z tego co widzę, raczej będzie to niewypał. Za to stare polecenie zostało zmodyfikowane,
czyli inaczej działa:
threadMemPerft depth max_thread hsize hprobe forget
Wcześniej parametr forget mógł przyjmować duże wartości, od 0 do 2^64-1 i trudno było go dobrać.
Teraz sensowe wartości są (prawdopodobnie) w mniejszym przedziale od 20 do 10000.
Na komputerze e3-1230 v2 3.3ghz warto sprawdzić nową komendę z tak dobranymi parametrami, aby
była taka sama ilość pamięci. Czyli np.:
threadMemPerft 10 259200000 8 200
threadMemPerft 10 259200000 8 150
threadMemPerft 10 259200000 8 100
Pozdrawiam i dzięki.
powinno być 5 parametrów, podałeś 4, zdaje się że zapomniałeś o ilości wątków. Mógłbyś mi podać przykładowe wartości tak żeby zajmowało to powiedzmy 6 giga ramu (mam 8 ) ?
aha, i w tabelce jest mały błąd - obliczenia robiłem na tym samym procku - e3-1230 v2 ;)
postaram się wieczorem zapuścić jeden a może i dwa testy zależy o której dotrę do domu...
Wszystko pomyliłem :)
1) Tabelka już poprawiona.
2) W poleceniach faktycznie zabrakło ilości wątków.
Chciałem porównać z sobą skuteczność różnych algorytmów w podobnych warunkach. Czyli
pozostawiamy taką samą ilość wątków, taką samą ilość układów w ram, no i ten sam procesor :)
Poprzedni algorytm (threadMemPerft2 w wersji 0) miał w RAM 32400000 * 8 = 259200000 układów.
Chciałbym zobaczyć jak on wypada w porównaniu z algorytmem threadMemPerft w wersji 1.
Więc takie przykładowe polecenia.
threadMemPerft 10 6 259200000 8 200
threadMemPerft 10 6 259200000 8 150
threadMemPerft 10 6 259200000 8 100
Wersja perft1 jest pod linkiem:
http://www.boincatpoland.org/smf/przetwarzanie-rozproszone/to-co-bawimy-sie-d/?action=dlattach;attach=1310
Pozdrawiam
Dla:
threadMemPerft 10 5 50000000 8 1000000
Wynik :
nodes:69352859712417 time:42144
Na Q6600
Zabieram się za dalsze testowanie. Zastanawia mnie jednak, czy skaczące obciążenie tej maszyny mocno wpływa na wyniki?
Cytat: krzyszp w 28 Maj 2013, 22:22
Dla:
threadMemPerft 10 5 50000000 8 1000000
Wynik :
nodes:69352859712417 time:42144
Na Q6600
Super dzięki. To chyba bardzo ładny wynik jak na tak małą ilość pamięci i procesor Q6600.
Uaktualniam tabelkę. Rozumiem że testowałeś wersję
perft, bo jest już wersja
perft1 :)
------------------------------------------------------------------------------------------------------------------
Wersja | Procesor | polecenie | wynik | czas | user
------------------------------------------------------------------------------------------------------------------
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 1000000 | 69352859710032! | 63547s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 1 0 | 69352859712417ok | 41515s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 0 | 69352859712417ok | 30042s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 0 | 69352859712417ok | 21051s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 1000000 | 69352859712417ok | 12173s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 10000000 | 69352859712417ok | 17768s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 10000000 | 69352859712417ok | 12092s |
0 | e3-1230 v2 3.3ghz | threadMemPerft2 10 6 32400000 8 7 | 69352859712417ok | 11709s | sknd
0 | i7 950 @3.07GHz | threadMemPerft2 10 5 56250000 8 1 | 69352859712417ok | 13667s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 50000000 | 69352859712417ok | 17781s |
0 | e3-1230 v2 3.3ghz | threadMemPerft2 10 6 32400000 8 1 | 69352859712417ok | 13085s | sknd
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 12 10000000 | 69352859712417ok | 18111s |
1 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 200 | 69352859712417ok | 25889s |
0 | Q6600 | threadMemPerft 10 5 50000000 8 1000000 | 69352859712417ok | 42144 | krzyszp
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 200 | 69352859712417ok | 16967 |
------------------------------------------------------------------------------------------------------------------
Cytat: krzyszp w 28 Maj 2013, 22:22
Zabieram się za dalsze testowanie. Zastanawia mnie jednak, czy skaczące obciążenie tej maszyny mocno wpływa na wyniki?
Trudno powiedzieć, za jakiś czas i to sprawdzimy. Na razie robimy pobieżne testy, wszystkie wyniki analizuję i
ocenię które algorytmy i które zakresy parametrów warto sprawdzić dokładnie.
W dokładnych testach sprawdzimy jaka w ogóle jest powtarzalność wyników na nieobciążonym komputerze. Gdy program
pracuje wielowątkowo, to nawet na nieobciążonym komputerze może podać różne czasy. Czasami ułamki sekund decydują o
tym, że wątek ma gotowe dane i nie musi danego układu przeliczać. Jeśli system uruchomi drugi wątek "za wcześnie" o te ułamki
sekund, to drugi wątek liczy to samo co pierwszy, zamiast odczytać wynik z tablicy. Jeśli uruchomi za późno, to dane które
zapisał pierwszy wątek mogą zostać zamazane. Za jakiś czas i nad tym popracuję, może uda się jeszcze coś przyspieszyć.
Teraz ciekawi mnie algorytm threadMemPerft w wersji nr 1. Na razie mam bardzo niejednoznaczne wyniki. Na małych
głębokościach działa szybciej ten z wersji nr 1, a na dużych chyba działał szybciej ten stary algorytm. Może będę musiał
go przywrócić.
Za jakiś czas postaram się przygotować testy w bardziej profesjonalny sposób. Na razie jest dobrze, jeśli program na wielu
różnych komputerach nie wywala się i podaje dobry wynik. :)
Tak, ten test był jeszcze na starej wersji.
Wyniki testu "ze skryptu", który testuje perft1 wg podanych wcześniej przez Ciebie danych do go.sh będą jutro...
Cytat: krzyszp w 28 Maj 2013, 23:50
Tak, ten test był jeszcze na starej wersji.
Wyniki testu "ze skryptu", który testuje perft1 wg podanych wcześniej przez Ciebie danych do go.sh będą jutro...
Super fajnie.
--------------------------------------------------------------------------------
Myślę powoli nad dokładnym oszacowaniem czasu jaki będziemy
potrzebowali na głębokości 13, 14, 15 i 16. Robimy zakłady? :)
Moje rokowania:
Obecna wersja programu na komputerze Q6600
depth 13 -> 6lat
depth 14 -> 85 lat
depth 15 -> 1284 lat
depth 16 -> 19263 lat
Trza by go z 50 razy przyspieszyć :D
Czyli na "dzisiejszych" procesorach będzie 3-4 razy szybciej.
Cytat: Dario666 w 29 Maj 2013, 08:49
Czyli na "dzisiejszych" procesorach będzie 3-4 razy szybciej.
Sprawdziłem ile jest
unikalnych układów na głębokości 6 ruchów. No i jest
ich 9417683, czyli 12 razy mniej niż wszystkich 119060324.
Na serwerze wystarczy zapamiętać te unikalne. Następnie trzeba 9417683 razy
policzyć na głębokość 9 ruchów i mamy łączną głębokość 15 ruchów. Na Q6600
schodził na głębokość 9 ruchów np. w 1986 sekund. Czyli tamta
wersja potrzebuje około 9417683 * 1986 / 24 / 3600 / 365 = 600 lat. Ale...
Komputery są szybsze i mają więcej pamięci, więc 600 / 4 = 150.
Mam nadzieję że zoptymalizuję zarządzanie pamięcią, więc 150 / 4 = 37.
Przyspieszenie liniowe nie wiem ile da... może z 10 razy, czyli 37/10 = 4 lata
Klient będzie pobierał do obliczeń 10-100
podobnych układów na raz, a w
podobnych jeszcze lepiej zadziała pamięć, czyli optymistyczna (ale nie szalona!) wersja to
około 2-3 lat :D
Pozdrawiam
Wyniki dla:
#!/bin/sh
(
echo threadMemPerft 9 4 43200000 8 20
echo quit
) | ./perft1 >> out.txt
(
echo threadMemPerft 9 4 43200000 8 50
echo quit
) | ./perft1 >> out.txt
(
echo threadMemPerft 9 4 43200000 8 80
echo quit
) | ./perft1 >> out.txt
(
echo threadMemPerft 9 4 43200000 8 120
echo quit
) | ./perft1 >> out.txt
(
echo threadMemPerft 9 4 43200000 8 200
echo quit
) | ./perft1 >> out.txt
(
echo threadMemPerft 9 4 43200000 8 300
echo quit
) | ./perft1 >> out.txt
(
echo threadMemPerft 9 4 43200000 5 20
echo quit
) | ./perft1 >> out.txt
(
echo threadMemPerft 9 4 43200000 5 50
echo quit
) | ./perft1 >> out.txt
(
echo threadMemPerft 9 4 43200000 5 80
echo quit
) | ./perft1 >> out.txt
(
echo threadMemPerft 9 4 43200000 5 120
echo quit
) | ./perft1 >> out.txt
(
echo threadMemPerft 9 4 43200000 5 200
echo quit
) | ./perft1 >> out.txt
(
echo threadMemPerft 9 4 43200000 5 300
echo quit
) | ./perft1 >> out.txt
Są następujące:
nodes:2439530234167 time:2636
nodes:2439530234167 time:2631
nodes:2439530234167 time:2635
nodes:2439530234167 time:2639
nodes:2439530234167 time:3920
nodes:2439530234167 time:2660
nodes:2439530234167 time:2617
nodes:2439530234167 time:2617
nodes:2439530234167 time:2616
nodes:2439530234167 time:2607
nodes:2439530234167 time:3921
nodes:2439530234167 time:2686
Cytat: mariotti w 28 Maj 2013, 16:59
Poprzedni algorytm (threadMemPerft2 w wersji 0) miał w RAM 32400000 * 8 = 259200000 układów.
Chciałbym zobaczyć jak on wypada w porównaniu z algorytmem threadMemPerft w wersji 1.
Więc takie przykładowe polecenia.
threadMemPerft 10 6 259200000 8 200
threadMemPerft 10 6 259200000 8 150
threadMemPerft 10 6 259200000 8 100
Wersja perft1 jest pod linkiem:
http://www.boincatpoland.org/smf/przetwarzanie-rozproszone/to-co-bawimy-sie-d/?action=dlattach;attach=1310
zrobiłem
threadMemPerft 10 6 259200000 8 200
nodes:69352859712417 time:16895
tylko że kurcze mać zapomniałem ściągnąć perft1, robiłem to ostatnią wersją perfta, dopiero teraz patrząc na twojego posta to sobie uświadomiłem :facepalm2: mam nadzieję że mimo wszystko do czegoś się to przyda może
Jak się podepnie cała drużyna to w tydzien zabraknie WU. Może liczyć od razu na głąbokość 16. ;D
Cytat: krzyszp w 29 Maj 2013, 09:49
Wyniki dla:
Są następujące:
threadMemPerft2 9 4 5400000 8 1 nodes:2439530234167 time:2110
threadMemPerft2 9 4 5400000 8 2 nodes:2439530234167 time:2053
threadMemPerft2 9 4 5400000 8 3 nodes:2439530234167 time:2027
threadMemPerft2 9 4 5400000 8 4 nodes:2439530234167 time:2004
threadMemPerft2 9 4 5400000 8 5 nodes:2439530234167 time:1981
threadMemPerft2 9 4 5400000 8 6 nodes:2439530234167 time:1977
threadMemPerft2 9 4 5400000 8 7 nodes:2439530234167 time:1986
threadMemPerft 9 4 10800000 4 1 nodes:2439530234167 time:5148
threadMemPerft 9 4 10800000 4 2 nodes:2439530234167 time:5140
threadMemPerft 9 4 10800000 4 3 nodes:2439530234167 time:5138
threadMemPerft 9 4 43200000 8 20 nodes:2439530234167 time:2636
threadMemPerft 9 4 43200000 8 50 nodes:2439530234167 time:2631
threadMemPerft 9 4 43200000 8 80 nodes:2439530234167 time:2635
threadMemPerft 9 4 43200000 8 120 nodes:2439530234167 time:2639
threadMemPerft 9 4 43200000 8 200 nodes:2439530234167 time:3920
threadMemPerft 9 4 43200000 8 300 nodes:2439530234167 time:2660
threadMemPerft 9 4 43200000 5 20 nodes:2439530234167 time:2617
threadMemPerft 9 4 43200000 5 50 nodes:2439530234167 time:2617
threadMemPerft 9 4 43200000 5 80 nodes:2439530234167 time:2616
threadMemPerft 9 4 43200000 5 120 nodes:2439530234167 time:2607
threadMemPerft 9 4 43200000 5 200 nodes:2439530234167 time:3921
threadMemPerft 9 4 43200000 5 300 nodes:2439530234167 time:2686
Dzięki za testy.
Czyli na Q6600 algorytm:
./perft1 threadMemPerft2 9 4 5400000 8 5 nodes:2439530234167 time:1981
działa najlepiej. Myślałem że to kiepska wersja i pójdzie w kosz, ale
będzie trzeba się jej przyjrzeć uważnie :)
Pozdrawiam
Cytat: mariotti w 29 Maj 2013, 15:41
Dzięki za testy.
Nie ma problemu, dawaj nastépne testy ;)
Cytat
zrobiłem
threadMemPerft 10 6 259200000 8 200
nodes:69352859712417 time:16895
Dobrze, przyda się każdy wynik.
Nowa tabelka
------------------------------------------------------------------------------------------------------------------
Wersja | Procesor | polecenie | wynik | czas | user
------------------------------------------------------------------------------------------------------------------
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 1000000 | 69352859710032! | 63547s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 1 0 | 69352859712417ok | 41515s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 0 | 69352859712417ok | 30042s |
1 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 200 | 69352859712417ok | 25889s |
2 | Phenom II 1050T 2.4GHz | threadMemPerft5 10 6 250000000 8 1000000 | 69352859712417ok | 24071s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 12 10000000 | 69352859712417ok | 18111s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 50000000 | 69352859712417ok | 17781s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 10000000 | 69352859712417ok | 17768s |
0 | Q6600 | threadMemPerft 10 5 50000000 8 1000000 | 69352859712417ok | 42144s | krzyszp
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 0 | 69352859712417ok | 21051s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 200 | 69352859712417ok | 16967s |
0 | i7 950 @3.07GHz | threadMemPerft2 10 5 56250000 8 1 | 69352859712417ok | 13667s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 1000000 | 69352859712417ok | 12173s |
2 | i7 950 @3.07GHz | threadMemPerft5 10 4 450000000 8 10000000 | 69352859712417ok | 12144s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 10000000 | 69352859712417ok | 12092s |
0 | e3-1230 v2 3.3ghz | threadMemPerft 10 6 259200000 8 200 | 69352859712417ok | 16895s | sknd
0 | e3-1230 v2 3.3ghz | threadMemPerft2 10 6 32400000 8 1 | 69352859712417ok | 13085s | sknd
0 | e3-1230 v2 3.3ghz | threadMemPerft2 10 6 32400000 8 7 | 69352859712417ok | 11709s | sknd
------------------------------------------------------------------------------------------------------------------
Więc jest nowa wersja programu:
perft2.
Jednak te nowe polecenia albo: na współgrają z procesorem
Phehom, albo jest duża losowość i takie same polecenia będą
się wykonywały w różnym czasie.
Jeśli prawdziwa jest ta pierwsza wersja, to będzie konieczna
inna wersja programu na każdy procesor - w sumie już jest
dużo wersji, wystarczy na danym procesorze wybrać odpowiednie
polecenie.
A jeśli ta druga wersja jest prawdziwa, to w ogóle trudne
będzie ustalenie, który algorytm jest najlepszy.
Na procesorze
e3-1230 v2 3.3ghz by pomógł mi test takich poleceń: (oczywiście
już tylko dla wersji perft2)
threadMemPerft5 10 4 259200000 8 10000000
threadMemPerft 10 6 259200000 5 10000000
threadMemPerft4 10 6 259200000 5 64
Na
Q6600threadMemPerft5 10 4 50000000 8 10000000
threadMemPerft2 10 4 6250000 8 6
Pozdrawiam i jeszcze raz dzięki wszystkim za pomoc
Wykonuje sié
Na swoim Q9400 uruchomiłem polecenie:
threadMemPerft2 10 4 6250000 8 6
Przy pierwszym poleceniu (threadMemPerft5 10 4 50000000 8 10000000) otrzymuje komunikat:
using: threadMemPerft5 depth max_thread hsize hprobe forget
Czyżby za mało pamięci?
Cytat: patyczak w 29 Maj 2013, 18:52
Na swoim Q9400 uruchomiłem polecenie:
threadMemPerft2 10 4 6250000 8 6
Przy pierwszym poleceniu (threadMemPerft5 10 4 50000000 8 10000000) otrzymuje komunikat:
using: threadMemPerft5 depth max_thread hsize hprobe forget
Czyżby za mało pamięci?
Powinno działać.
U siebie odpalam, tak jak widać na zrzucie z shella
(zmniejszyłem tylko głębokość z 10 ruchów do 6)
./perft2
threadMemPerft5
using: threadMemPerft5 depth max_thread hsize hprobe forget
threadMemPerft5 6 4 50000000 8 10000000
nodes:119060324 time:3
quit
Prawdopodobnie źle była wpisana/wklejona komenda i wyskoczył taki mini help.
A jeśli była dobrze wpisana, to może jakiś rzadki błąd w się uaktywnił.
Mam prośbę: spróbuj jeszcze kilka razy, bo wszelkie informacje o błędach są
dla mnie najważniejsze :)
Wzór na ilość pamięci w poleceniu threadMemPerft5 wygląda tak:
50000000 * 24 = 1.200.000.000 bajtów = 1.2 giba bajta.
Pozdrawiam
Cytat
Prawdopodobnie źle była wpisana/wklejona komenda i wyskoczył taki mini help.
Rzeczywiście musiałem jakąś literówkę zrobić. Odpaliłem drugi raz i tym razem poszło :)
Nowa tabelka
------------------------------------------------------------------------------------------------------------------
Wersja | Procesor | polecenie | wynik | czas | user
------------------------------------------------------------------------------------------------------------------
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 1000000 | 69352859710032! | 63547s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 1 0 | 69352859712417ok | 41515s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 0 | 69352859712417ok | 30042s |
1 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 200 | 69352859712417ok | 25889s |
2[1]| Phenom II 1050T 2.4GHz | threadMemPerft5 10 6 250000000 8 1000000 | 69352859712417ok | 24071s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 12 10000000 | 69352859712417ok | 18111s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 50000000 | 69352859712417ok | 17781s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 10000000 | 69352859712417ok | 17768s |
2 | Phenom II 1050T 2.4GHz | threadMemPerft5 10 6 250000000 5 1000000 | 69352859712417ok | 15251s |
2 | Phenom II 1050T 2.4GHz | threadMemPerft5 10 6 250000000 8 1000000 | 69352859712417ok | 15186s |
0 | Q6600 | threadMemPerft 10 5 50000000 8 1000000 | 69352859712417ok | 42144s | krzyszp
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 0 | 69352859712417ok | 21051s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 200 | 69352859712417ok | 16967s |
0 | i7 950 @3.07GHz | threadMemPerft2 10 5 56250000 8 1 | 69352859712417ok | 13667s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 1000000 | 69352859712417ok | 12173s |
2 | i7 950 @3.07GHz | threadMemPerft5 10 4 450000000 8 10000000 | 69352859712417ok | 12144s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 10000000 | 69352859712417ok | 12092s |
2 | i7 950 @3.07GHz | threadMemPerft5 10 5 450000000 8 10000000 | 69352859712417ok | 11475s |
2 | i7 950 @3.07GHz | threadMemPerft5 10 5 450000000 5 10000000 | 69352859712417ok | 11396s |
0 | e3-1230 v2 3.3ghz | threadMemPerft 10 6 259200000 8 200 | 69352859712417ok | 16895s | sknd
0 | e3-1230 v2 3.3ghz | threadMemPerft2 10 6 32400000 8 1 | 69352859712417ok | 13085s | sknd
2 | e3-1230 v2 3.3ghz | threadMemPerft5 10 4 259200000 8 10000000 | 69352859712417ok | 12730s | sknd
0 | e3-1230 v2 3.3ghz | threadMemPerft2 10 6 32400000 8 7 | 69352859712417ok | 11709s | sknd
------------------------------------------------------------------------------------------------------------------
[1] - z tej wersji prawdopodobnie zapomniałem usunąć asercje i spowolniły program.
Cytat: mariotti w 29 Maj 2013, 16:32
Na procesorze e3-1230 v2 3.3ghz by pomógł mi test takich poleceń: (oczywiście
już tylko dla wersji perft2)
threadMemPerft5 10 4 259200000 8 10000000
threadMemPerft 10 6 259200000 5 10000000
threadMemPerft4 10 6 259200000 5 64
threadMemPerft5 10 4 259200000 8 10000000
nodes:69352859712417 time:12730
mam nadzieje że celowo wpisałeś liczbę wątków 4 a nie 6 ;)
Cytat: sknd w 29 Maj 2013, 22:51
Cytat: mariotti w 29 Maj 2013, 16:32
Na procesorze e3-1230 v2 3.3ghz by pomógł mi test takich poleceń: (oczywiście
już tylko dla wersji perft2)
threadMemPerft5 10 4 259200000 8 10000000
threadMemPerft 10 6 259200000 5 10000000
threadMemPerft4 10 6 259200000 5 64
threadMemPerft5 10 4 259200000 8 10000000
nodes:69352859712417 time:12730
mam nadzieje że celowo wpisałeś liczbę wątków 4 a nie 6 ;)
Dziękuję za testy, już dopisuję wynik do tabelki na górze.
Tak, celowo wpisałem. Algorytm threadMemPerft5 ma ulepszone
zarządzanie wątkami - przynajmniej w teorii. Jeśli się nie mylę,
to najszybciej będzie działał gdy ilość wątków jest równa ilości
fizycznych rdzeni, a na procesorze z hyperthreadingiem... trudno
powiedzieć, zależy ile tak naprawdę daje ten hyperthreding. Być
może na procesorach z hyperthreadingiem opłaci się dodać jeden
wątek więcej.
Pozdrawiam
Z samej ciekawości, jak twoja aplikacja skaluje na większej ilości wątków, jutro będę miał wolny czas i przeprowadzę testy na serwerze Ubuntu 10.10 z 48 rdzeni @ 2.3GHz (AMD) i 16GB RAM. Jakie byłyby optymalne ustawienia?
threadMemPerft5 10 48 500000000 16 1000000
Czy to jest OK?
Cytat: AXm77 w 30 Maj 2013, 00:39
Z samej ciekawości,
Super że się zaciekawiłeś.
Cytat: AXm77 w 30 Maj 2013, 00:39
jak twoja aplikacja skaluje na większej ilości wątków,
W skrócie to dążę do tego, aby skalowała się liniowo. W szczegółach jest to bardzo
skomplikowane. Każdy algorytm który testowałem skaluje się trochę inaczej. Zadania
często powtarzają się, przy dużej głębokości prawdopodobnie jest tylko 0.1% unikalnych
zadań, pozostałe przynajmniej raz są zduplikowane. Zadania można oznaczyć kolejnymi
literami, weźmy przykładowe siedem zadań: A B C A D B A. Jeśli te zadania uruchomimy
na 7 wątkach, to przy założeniu że każde zadanie jest tak samo pracochłonne, powinny
się wykonać 7 razy szybciej niż na jednym wątku. Ale unikalnych zadań jest tylko 4, więc
aplikacja jednowątkowa może zapamiętać wyniki i potem zamiast obliczeń, może po prostu
odczytać. Czyli w takich warunkach aplikacja 1-wątkowa będzie tylko 4 razy wolniejsza
od 7-wątkowej. Dążę do tego, aby aplikacja jedno zadanie liczyła tylko jeden raz i to w
zasadzie obojętnie czy zostanie uruchomiona w jednym wątku czy w wielu.
Ciekawi mnie na ile w tym problemie można zbliżyć się do liniowej skalowalności. Nie
znam dokładnej odpowiedzi na to pytanie, ale jestem raczej optymistą. Praktycznie
codziennie mam jakiś pomysł na udoskonalenie, nie wszystkie udoskonalenia sprawują się
zgodnie z oczekiwaniami, ale względem pierwszej wersji obecny program działa 4 razy szybciej. To
przyspieszenie wynika tylko i wyłącznie z "ochrony" wątków przed liczeniem kilka razy
tego samego, sam kod jeszcze nie był w żaden sposób optymalizowany.
Cytat: AXm77 w 30 Maj 2013, 00:39
jutro będę miał wolny czas i przeprowadzę testy na serwerze Ubuntu 10.10 z 48 rdzeni @ 2.3GHz (AMD) i 16GB RAM. Jakie byłyby optymalne ustawienia?
threadMemPerft5 10 48 500000000 16 1000000
Czy to jest OK?
Żeby testy nam coś dały, to trzeba odpalić kilka razy, chociaż 4 razy.
Żeby sprawdzić skalowalność, moja propozycja jest np. taka:
threadMemPerft5 10 1 500000000 8 10000000
threadMemPerft5 10 2 500000000 8 10000000
threadMemPerft5 10 4 500000000 8 10000000
threadMemPerft5 10 8 500000000 8 10000000
threadMemPerft5 10 16 500000000 8 10000000
threadMemPerft5 10 48 500000000 8 10000000
threadMemPerft5 10 52 500000000 8 10000000
Lub tak:
threadMemPerft5 10 1 500000000 5 10000000
threadMemPerft5 10 2 500000000 5 10000000
threadMemPerft5 10 4 500000000 5 10000000
threadMemPerft5 10 8 500000000 5 10000000
threadMemPerft5 10 16 500000000 5 10000000
threadMemPerft5 10 48 500000000 5 10000000
threadMemPerft5 10 52 500000000 5 10000000
Wiem że to zajmie masę czasu, ale żeby zrobić sensowne porównanie, to musimy
mieć materiał do tego porównywania. Można zamiast głębokości 10 dać
głębokość 9 - to nie to samo co 10, ale znacznie przyspieszy. Jeśli nie masz
tyle czasu, to może odpal dwa razy:
threadMemPerft5 10 1 500000000 5 10000000
threadMemPerft5 10 52 500000000 5 10000000
Dzięki temu też się czegoś ważnego dowiemy.
Pracuję nad wersją 6 i 7 tego algorytmu. Ulepszenia będą szły cały czas w
kierunku ochrony przed wielokrotnym liczeniem tego samego - to także
oznacza że aplikacja powinna się lepiej skalować. Jakbyś mógł przetestować
potem tak samo wersję 6 i 7, to byśmy wiedzieli czy skalowanie ( i nie tylko
skalowanie ) jakoś istotnie się poprawiło.
Aplikacja cały czas ma heurystykę do synchronizacji wątków, heurystykę, czyli
coś co zwykle działa, ale nie daje 100% gwarancji że zawsze będzie poprawny
wynik. Test na takim sprzęcie (dużo rdzeni i wątków) powie nam coś nowego na
temat "siły" tej heurystyki - i nie tylko, da nam też ogólny pogląd na stabilność :)
Jeszcze raz dzięki i pozdrawiam.
Przygotowałem skrypt (apropos: ostatnia wartość ma być milion czy dziesięć milionów?) i przetestowałem z głębokością 7: 52 -12s a 48 - 13s.
Jutro startuję z głębokością 10 na 52, 48, 24, 16, 8, 4, 2, 1 (dokładnie w takiej koleności,zaczynam od 52), przewiduję obciążenie na jakieś dwie doby.
Cytat: AXm77 w 30 Maj 2013, 04:48
Przygotowałem skrypt (apropos: ostatnia wartość ma być milion czy dziesięć milionów?) i przetestowałem z głębokością 7: 52 -12s a 48 - 13s.
Jutro startuję z głębokością 10 na 52, 48, 24, 16, 8, 4, 2, 1 (dokładnie w takiej koleności,zaczynam od 52), przewiduję obciążenie na jakieś dwie doby.
Na razie nie wiem jaka jest optymalna wartość ostatniego parametru. W tych testach ważne jest tylko, aby zawsze była taka sama.
Pozdrawiam i dzięki za testy.
Polecenie:
threadMemPerft5 10 4 50000000 8 10000000
Wynik:
nodes:69352859712417 time:32666
Q9400
Polecenie:
threadMemPerft5 10 4 50000000 8 10000000
nodes:69352859712417 time:37149
Natomiast:
threadMemPerft2 10 4 6250000 8 6
jeszcze się wykonuje na Q6600
Tylko taka jedna uwaga: fajnie, że optymalizujesz to pod kątem wątków, ale z tego co zrozumiałem to celujemy w BOINC. Jeśli tak to prawdopodobnie będziesz wykorzystywał jeden wątek (liczba projektów wielowątkowych jest naprawdę niewielka) lub musisz pójść w kierunku GPU a tam wątki będą działały na zupełnie innej zasadzie i inaczej się będą skalowały.
Cytat: Karlik w 30 Maj 2013, 12:39
Tylko taka jedna uwaga: fajnie, że optymalizujesz to pod kątem wątków, ale z tego co zrozumiałem to celujemy w BOINC. Jeśli tak to prawdopodobnie będziesz wykorzystywał jeden wątek (liczba projektów wielowątkowych jest naprawdę niewielka) lub musisz pójść w kierunku GPU a tam wątki będą działały na zupełnie innej zasadzie i inaczej się będą skalowały.
To znaczy, że BOINC wymaga by aplikacja nie była wielowątkowa??
Pierwszy wynik: :)
threadMemPerft5 10 52 580000000 8 1000000 - nodes:69352859712417 time:2074
Porównując do wyników twojego Phenoma (moje Opterony to praktycznie ten sam procesor - jakiej prędkości RAM masz zainstalowany w tym systemie?) program skaluje całkiem nieźle: 1984s vs
2074s 2065s
Cytat
To znaczy, że BOINC wymaga by aplikacja nie była wielowątkowa??
Wydaje mi się, że nie ma takich wymagań. Zdarzały się projekty, w których jedno WU zajmowało dwa rdzenie.
Zamknieta AQUA. Dzialajace Yafu, BURP, renderfarm.fi, bylo cos (nie wiem czy jest dalej) w Milce (nbody?), chyba (ale nie daje glowy) Test4Theory pod VM wszystko uzywalo/uzywa wiecej niz 1core. Wiec sam BOINC nie ogranicza applikacji i mozna liczyc mt.
To chyba Yafu skaluje naprawdę pięknie, próbki które liczyły godzinami na i5, leciały w minutach na Opteronach.
Kolejny wynik: :)
threadMemPerft5 10 52 580000000 8 1000000 - nodes:69352859712417 time:2074
threadMemPerft5 10 48 580000000 8 1000000 - nodes:69352859712417 time:2065
Jak widać lepiej liczy gdy jest tyle samo wątków co rdzeni.
zapodałem kompowi:
threadMemPerft 10 6 259200000 5 10000000
mam nadzieję, że to, ze ustawiłem boinca na 25% procesorów, by pozostałe rdzenie się nie nudziły, nie będzie wpływać na wyniki? Bo pewnie jakbym zostawił boinca na 100% to miałoby to wpływ spory? Pytam, bo chcę wyjść na parę godzin a wolałbym żeby komp nie miał pustego przebiegu jak już to policzy...
threadMemPerft5 10 52 580000000 8 1000000 - nodes:69352859712417 time:2074
threadMemPerft5 10 48 580000000 8 1000000 - nodes:69352859712417 time:2065
threadMemPerft5 10 32 580000000 8 1000000 - nodes:69352859712417 time:2883
threadMemPerft5 10 24 580000000 8 1000000 - nodes:69352859712417 time:3709
Cytat: sknd w 30 Maj 2013, 13:45
mam nadzieję, że to, ze ustawiłem boinca na 25% procesorów, by pozostałe rdzenie się nie nudziły, nie będzie wpływać na wyniki?
Może mieć wpływ ale jak duży to już nie wiem. Zależne od procesora i tego co się na nim liczy.
Nowa tabelka
------------------------------------------------------------------------------------------------------------------
Wersja | Procesor | polecenie | wynik | czas | user
------------------------------------------------------------------------------------------------------------------
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 1000000 | 69352859710032! | 63547s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 1 0 | 69352859712417ok | 41515s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 0 | 69352859712417ok | 30042s |
1 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 200 | 69352859712417ok | 25889s |
2[1]| Phenom II 1050T 2.4GHz | threadMemPerft5 10 6 250000000 8 1000000 | 69352859712417ok | 24071s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 12 10000000 | 69352859712417ok | 18111s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 50000000 | 69352859712417ok | 17781s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 10000000 | 69352859712417ok | 17768s |
2 | Phenom II 1050T 2.4GHz | threadMemPerft5 10 6 250000000 12 1000000 | 69352859712417ok | 15643s |
2 | Phenom II 1050T 2.4GHz | threadMemPerft5 10 6 250000000 5 1000000 | 69352859712417ok | 15251s |
2 | Phenom II 1050T 2.4GHz | threadMemPerft5 10 6 250000000 8 1000000 | 69352859712417ok | 15186s |
0 | Q6600 | threadMemPerft 10 5 50000000 8 1000000 | 69352859712417ok | 42144s | krzyszp
2 | Q6600 | threadMemPerft5 10 4 50000000 8 10000000 | 69352859712417ok | 37149s | krzyszp
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 0 | 69352859712417ok | 21051s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 200 | 69352859712417ok | 16967s |
0 | i7 950 @3.07GHz | threadMemPerft2 10 5 56250000 8 1 | 69352859712417ok | 13667s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 1000000 | 69352859712417ok | 12173s |
2 | i7 950 @3.07GHz | threadMemPerft5 10 4 450000000 8 10000000 | 69352859712417ok | 12144s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 10000000 | 69352859712417ok | 12092s |
2 | i7 950 @3.07GHz | threadMemPerft5 10 5 450000000 8 10000000 | 69352859712417ok | 11475s |
2 | i7 950 @3.07GHz | threadMemPerft5 10 5 450000000 5 10000000 | 69352859712417ok | 11396s |
0 | e3-1230 v2 3.3ghz | threadMemPerft 10 6 259200000 8 200 | 69352859712417ok | 16895s | sknd
2[2]| e3-1230 v2 3.3ghz | threadMemPerft 10 6 259200000 5 10000000 | 69352859712417ok | 13683s | sknd
0 | e3-1230 v2 3.3ghz | threadMemPerft2 10 6 32400000 8 1 | 69352859712417ok | 13085s | sknd
2 | e3-1230 v2 3.3ghz | threadMemPerft5 10 4 259200000 8 10000000 | 69352859712417ok | 12730s | sknd
0 | e3-1230 v2 3.3ghz | threadMemPerft2 10 6 32400000 8 7 | 69352859712417ok | 11709s | sknd
2 | Q9400 | threadMemPerft5 10 4 50000000 8 10000000 | 69352859712417ok | 32666s | patyczak
2 | AMD 48core | threadMemPerft5 10 52 580000000 8 1000000 | 69352859712417ok | 2074s | AXm77
2 | AMD 48core | threadMemPerft5 10 48 580000000 8 1000000 | 69352859712417ok | 2065s | AXm77
2 | AMD 48core | threadMemPerft5 10 32 580000000 8 1000000 | 69352859712417ok | 2883s | AXm77
2 | AMD 48core | threadMemPerft5 10 24 580000000 8 1000000 | 69352859712417ok | 3709s | AXm77
2 | AMD 48core | threadMemPerft5 10 16 580000000 8 1000000 | 69352859712417ok | 5362s | AXm77
------------------------------------------------------------------------------------------------------------------
[1] - z tej wersji prawdopodobnie zapomniałem usunąć asercje i spowolniły program.
[2] - dwa rdzenie komputera były obciążone
Cytat: patyczak
Polecenie:
threadMemPerft5 10 4 50000000 8 10000000
Wynik:
nodes:69352859712417 time:32666
Q9400
Dzięki, wynik dodany do tabelki.
Jeśli nie masz dosyć testów, to teraz np. takie komendy:
threadMemPerft5 10 4 50000000 8 1000000
threadMemPerft5 10 4 50000000 8 30000000
threadMemPerft5 10 4 50000000 8 100000000
Cytat: krzyszp
threadMemPerft5 10 4 50000000 8 10000000
nodes:69352859712417 time:37149
Natomiast:
threadMemPerft2 10 4 6250000 8 6
jeszcze się wykonuje na Q6600
Czyli mamy kolejne potwierdzenie że threadMemPerft5 działa szybciej
niż threadMemPerft. Zobaczymy jeszcze jak wypadnie w porównaniu do
threadMemPerft2. Dzięki za testy.
Cytat: Karlik
Tylko taka jedna uwaga: fajnie, że optymalizujesz to pod kątem wątków, ale z tego co zrozumiałem to celujemy w BOINC. Jeśli tak to prawdopodobnie będziesz wykorzystywał jeden wątek (liczba projektów wielowątkowych jest naprawdę niewielka) lub musisz pójść w kierunku GPU a tam wątki będą działały na zupełnie innej zasadzie i inaczej się będą skalowały.
Optymalizacja w kierunku wątków wychodzi przy okazji, ale to chyba dobrze że użytkownik sam będzie
mógł wskazać ilość wątków? W przeciwnym razie ktoś z maszyną która ma 256 rdzeni będzie liczył
na jednym, a 255 będzie się marnowało :D.
Na razie optymalizuję w kierunku ochrony wątków przed wykonywaniem tych samych zadań. Na poziomie
5-ciu ruchów jeden układ powtarza się nawet kilkaset razy, bez optymalizacji program może kilkaset
razy liczyć dokładnie to samo zadanie. Jeśli ta ochrona jest dobra, to program sam z automatu lepiej
się skaluje.
Co do GPU, to tamte rdzenie nie mają stosu jak rdzenie w CPU. Rdzenie liczą wiele szybciej przy
mniejszej ilości tranzystorów, ale kosztem tego że się najlepiej nadają do obliczeń strumieniowych,
np. ciągłe mnożenie i dodawanie. W takim programie jak ten bym musiał zasymulować stos programowo
na jakiejś tabicy. Z tego powodu może się okazać, że na GPU będzie wolniej niż na CPU -
ale pewności na 100% nie mam, może kiedyś pomyślimy nad tym poważniej.
Cytat: AXm77
Porównując do wyników twojego Phenoma (moje Opterony to praktycznie ten sam procesor - jakiej prędkości RAM masz zainstalowany w tym systemie?) program skaluje całkiem nieźle: 1984s vs 2074s 2065s
Najlepszy wynik na phenomie 15186s * 6 rdzeni = 91116s
Twój wynik 2074 * 48 = 99552s
Czyli po ośmiokrotnym zwiększeniu łączny czas obliczeń zwiększył
się około 10% - ale to jednak inne warunki testowe :)
(99552 - 91116) / 91116 = 9,26%
Mój procesor jest przetaktowany w dół, a pamięć mam dwóch rodzajów na jednej
płycie - aż dziwne że to działa :D Więc powyższe obliczenia potem zrobimy
jeszcze raz, odwołując się tylko do Twoich wyników :)
Cytat: AXm77
To chyba Yafu skaluje naprawdę pięknie, próbki które liczyły godzinami na i5, leciały w minutach na Opteronach.
Kolejny wynik: :)
threadMemPerft5 10 52 580000000 8 1000000 - nodes:69352859712417 time:2074
threadMemPerft5 10 48 580000000 8 1000000 - nodes:69352859712417 time:2065
Jak widać lepiej liczy gdy jest tyle samo wątków co rdzeni.
Jeju, śmiga na tym sprzęcie że aż miło :D
Ile dziś trzeba zapłacić żeby mieć taki w domu?
Cytat: sknd
zapodałem kompowi:
threadMemPerft 10 6 259200000 5 10000000
mam nadzieję, że to, ze ustawiłem boinca na 25% procesorów, by pozostałe rdzenie się nie nudziły, nie będzie wpływać na wyniki? Bo pewnie jakbym zostawił boinca na 100% to miałoby to wpływ spory? Pytam, bo chcę wyjść na parę godzin a wolałbym żeby komp nie miał pustego przebiegu jak już to policzy...
Obawiam się że będzie miało wpływ te 25%, ale to nic nie szkodzi, zobaczymy
dzięki temu w kolejnych warunkach czy aplikacja poda dobry wynik i czy się nie wywali.
Dzięki wszystkim i pozdrawiam.
P.S.
Testuję kolejną wersję programu, na małych głębokościach nie widzę przyspieszenia.
Jeśli na dużych głębokościach będą u mnie wyniki podobne lub lepsze, to wrzucę
kolejną wersję do przetestowania.
P.S 2
Widać że na razie wygrywa wersja threadMemPerft5, ale od czasu do czasu
wersja threadMemPerft2 też działa ładnie. Może da się zrobić hybrydę z
tych dwóch wersji - zobaczymy czy hybryda będzie miała zalety czy wady
swoich protoplastów :)
Następny wynik dla
threadMemPerft2 10 4 6250000 8 6
Wynosi
nodes:69352859712417 time:41457
Komputer stale obciążony...
Wykonam te testy jeszcze raz przy wstrzymanym liczeniu BOINC - zobaczymy, jak bardzo skróci to obliczenia...
Cytat: mariotti w 30 Maj 2013, 15:47
...
Jeju, śmiga na tym sprzęcie że aż miło :D
Ile dziś trzeba zapłacić żeby mieć taki w domu?
....
Mniej niż by się mogło wydawać. :)
Koleny wynik:
threadMemPerft5 10 52 580000000 8 1000000 - nodes:69352859712417 time:2074
threadMemPerft5 10 48 580000000 8 1000000 - nodes:69352859712417 time:2065
threadMemPerft5 10 32 580000000 8 1000000 - nodes:69352859712417 time:2883
threadMemPerft5 10 24 580000000 8 1000000 - nodes:69352859712417 time:3709
threadMemPerft5 10 16 580000000 8 1000000 - nodes:69352859712417 time:5362
Cytat: krzyszp w 30 Maj 2013, 16:00
Następny wynik dla
threadMemPerft2 10 4 6250000 8 6
Wynosi
nodes:69352859712417 time:41457
Komputer stale obciążony...
Wykonam te testy jeszcze raz przy wstrzymanym liczeniu BOINC - zobaczymy, jak bardzo skróci to obliczenia...
Jeśli stale jest obciążony to możliwe że spowalnia każdy test w podobnym stopniu. Jeśli w
podobnym, to można porównywać.
Zastanawiam się jakie przyspieszenia są ważne dla tego projektu, a jakie należy zignorować. Wydaj mi
się, że przyspieszenie o 5% jest jeszcze warte zachodu. Dokładność pomiaru +-3% w zupełności
wystarczy, a +-5% też da jakiś pogląd.
Teraz z inne beczki.
Będę musiał zoptymalizować aplikację liniowo - przypuszczam że to się bardzo opłaci. Pomysły na
optymalizacje algorytmiczne powoli mi się wyczerpują i już niewiele dają. Optymalizacja liniowa
zajmie mi sporo czasu, to żmudna robota. Zastanawiam się, żeby odpalić już jakąś namiastkę
docelowego serwera, może na razie coś przez interfejs www. W czasie gdy ja bym pracował na
optymalizacją liniową, to na kilku kompach byśmy mogli sprawdzać jak sprawuje się całość.
Na głębokości 4 ruchów jest 8902 liści, a tym tylko 5362 unikalnych. Można te unikalne wgrać na
jakiś serwer. Klient może pobierać jednorazowo 20 zadań, następnie je przeliczać na głębokość 9-ciu
ruchów i wyniki odsyłać. Przed obliczeniami klient będzie musiał nadać sobie losowe wartości
kluczy zobrista. W celu weryfikacji, każdy układ powinien być dwa razy przeliczony. Czasochłonność
przeliczenia 20 zadań na głębokość 9 ruchów powinna być podobna do jednego na 10 ruchów. Możemy
się spodziewać że jeden taki task będzie trwał 4-10h (przed optymalizacją, na zwykłych
komputerach). 5362/20 daje 268 tasków. Na 10 komputerach po jednym tasku na dobę policzymy w
miesiąc. Uzyskamy w ten sposób wynik dla głębokości 13 ruchów. Zobaczymy czy wynik jest
prawidłowy, jeśli nie będzie prawidłowy, to zrobimy drugą rundę i sprawdzimy czy działa weryfikacja.
Jeśli wszystko zadziała, to sprawdzimy jeszcze pobieżnie wersję zoptymalizowaną - do tego czasu
powinienem mieć gotową. Wtedy będziemy gotowi na większe głębokości i na sprzężenie tego wszystkiego
z siecią BOINC.
Co myślicie?
Jak najbardziej za :)
natomiast pomyślałbym już o stawianiu serwera pod boinc - w końcu możesz wygodnie wysyłać za jego pomocą próbki do znacznie większej ilości komputerów z różną konfiguracją, a i wyniki testów będziesz miał szybciej...
Może TJM mógłby Ci pomóc postawić serwer? Oczywiście, musiałbyś zrobić zamknięte testy próbek, bo bez sensu by było na tę chwilę marnować czas na tłumaczenia "co i jak" światu... A i wprawy w zarządzaniu serwerem mógłbyś nabrać.
Cytat: mariotti w 30 Maj 2013, 15:47Optymalizacja w kierunku wątków wychodzi przy okazji, ale to chyba dobrze że użytkownik sam będzie mógł wskazać ilość wątków? W przeciwnym razie ktoś z maszyną która ma 256 rdzeni będzie liczył na jednym, a 255 będzie się marnowało :D.
Co do GPU, to tamte rdzenie nie mają stosu jak rdzenie w CPU. Rdzenie liczą wiele szybciej przy
mniejszej ilości tranzystorów, ale kosztem tego że się najlepiej nadają do obliczeń strumieniowych,
np. ciągłe mnożenie i dodawanie. W takim programie jak ten bym musiał zasymulować stos programowo
na jakiejś tabicy. Z tego powodu może się okazać, że na GPU będzie wolniej niż na CPU -
ale pewności na 100% nie mam, może kiedyś pomyślimy nad tym poważniej.
Ja tylko rzucam pomysłami, sam musisz ocenić dopasowanie do swojego algorytmu, bo ja go nie znam :D Co do liczby wątków to przy 255 rdzeniach już zmieni Ci się sposób skalowania ze względu na dość spore odległości pomiędzy skrajnymi rdzeniami i rdzeniami a pamięcią. Dopóki masz 1-2 procesory możesz się tym praktycznie nie przejmować, ale przy większej liczbie musisz się zastanowić czy czasy "transportu danych" i synchronizacji pamięci (cache<->RAM) nie spowodują jakichś dodatowych problemów.
Poza tym nie wiem jak sobie wyobrażasz opcje konfiguracyjne dla klienta. Miałby po jednym profilu dla każdego komputera, żeby mógł sobie ustawić ile rdzeni chce przeznaczyć na obliczenia? Albo będziesz procentową liczbę dostępnych brał (nie wiem jak rozróżnisz fizyczne od wirtualnych - chyba musiałbyś sobie zrobić katalog wszystkich procesorów z HT). Tylko wtedy wymuszasz na użytkowniku: albo liczysz moje albo cudze, jednocześnie nie pozwalam. :/ Nie chcę bombardować pomysłu, ale jakoś nie potrafię znaleźć rozwiązania optymalnego tej sytuacji.
threadMemPerft 10 6 259200000 5 10000000
nodes:69352859712417 time:13683
zrobione na e3-1230 v2 przy dwóch rdzeniach boincujących ;)
Cytat: Karlik w 30 Maj 2013, 17:12
Ja tylko rzucam pomysłami, sam musisz ocenić dopasowanie do swojego algorytmu, bo ja go nie znam :D
Mnie też jest trudno ocenić, poza oczywistymi sprawami, muszę napisać i zmierzyć czas; a w tych oczywistych
czasami też mi oczy wyłażą ze zdziwienia :) Dobra aplikacja na GPU to masakryczna ilość roboty i potem test -
albo działa szybciej, albo wolniej.
Cytat: Karlik w 30 Maj 2013, 17:12
Co do liczby wątków to przy 255 rdzeniach już zmieni Ci się sposób skalowania ze względu na dość spore odległości pomiędzy skrajnymi
rdzeniami i rdzeniami a pamięcią. Dopóki masz 1-2 procesory możesz się tym praktycznie nie przejmować, ale przy większej liczbie musisz
się zastanowić czy czasy "transportu danych" i synchronizacji pamięci (cache<->RAM) nie spowodują jakichś dodatowych problemów.
Jeśli mamy dużą ilość rdzeni, np. te 256, to w celu pełnego wykorzystania, mamy dwie możliwości:
1) odpalić kilka aplikacji niezależnie.
2) odpalić jedną na 256 wątkach.
Zalety 1)
-każda aplikacja działa na lokalnych danych, nie ma kosztów transferów, jest więcej trafień w cache.
Zalety 2)
- aplikacja ma do dyspozycji ogromną ilość RAM - można lepiej ochronić przed liczeniem tych samych pod-zadań,
- w ogóle można znaleźć i odrzucić więcej takich samych pod-zadań.
Co się opłaci? Oczywiście zależy od kosztów transferów. Jednak ogromna pamięć tak mocno
przyspiesza, że ja choć nie wiem, to mocno obstawiam wersję drugą.
Cytat: Karlik w 30 Maj 2013, 17:12
Poza tym nie wiem jak sobie wyobrażasz opcje konfiguracyjne dla klienta. Miałby po jednym profilu dla każdego komputera, żeby
mógł sobie ustawić ile rdzeni chce przeznaczyć na obliczenia? Albo będziesz procentową liczbę dostępnych brał (nie wiem jak
rozróżnisz fizyczne od wirtualnych - chyba musiałbyś sobie zrobić katalog wszystkich procesorów z HT). Tylko wtedy wymuszasz
na użytkowniku: albo liczysz moje albo cudze, jednocześnie nie pozwalam. :/ Nie chcę bombardować pomysłu, ale jakoś nie potrafię
znaleźć rozwiązania optymalnego tej sytuacji.
Nie wiem jak to wygodnie rozwiązać. Najlepiej jakby użytkownik się znał i wpisał ręcznie sam :D Można też zrobić benchmark. W benchmarku
program będzie zwiększał sobie ilość rdzeni i pamięci tak długo, aż zacznie spowalniać - ale to też jest związane z problemami.
Pozdrawiam i dzięki.
Cytat: sknd w 30 Maj 2013, 17:30
threadMemPerft 10 6 259200000 5 10000000
nodes:69352859712417 time:13683
zrobione na e3-1230 v2 przy dwóch rdzeniach boincujących ;)
Dzięki, dodane do tabelki.
Cytat: krzyszp w 30 Maj 2013, 17:08
Jak najbardziej za :)
natomiast pomyślałbym już o stawianiu serwera pod boinc - w końcu możesz wygodnie wysyłać za jego pomocą próbki do znacznie większej ilości komputerów z różną konfiguracją, a i wyniki testów będziesz miał szybciej...
No cóż, to już są powalające argumenty, a są jeszcze inne za BOINC...
Będzie trzeba tak zrobić. Najgorzej z konfiguracją, poprzednio mi się nie udało :/
Spróbuję jeszcze raz.
Cytat: krzyszp w 30 Maj 2013, 17:08
Może TJM mógłby Ci pomóc postawić serwer? Oczywiście, musiałbyś zrobić zamknięte testy próbek, bo bez sensu by było na tę chwilę marnować czas na tłumaczenia "co i jak" światu... A i wprawy w zarządzaniu serwerem mógłbyś nabrać.
Muszę się nauczyć.
Więc przygotujcie się, że zasypię was wkrótce masą lamerskich pytań :D
Pozdrawiam
P.S.
Jaki dział forum jest na pytania o konfigurację serwera?
Ja mogę udostępnić kawałek OProject@Home. Aplikacja jednak musi być raczej jednowątkowa. Nie wiem też jak z dostosowywaniem jej do BOINC - większością spraw mogę się zająć ale częścią już nie.
Nowy admin by się przydał :parrrty:
Cytat: Rysiu w 30 Maj 2013, 18:12
Ja mogę udostępnić kawałek OProject@Home. Aplikacja jednak musi być raczej jednowątkowa. Nie wiem też jak z dostosowywaniem jej do BOINC - większością spraw mogę się zająć ale częścią już nie.
Nowy admin by się przydał :parrrty:
Przy dostosowywaniu aplikacji do BOINC będę miał problemy, ale raczej małe, raczej dam radę.
Ilość wątków się ustawia, można ustawić jeden lub sto, można ustawić na stałe, może użytkownik ustawiać, obojętnie.
Boję się tej całej instalacji i konfiguracji, tutaj mogę potrzebować dużo pomocy.
Pozdrawiam
threadMemPerft5 10 8 580000000 8 1000000 - nodes:69352859712417 time:10352
Nowa tabelka
------------------------------------------------------------------------------------------------------------------
Wersja | Procesor | polecenie | wynik | czas | user
------------------------------------------------------------------------------------------------------------------
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 1000000 | 69352859710032! | 63547s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 1 0 | 69352859712417ok | 41515s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 0 | 69352859712417ok | 30042s |
1 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 200 | 69352859712417ok | 25889s |
2[1]| Phenom II 1050T 2.4GHz | threadMemPerft5 10 6 250000000 8 1000000 | 69352859712417ok | 24071s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 12 10000000 | 69352859712417ok | 18111s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 50000000 | 69352859712417ok | 17781s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 10000000 | 69352859712417ok | 17768s |
2 | Phenom II 1050T 2.4GHz | threadMemPerft5 10 6 250000000 12 1000000 | 69352859712417ok | 15643s |
2 | Phenom II 1050T 2.4GHz | threadMemPerft5 10 6 250000000 5 1000000 | 69352859712417ok | 15251s |
2 | Phenom II 1050T 2.4GHz | threadMemPerft5 10 6 250000000 8 1000000 | 69352859712417ok | 15186s |
3 | Phenom II 1050T 2.4GHz | threadMemPerft6 10 6 250000000 8 1000000 | 69352859712417ok | 13618s |
3 | Phenom II 1050T 2.4GHz | threadMemPerft6 10 6 250000000 8 10000000 | 69352859712417ok | 13599s |
0 | Q6600 | threadMemPerft 10 5 50000000 8 1000000 | 69352859712417ok | 42144s | krzyszp
2 | Q6600 | threadMemPerft5 10 4 50000000 8 10000000 | 69352859712417ok | 37149s | krzyszp
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 0 | 69352859712417ok | 21051s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 200 | 69352859712417ok | 16967s |
0 | i7 950 @3.07GHz | threadMemPerft2 10 5 56250000 8 1 | 69352859712417ok | 13667s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 1000000 | 69352859712417ok | 12173s |
2 | i7 950 @3.07GHz | threadMemPerft5 10 4 450000000 8 10000000 | 69352859712417ok | 12144s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 10000000 | 69352859712417ok | 12092s |
2 | i7 950 @3.07GHz | threadMemPerft5 10 5 450000000 8 10000000 | 69352859712417ok | 11475s |
2 | i7 950 @3.07GHz | threadMemPerft5 10 5 450000000 5 10000000 | 69352859712417ok | 11396s |
3 | i7 950 @3.07GHz | threadMemPerft6 10 5 450000000 8 30000000 | 69352859712417ok | 10359s |
3 | i7 950 @3.07GHz | threadMemPerft6 10 5 450000000 8 10000000 | 69352859712417ok | 10341s |
0 | e3-1230 v2 3.3ghz | threadMemPerft 10 6 259200000 8 200 | 69352859712417ok | 16895s | sknd
2[2]| e3-1230 v2 3.3ghz | threadMemPerft 10 6 259200000 5 10000000 | 69352859712417ok | 13683s | sknd
0 | e3-1230 v2 3.3ghz | threadMemPerft2 10 6 32400000 8 1 | 69352859712417ok | 13085s | sknd
2 | e3-1230 v2 3.3ghz | threadMemPerft5 10 4 259200000 8 10000000 | 69352859712417ok | 12730s | sknd
0 | e3-1230 v2 3.3ghz | threadMemPerft2 10 6 32400000 8 7 | 69352859712417ok | 11709s | sknd
2 | Q9400 | threadMemPerft2 10 4 6250000 8 6 | 69352859712417ok | 34954s | patyczak
2 | Q9400 | threadMemPerft5 10 4 50000000 8 10000000 | 69352859712417ok | 32666s | patyczak
2 | AMD 48core | threadMemPerft5 10 4 580000000 8 1000000 | 69352859712417ok | 19820s | AXm77
2 | AMD 48core | threadMemPerft5 10 8 580000000 8 1000000 | 69352859712417ok | 10352s | AXm77
2 | AMD 48core | threadMemPerft5 10 16 580000000 8 1000000 | 69352859712417ok | 5362s | AXm77
2 | AMD 48core | threadMemPerft5 10 24 580000000 8 1000000 | 69352859712417ok | 3709s | AXm77
2 | AMD 48core | threadMemPerft5 10 32 580000000 8 1000000 | 69352859712417ok | 2883s | AXm77
2 | AMD 48core | threadMemPerft5 10 52 580000000 8 1000000 | 69352859712417ok | 2074s | AXm77
2 | AMD 48core | threadMemPerft5 10 48 580000000 8 1000000 | 69352859712417ok | 2065s | AXm77
------------------------------------------------------------------------------------------------------------------
[1] - z tej wersji prawdopodobnie zapomniałem usunąć asercje i spowolniły program.
[2] - dwa rdzenie komputera były obciążone
Byłem już sceptyczny, ale są rekordowe czasy na dwóch różnych komputerach.
Na dużych głębokościach polecenie threadMemPerft6 działa wyraźnie szybciej, choć
na małych nie było żadnego efektu. Zatem udostępniam trzecią wersję programu :D
Z poleceniem threadMemPerft6 można tak samo kombinować jak z threadMemPerft5 - parametry
w piątce i szóstce mają takie samo znaczenie, zmienił się tylko algorytm.
Pozdrawiam
Czyli jak coś liczę na drugiej wersji programu to lepiej przerwać i liczyć na trzeciej wersji czy dokończyć?
Cytat: patyczak w 30 Maj 2013, 20:14
Czyli jak coś liczę na drugiej wersji programu to lepiej przerwać i liczyć na trzeciej wersji czy dokończyć?
Można dokończyć. Potem będzie więcej materiału do porównania z następnymi wynikami :)
Ja też jestem za tym, by ten program był jednowątkowy, bo to znacznie upraszcza sprawę. Nie ma takich problemów jak np. z Yafu, który liczy serię zadań, powiedzmy na 16 rdzeniach, i czeka aż wszystkie 16 się skończy. Dopiero wtedy znów zapodaje 16 nowych zadań. Nie trzeba mówić, że niektóre zadania kończą się znacznie szybciej, więc pozostały czas tych rdzeni jest "marnowany".
Można by było zrobić tak jak w OPTIMA@home, gdzie zadania są ściągane praktycznie na bieżąco (po zwrocie poprzedniego WU) i wtedy serwer kształtowałby listę zadań na bieżąco.
Kolejny wynik (druga wersja programu):
threadMemPerft2 10 4 6250000 8 6
nodes:69352859712417 time:34954
Q9400
Cytat: Dario666 w 30 Maj 2013, 21:23
Ja też jestem za tym, by ten program był jednowątkowy, bo to znacznie upraszcza sprawę. Nie ma takich problemów jak np. z Yafu, który liczy serię zadań, powiedzmy na 16 rdzeniach, i czeka aż wszystkie 16 się skończy. Dopiero wtedy znów zapodaje 16 nowych zadań. Nie trzeba mówić, że niektóre zadania kończą się znacznie szybciej, więc pozostały czas tych rdzeni jest "marnowany".
Trochę boję się chwalić przedwcześnie, ale te problemy mam chyba całkiem ładnie
rozwiązane, zwłaszcza w najnowszej wersji. Wątki równo startują i równo się kończą -
przynajmniej bardzo starałem się uzyskać taki efekt. Można włączyć monitor systemu,
ustawić tick czasu na 5-10s, nasŧepnie można odpalić program na jakiś test który
trwa chociaż z 1000 sekund i na wykresie pokaże się nam obciążenie rdzeni w czasie.
Problem pod-zadań też mam przemyślany. Program za jednym razem ściągnie 20-100
pod-zadań. Następnie każde z pod-zadań dzielone jest na wiele jeszcze mniejszych
tasków. Te najmniejsze taski są ustawiane w kolejce, a wątki pobierają je z kolejki. Jak
ustawimy jeden wątek, to z kolejki będzie pobierał jeden wątek i system będzie obciążony
jednym wątkiem - nie będzie to stanowiło żadnego problemu. Jak ktoś zdecyduje się
na liczenie w pięciu wątkach, to system będzie obciążony pięcioma, a kolejka prawie
pięć razy szybciej się opróżni. Każdy będzie mógł aplikację używać zgodnie ze swoimi
preferencjami - podobnie sprawa tyczy się pamięci - każdy udostępni aplikacji tyle RAM,
ile uzna za stosowne. Aplikacja po prostu jest tak napisana, żeby umiała wykorzystać wszystko
co użytkownik zdecyduje się jej udostępnić, a przynajmniej tak się starałem :D
Tak czy inaczej, aplikacja może z powodzeniem pracować jako jednowątkowa.
Pewnie jeszcze niepokojąca jest sprawa dlaczego ma pobierać 20-100 zadań za
jednym razem. Otóż jestem prawie pewny, że 100 zadań "jednocześnie" policzy się
znacznie szybciej niż te same 100 zadań jedno po drugim. Nie wiem jakie to
będzie przyspieszenie, ale może być duże... rzędu 2-3 razy. Jeśli czekanie
przez pół doby na zakończenie będzie niewygodne, to dorobimy jakieś save-owanie.
Cytat: Dario666 w 30 Maj 2013, 21:23
Można by było zrobić tak jak w OPTIMA@home, gdzie zadania są ściągane praktycznie na bieżąco (po zwrocie poprzedniego WU) i wtedy serwer kształtowałby listę zadań na bieżąco.
Efekt dla użytkownika będzie podobny. Program ściągnie zadanie, a potem odeśle wyniki.
Właściwie to użytkownik może nawet nie zauważyć, że ściąga paczkę zadań, a nie jedno
zadanie.
Pozdrawiam
Cytat: patyczak w 30 Maj 2013, 21:55
Kolejny wynik (druga wersja programu):
threadMemPerft2 10 4 6250000 8 6
nodes:69352859712417 time:34954
Q9400
Czyli
piątka wgrała? :D
Pozdrawiam
Cytat: mariotti w 30 Maj 2013, 22:25
Cytat: patyczak w 30 Maj 2013, 21:55
Kolejny wynik (druga wersja programu):
threadMemPerft2 10 4 6250000 8 6
nodes:69352859712417 time:34954
Q9400
Czyli piątka wgrała? :D
Na to wygląda ;D
Cytat: AXm77 w 30 Maj 2013, 19:38
threadMemPerft5 10 8 580000000 8 1000000 - nodes:69352859712417 time:10352
Zastanawiam się, czy jest sens testów na mniejszej ilości niż 4 rdzenie. Może w tym
czasie lepiej zrobić analogiczny test dla wersji threadMemPerft
6?
Poza tym niektóre procesory gdy pracują na jednym wątku to potrafią przyspieszyć
zegar, więc na małej ilości wątków może nam wyjść dobry czas, ale spowodowany
czymś innym niż zła skalowalność :)
Pozdrawiam
Doliczę te 4 (jeszcze jakieś 2 godziny - tak przewiduje).
Opterony 6176 nie mają turbo, także po obciążeniem zawsze będzie 2.3 max.
Planuję jeszcze na "5" przeliczyć 12 i 36 (czyli obciążenie całego jednego i trzech procesorów.)
Cytat: AXm77 w 30 Maj 2013, 22:54
Doliczę te 4 (jeszcze jakieś 2 godziny - tak przewiduje).
Opterony 6176 nie mają turbo, także po obciążeniem zawsze będzie 2.3 max.
Fajnie, dzięki.
W sumie odnośnie procesów i wątków przyszło mi do głowy takie rozwiązanie ze względu na podejście, które opisałeś (w sumie bazuje na ogólnych zasadach działania systemów rozproszonych):
1. Uruchom program.
2. Spróbuj się podłączyć do istniejącej puli zasobów.
3. Udało się - wykonuj te zadania.
4. Nie udało się - zostań masterem i stwórz interfejs do podłączenia się innych procesów.
Wtedy możnaby względnie dynamicznie z poziomu klienta zmieniać liczbę wątków, które w danym momencie mają pracować. Teraz pojawia się innego rodzaju problem - przydział zadań. Nie pisałem nic po stronie boincowego serwera, ale można spróbować zrobić coś takiego, że wysyłamy próbki z tymi samymi danymi w liczbie takiej jak mu ustawimy w opcjach lub liczbie rdzeni procesora. Potem już procesy po stronie klienta się martwią jak to ogarnąć (patrz wyżej), potem master wysyła gotowe dane a reszta nic (albo te same dane). Jeżeli checkpointy będziemy zapisywać w folderze projektu a nie slotu to raczej dałoby się coś takiego zrobić (wtedy nie ma znaczenia kolejność wznawiania procesów - po prostu najwcześniej uruchomiony robi za mastera). Gdybyśmy jednak uruchamiali te procesy po kolei, trzebaby po prostu spowodować wyłączenie procesu jeżeli wcześniej już wszystko w obrębie próbki zostało przeliczone (wystarczy stwierdzić, że nie ma pliku wejściowego albo coś w tym stylu).
Cytat: Karlik w 30 Maj 2013, 23:22
W sumie odnośnie procesów i wątków przyszło mi do głowy takie rozwiązanie ze względu na podejście, które opisałeś (w sumie bazuje na ogólnych zasadach działania systemów rozproszonych):
1. Uruchom program.
2. Spróbuj się podłączyć do istniejącej puli zasobów.
3. Udało się - wykonuj te zadania.
4. Nie udało się - zostań masterem i stwórz interfejs do podłączenia się innych procesów.
W ogóle to jest fajna strategia. Taki program żyje sam własnym życiem i nie potrzebuje jednego
centralnego systemu. Myślałem żeby w ten sposób zrobić program do samouczenia. Na każdym
kliencie program próbuje nowej strategii. Jeśli nowa strategia wydaje się dobra, to prosi dowolnego
losowego klienta o przetestowanie takiej samej. Tamten mu odpowiada czy też się udało czy nie.
Jeśli się udało, to porównuje ze swoją najlepszą. Ostatecznie strategia otrzymuje tym większą
rangę im częściej była testowana, a przeżycie strategii w środowisku rozproszonym zależałoby
tylko od tej rangi. Najlepsze szybko by się propagowały, gorsze by umierały, potem z najlepszych
ewoluowałyby jeszcze lepsze... Koncepcyjnie taki pomysł jest prosty i fajny, ale realizacja to
masakryczny nakład pracy :)
Czy taka strategia nadaje się do tego problemu, który tylko zlicza węzły? Myślę że tak. Ale
cała baza zadań jest zbyt duża, aby każdy klient miał jej kopię. Zatem klient musiałby mieć
tylko jakiś seed, a na jego podstawie mógłby ustalić za jaką część bazy jest odpowiedzialny.
Bazę można podzielić na setki albo tysiące takich części. Gdy taki klient nie może połączyć się z
żadnym innym, to realizuje losowe-niewykonane zadania ze swojej bazy. Gdy może się połączyć, to dokonuje
synchronizacji. Niektóre klienty wygenerują błędne obliczenia, więc jeśli coś zostanie policzone
nadmiarowo to nawet lepiej. W końcu gdy klient miałby wszystkie wyniki dla swojej części bazy, to
by je wysłał na maszynę centralną - czyli jednak jakaś maszyna centralna musi być, choćby o
takim marginalnym znaczeniu :)
No ale znów dochodzimy do czegoś, co koncepcyjnie jest proste, a w realizacji masakra :)
Cytat: Karlik w 30 Maj 2013, 23:22
Wtedy możnaby względnie dynamicznie z poziomu klienta zmieniać liczbę wątków, które w danym momencie mają pracować. Teraz pojawia się innego rodzaju problem - przydział zadań. Nie pisałem nic po stronie boincowego serwera, ale można spróbować zrobić coś takiego, że wysyłamy próbki z tymi samymi danymi w liczbie takiej jak mu ustawimy w opcjach lub liczbie rdzeni procesora. Potem już procesy po stronie klienta się martwią jak to ogarnąć (patrz wyżej), potem master
Można zrobić jeszcze lepszy hardcore, taki żeby mastera prawie nie było :D
Master tylko daje 1000 wersji programu do pobrania, każda wersja ma inny seed - czyli
ta część serwera to serwer FTP :D Potem program działają jak wirus - z taką tylko różnicą że
klonują się za zgodą właściciela komputera. Ostatecznie na mastera wysyłają dane.
A może nawet by nie musiały na mastera wysyłać wyników :D
Cytat: Karlik w 30 Maj 2013, 23:22
wysyła gotowe dane a reszta nic (albo te same dane). Jeżeli checkpointy będziemy zapisywać w folderze projektu a nie slotu to raczej dałoby się coś takiego zrobić (wtedy nie ma znaczenia kolejność wznawiania procesów - po prostu najwcześniej uruchomiony robi za mastera). Gdybyśmy jednak uruchamiali te procesy po kolei, trzebaby po prostu spowodować wyłączenie procesu jeżeli wcześniej już wszystko w obrębie próbki zostało przeliczone (wystarczy stwierdzić, że nie ma pliku wejściowego albo coś w tym stylu).
Nom fajne to wszystko, ale za dużo roboty...
Zrobimy standardowo, czyli synchronizacja na centralnym serwerze :)
Pozdrawiam
threadMemPerft5 10 4 580000000 8 1000000 - nodes:69352859712417 time:19820
Cytat: AXm77 w 31 Maj 2013, 01:05
threadMemPerft5 10 4 580000000 8 1000000 - nodes:69352859712417 time:19820
Dodane do tabelki powyżej.
Pozdrawiam
Niezłe przyśpieszenie na "6"-tce: :)
threadMemPerft6 10 52 580000000 8 1000000 - nodes:69352859712417 time:1658
threadMemPerft6 10 48 580000000 8 1000000 - nodes:69352859712417 time:1642
threadMemPerft6 10 32 580000000 8 1000000 - nodes:69352859712417 time:2383
threadMemPerft6 10 24 580000000 8 1000000 - nodes:69352859712417 time:3080
Cytat: AXm77 w 31 Maj 2013, 06:01
Niezłe przyśpieszenie na "6"-tce: :)
threadMemPerft6 10 52 580000000 8 1000000 - nodes:69352859712417 time:1658
threadMemPerft6 10 48 580000000 8 1000000 - nodes:69352859712417 time:1642
threadMemPerft6 10 32 580000000 8 1000000 - nodes:69352859712417 time:2383
threadMemPerft6 10 24 580000000 8 1000000 - nodes:69352859712417 time:3080
Dziękuję. Niezła maszynka do liczenia.
Ciekawy jestem kilku rzeczy....
Po pierwsze jakby ta aplikacja bez przeróbek działała na klastrze, np. na 6ciu komputerach i każdy
komputer z jednym procesorem 8-rdzeniowym . Po drugie jakby działała po przystosowaniu do obliczeń
na klastrze. Po trzecie jakby działała tak po prostu na jakimś amazonie. Apropo... czy orientuj się
ktoś ile na amazonie kosztuje wynajęcie np. 100 rdzeni na 1 godzinę? Jeśli niedrogo, to można
spróbować :) Jeszcze jedna rzecz mnie ciekawi, jak aplikacja by się zachowała na kompie z
ogromną ilością pamięci, np. 1TB ramu. Rysiu załatwił mi do testów maszynkę która ma 256GB ram,
ale dopiero uczę się obsługi :)
Pozdrawiam
Nowa tabelka
------------------------------------------------------------------------------------------------------------------
Wersja | Procesor | polecenie | wynik | czas | user
------------------------------------------------------------------------------------------------------------------
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 1000000 | 69352859710032! | 63547s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 1 0 | 69352859712417ok | 41515s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 0 | 69352859712417ok | 30042s |
1 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 200 | 69352859712417ok | 25889s |
2[1]| Phenom II 1050T 2.4GHz | threadMemPerft5 10 6 250000000 8 1000000 | 69352859712417ok | 24071s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 12 10000000 | 69352859712417ok | 18111s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 50000000 | 69352859712417ok | 17781s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 10000000 | 69352859712417ok | 17768s |
2 | Phenom II 1050T 2.4GHz | threadMemPerft5 10 6 250000000 12 1000000 | 69352859712417ok | 15643s |
2 | Phenom II 1050T 2.4GHz | threadMemPerft5 10 6 250000000 5 1000000 | 69352859712417ok | 15251s |
2 | Phenom II 1050T 2.4GHz | threadMemPerft5 10 6 250000000 8 1000000 | 69352859712417ok | 15186s |
3 | Phenom II 1050T 2.4GHz | threadMemPerft6 10 6 250000000 8 1000000 | 69352859712417ok | 13618s |
3 | Phenom II 1050T 2.4GHz | threadMemPerft6 10 6 250000000 8 10000000 | 69352859712417ok | 13599s |
0 | Q6600 | threadMemPerft 10 5 50000000 8 1000000 | 69352859712417ok | 42144s | krzyszp
2 | Q6600 | threadMemPerft5 10 4 50000000 8 10000000 | 69352859712417ok | 37149s | krzyszp
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 0 | 69352859712417ok | 21051s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 200 | 69352859712417ok | 16967s |
0 | i7 950 @3.07GHz | threadMemPerft2 10 5 56250000 8 1 | 69352859712417ok | 13667s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 1000000 | 69352859712417ok | 12173s |
2 | i7 950 @3.07GHz | threadMemPerft5 10 4 450000000 8 10000000 | 69352859712417ok | 12144s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 10000000 | 69352859712417ok | 12092s |
2 | i7 950 @3.07GHz | threadMemPerft5 10 5 450000000 8 10000000 | 69352859712417ok | 11475s |
2 | i7 950 @3.07GHz | threadMemPerft5 10 5 450000000 5 10000000 | 69352859712417ok | 11396s |
3 | i7 950 @3.07GHz | threadMemPerft6 10 5 450000000 8 30000000 | 69352859712417ok | 10359s |
3 | i7 950 @3.07GHz | threadMemPerft6 10 5 450000000 8 10000000 | 69352859712417ok | 10341s |
0 | e3-1230 v2 3.3ghz | threadMemPerft 10 6 259200000 8 200 | 69352859712417ok | 16895s | sknd
2[2]| e3-1230 v2 3.3ghz | threadMemPerft 10 6 259200000 5 10000000 | 69352859712417ok | 13683s | sknd
0 | e3-1230 v2 3.3ghz | threadMemPerft2 10 6 32400000 8 1 | 69352859712417ok | 13085s | sknd
2 | e3-1230 v2 3.3ghz | threadMemPerft5 10 4 259200000 8 10000000 | 69352859712417ok | 12730s | sknd
0 | e3-1230 v2 3.3ghz | threadMemPerft2 10 6 32400000 8 7 | 69352859712417ok | 11709s | sknd
2 | Q9400 | threadMemPerft2 10 4 6250000 8 6 | 69352859712417ok | 34954s | patyczak
2 | Q9400 | threadMemPerft5 10 4 50000000 8 10000000 | 69352859712417ok | 32666s | patyczak
2 | AMD 48core | threadMemPerft5 10 4 580000000 8 1000000 | 69352859712417ok | 19820s | AXm77
2 | AMD 48core | threadMemPerft5 10 8 580000000 8 1000000 | 69352859712417ok | 10352s | AXm77
2 | AMD 48core | threadMemPerft5 10 16 580000000 8 1000000 | 69352859712417ok | 5362s | AXm77
2 | AMD 48core | threadMemPerft5 10 24 580000000 8 1000000 | 69352859712417ok | 3709s | AXm77
2 | AMD 48core | threadMemPerft6 10 24 580000000 8 1000000 | 69352859712417ok | 3080s | AXm77
2 | AMD 48core | threadMemPerft5 10 32 580000000 8 1000000 | 69352859712417ok | 2883s | AXm77
2 | AMD 48core | threadMemPerft6 10 32 580000000 8 1000000 | 69352859712417ok | 2383s | AXm77
2 | AMD 48core | threadMemPerft5 10 52 580000000 8 1000000 | 69352859712417ok | 2074s | AXm77
2 | AMD 48core | threadMemPerft5 10 48 580000000 8 1000000 | 69352859712417ok | 2065s | AXm77
2 | AMD 48core | threadMemPerft6 10 52 580000000 8 1000000 | 69352859712417ok | 1658s | AXm77
2 | AMD 48core | threadMemPerft6 10 48 580000000 8 1000000 | 69352859712417ok | 1642s | AXm77
------------------------------------------------------------------------------------------------------------------
[1] - z tej wersji prawdopodobnie zapomniałem usunąć asercje i spowolniły program.
[2] - dwa rdzenie komputera były obciążone
Cytat: mariotti w 30 Maj 2013, 22:20
Jeśli czekanie przez pół doby na zakończenie będzie niewygodne, to dorobimy jakieś save-owanie.
No, to jest sprawa podstawowa :p_arr:
Cytat: sknd w 31 Maj 2013, 07:35
Cytat: mariotti w 30 Maj 2013, 22:20
Jeśli czekanie przez pół doby na zakończenie będzie niewygodne, to dorobimy jakieś save-owanie.
No, to jest sprawa podstawowa :p_arr:
Zależy ile czasu będzie się wykonywał jeden task. A czas wykonania jednego
tasku zależy od tego, jak mi się uda przyspieszyć program. Zależy także od
tego, czy opłaci się do jednego tasku upakować 5 układów czy może 100.
Pozdrawiam
threadMemPerft6 10 16 580000000 8 1000000 - nodes:69352859712417 time:4593
threadMemPerft6 10 8 580000000 8 1000000 - nodes:69352859712417 time:9095
threadMemPerft6 10 4 580000000 8 1000000 - nodes:69352859712417 time:18154
Panowie nie chcę nikogo trochę hamować ale niestety większości ze spraw o których tutaj jest pisane odnośnie obliczeń rozproszonych nie ma najmniejszych szans realizacji.
Droga od postawienia serwera BOINC do czegoś takiego o czym piszecie jest bardzo długa i zawiła. Jak czytałem mówimy tutaj o serwerze master, który dosyła dane do klientów i o jakimś skalowaniu wątków, wewnętrznych benchmarkach oraz aplikacjach działających na różnej ilości wątków. Niestety 99% z tego trzeba wsadzić do kosza. Nawet najlepsze projekty różnie działają, a różnica między pierwszym projektem, który sobie na szybkiego odpalimy a czołówką najlepszych jest gigantyczna.
Do czegoś takiego najprawdopodobniej łatwiej byłoby napisać własny soft w postaci klienta i serwera i udostępnić liczącym. Wtedy mamy całkowitą dowolność i pisząc całość od zera w technologii, którą znamy możemy coś takiego zrobić.
Tak napisać, że serwer ma robić X, a klient to będzie sobie pobierać Y i skalować odpowiednio tylko wątki to prosto. Problem jednak zamknie się na tym, że podczas konfiguracji wyskoczy jeden błąd i będzie kaplica. Alarmuję więc - nie twórzmy wielkich teorii o tym jak ma działać serwer BOINC, a dostosujmy się do tego jak jest on skonstruowany.
Koncepcja podstawowej aplikacji BOINC jest szalenie prosta.
1. Serwer tworzy zadanie
2. Klient pobiera aplikację liczącą i zadanie
3. Klient wykonuje obliczenia sekwencyjnie na jednym wątku i zapisuje wyniki do pliku
4. Klient odsyła dane (także plik wyniku) do serwera
5. Serwer analizuje nadesłane dane
Nie ma tutaj miejsca na jakąkolwiek komunikację w środku wykonywania zadania. Jedyna znacząca komunikacja to pobieranie zadania i odsyłanie wyników. Zadania także nie mogą być liczone w dziesiątkach czy też setkach na jednym kliencie w jakimś krótkim odcinku czasowym. Żaden serwer BOINC tego nie obsłuży. Każde zadanie powinno wykonywać się przynajmniej godzinę.
Znak zapytania bym postawił przy samych aplikacjach wielowątkowych, pomimo, że takie BOINC wspiera.
Przepraszam za takie oblanie zimną wodą ale niestety tak to wygląda. Oczywiście można zrobić wszystko - pytanie tylko czy ktoś zdoła obejść wszystkie problemy. Wydaje mi się, że nie jest to tego kalibru problem aby pisać pod niego na nowo pół środowiska serwera BOINC.
Jest jeszcze taki myk, że serwer może nam podesłać duże zadanie i klient może odsyłać wyniki cząstkowe za pomocą Trickle.
A także drugi myk - user może dla każdego hosta ustawiać ile rdzeni ma liczyć poprzez preferencje.
threadMemPerft6 10 48 580000000 8 1000000 - nodes:69352859712417 time:1642
threadMemPerft6 10 48 580000000 5 1000000 - nodes:69352859712417 time:1617
threadMemPerft6 10 48 580000000 5 10000000 - nodes:69352859712417 time:1613
Jak widać powyżej zmiana przedostatniej zmiennej poprawiła minimalnie wynik. Jaka jest najmniejsza wartość tej zmiennej?
Cytat: AXm77 w 31 Maj 2013, 16:32
threadMemPerft6 10 48 580000000 8 1000000 - nodes:69352859712417 time:1642
threadMemPerft6 10 48 580000000 5 1000000 - nodes:69352859712417 time:1617
threadMemPerft6 10 48 580000000 5 10000000 - nodes:69352859712417 time:1613
Jak widać powyżej zmiana przedostatniej zmiennej poprawiła minimalnie wynik. Jaka jest najmniejsza wartość tej zmiennej?
Dziękuję za kolejne testy. Kolejna wersja algorytmu działa u mnie wyraźnie gorzej, więc nie
udostępniam dziś nowej. Będę musiał popracować teraz nad:
1) serwerem boinc
2) optymalizacją liniową
Obie rzeczy zajmą mi sporo czasu, więc następne wersje do testowania mogą pojawiać się w
dłuższych odstępach czasu.
---------------------------------------------------------------------------------------------------------
Znaczenie parametrów w komendzie:
threadMemPerft6 depth max_thread hsize hprobe forgetdepth - oczywiście głębokość przeszukiwania
max_thread - maksymalna ilość wątków obciążających
hsize - rozmiar hash-table w elementach, jeden element to 24 bajty
hprobe - ten parametr decyduje o tym jak długo program ma szukać po
pierwsze elementu najgorszego a po drugie elementu w którym został zapisany
dany układ. Układy często powtarzają się, więc po obliczeniach program
zapamiętuje wyniki w hash-table, a przed obliczeniami sprawdza czy nie ma w
niej gotowego wyniku. Parametr
hprobe decyduje o tym ile elementów
program ma przeszukać w trakcie szukania wyników. Im więcej przeszuka, tym
bardziej go to spowolni, ale sprawa nie jest taka prosta. Niektóre pod-zadania są
bardziej czasochłonne, inne mniej. Jeśli parametr hprobe jest duży, to program
przeszuka więcej elementów także w takim celu, alby znaleźć element najgorszy.
Najgorszy czyli taki, z którego zapamiętania są (potencjalnie) najmniejsze korzyści.
W skrócie: mała wartość tego parametru powoduje że program szybko
wyszukuje, ale może usunąć ważny element. Duża wartość powoduje, że
program wyszukuje długo i go to spowalnia, ale usuwa mało przydatne
elementy.
Optymalna wartość tego parametru leży w granicach od 1 do 20, a bardziej
prawdopodobnie w przedziale od 3 do 12.
forget - ten parametr to bonus dla nowych układów. Układy warto przechowywać w
hash-table gdy po pierwsze dają duże oszczędności, a po drugie gdy są nowe. Wyjaśnienie
dlaczego warto przechowywać nowe układy które dają mniej oszczędności niż stare jest
dość zawiłe, więc je pominę. Im większą wartość nadamy temu parametrowi, tym bardziej
będą preferowane nowe układy. Optymalnej wartości nie znam, ani nawet nie potrafię
oszacować w jakim ona leży przedziale. Dozwolone wartości są od zera do ponad 4 miliardów.
Poniżej aktualna tabelka:
------------------------------------------------------------------------------------------------------------------
Wersja | Procesor | polecenie | wynik | czas | user
------------------------------------------------------------------------------------------------------------------
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 1000000 | 69352859710032! | 63547s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 1 0 | 69352859712417ok | 41515s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 0 | 69352859712417ok | 30042s |
1 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 200 | 69352859712417ok | 25889s |
2[1]| Phenom II 1050T 2.4GHz | threadMemPerft5 10 6 250000000 8 1000000 | 69352859712417ok | 24071s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 12 10000000 | 69352859712417ok | 18111s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 50000000 | 69352859712417ok | 17781s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 10000000 | 69352859712417ok | 17768s |
2 | Phenom II 1050T 2.4GHz | threadMemPerft5 10 6 250000000 12 1000000 | 69352859712417ok | 15643s |
2 | Phenom II 1050T 2.4GHz | threadMemPerft5 10 6 250000000 5 1000000 | 69352859712417ok | 15251s |
2 | Phenom II 1050T 2.4GHz | threadMemPerft5 10 6 250000000 8 1000000 | 69352859712417ok | 15186s |
3 | Phenom II 1050T 2.4GHz | threadMemPerft6 10 6 250000000 8 1000000 | 69352859712417ok | 13618s |
3 | Phenom II 1050T 2.4GHz | threadMemPerft6 10 6 250000000 8 10000000 | 69352859712417ok | 13599s |
0 | Q6600 | threadMemPerft 10 5 50000000 8 1000000 | 69352859712417ok | 42144s | krzyszp
2 | Q6600 | threadMemPerft5 10 4 50000000 8 10000000 | 69352859712417ok | 37149s | krzyszp
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 0 | 69352859712417ok | 21051s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 200 | 69352859712417ok | 16967s |
0 | i7 950 @3.07GHz | threadMemPerft2 10 5 56250000 8 1 | 69352859712417ok | 13667s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 1000000 | 69352859712417ok | 12173s |
2 | i7 950 @3.07GHz | threadMemPerft5 10 4 450000000 8 10000000 | 69352859712417ok | 12144s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 10000000 | 69352859712417ok | 12092s |
2 | i7 950 @3.07GHz | threadMemPerft5 10 5 450000000 8 10000000 | 69352859712417ok | 11475s |
2 | i7 950 @3.07GHz | threadMemPerft5 10 5 450000000 5 10000000 | 69352859712417ok | 11396s |
3 | i7 950 @3.07GHz | threadMemPerft6 10 5 450000000 8 30000000 | 69352859712417ok | 10359s |
3 | i7 950 @3.07GHz | threadMemPerft6 10 5 450000000 8 10000000 | 69352859712417ok | 10341s |
0 | e3-1230 v2 3.3ghz | threadMemPerft 10 6 259200000 8 200 | 69352859712417ok | 16895s | sknd
2[2]| e3-1230 v2 3.3ghz | threadMemPerft 10 6 259200000 5 10000000 | 69352859712417ok | 13683s | sknd
0 | e3-1230 v2 3.3ghz | threadMemPerft2 10 6 32400000 8 1 | 69352859712417ok | 13085s | sknd
2 | e3-1230 v2 3.3ghz | threadMemPerft5 10 4 259200000 8 10000000 | 69352859712417ok | 12730s | sknd
0 | e3-1230 v2 3.3ghz | threadMemPerft2 10 6 32400000 8 7 | 69352859712417ok | 11709s | sknd
2 | Q9400 | threadMemPerft2 10 4 6250000 8 6 | 69352859712417ok | 34954s | patyczak
2 | Q9400 | threadMemPerft5 10 4 50000000 8 10000000 | 69352859712417ok | 32666s | patyczak
2 | AMD 48core | threadMemPerft5 10 4 580000000 8 1000000 | 69352859712417ok | 19820s | AXm77
2 | AMD 48core | threadMemPerft6 10 4 580000000 8 1000000 | 69352859712417ok | 18154s | AXm77
2 | AMD 48core | threadMemPerft5 10 8 580000000 8 1000000 | 69352859712417ok | 10352s | AXm77
2 | AMD 48core | threadMemPerft6 10 8 580000000 8 1000000 | 69352859712417ok | 9095s | AXm77
2 | AMD 48core | threadMemPerft5 10 16 580000000 8 1000000 | 69352859712417ok | 5362s | AXm77
2 | AMD 48core | hreadMemPerft6 10 16 580000000 8 1000000 | 69352859712417ok | 4593s | AXm77
2 | AMD 48core | threadMemPerft5 10 24 580000000 8 1000000 | 69352859712417ok | 3709s | AXm77
2 | AMD 48core | threadMemPerft6 10 24 580000000 8 1000000 | 69352859712417ok | 3080s | AXm77
2 | AMD 48core | threadMemPerft6 10 48 580000000 1 10000000| 69352859712417ok | 2921s | AXm77
2 | AMD 48core | threadMemPerft5 10 32 580000000 8 1000000 | 69352859712417ok | 2883s | AXm77
2 | AMD 48core | threadMemPerft6 10 32 580000000 8 1000000 | 69352859712417ok | 2383s | AXm77
2 | AMD 48core | threadMemPerft5 10 52 580000000 8 1000000 | 69352859712417ok | 2074s | AXm77
2 | AMD 48core | threadMemPerft6 10 48 580000000 3 10000000| 69352859712417ok | 1669s | AXm77
2 | AMD 48core | threadMemPerft5 10 48 580000000 8 1000000 | 69352859712417ok | 2065s | AXm77
2 | AMD 48core | threadMemPerft6 10 52 580000000 8 1000000 | 69352859712417ok | 1658s | AXm77
2 | AMD 48core | threadMemPerft6 10 48 580000000 8 1000000 | 69352859712417ok | 1642s | AXm77
2 | AMD 48core | threadMemPerft6 10 48 580000000 4 10000000| 69352859712417ok | 1641s | AXm77
2 | AMD 48core | threadMemPerft6 10 48 580000000 5 1000000 | 69352859712417ok | 1617s | AXm77
2 | AMD 48core | threadMemPerft6 10 48 580000000 5 10000000| 69352859712417ok | 1613s | AXm77
------------------------------------------------------------------------------------------------------------------
[1] - z tej wersji prawdopodobnie zapomniałem usunąć asercje i spowolniły program.
[2] - dwa rdzenie komputera były obciążone
jeszcze powiedz, co ci teraz ewentualnie potestować :)
Właśnie o tym mówiłem. Najprostrze rozwiązania są najlepsze ;D , a nie kombinować jak koń pod górę z dzieleniem zadań na duże ilości wątków. Jak widać z wyników ten Opteron na jednym wątku przeliczy na głębokość 10 w około 20 godzin. To jest bardzo dobry czas na uzyskanie 1 rozwiązania, które ładnie można odesłać na serwer. Wtedy serwer projektu uzupełnia sobie bazę danych i zapodaje nowe zadania. Jeśli ktoś będzie chciał i będzie miał tyle rdzeni to może i 48 takich zadań na raz liczyć. Na razie chyba nie wiesz jaka jest rzeczywista róznica między rozwiązaniem wielowątkowym, a uruchomieniem wielu procesó 1 wątkowych...
tylko ze jak 20 godzin WU to koniecznie checkpointy...
threadMemPerft6 10 48 580000000 1 10000000 - nodes:69352859712417 time:2921
Jak widać hprobe=1 prawie podwoił czas liczenia :(
Spróbuję 3 i 4.
Cytat: Rysiu w 31 Maj 2013, 13:08
Panowie nie chcę nikogo trochę hamować ale niestety większości ze spraw o których tutaj jest pisane odnośnie obliczeń rozproszonych nie ma najmniejszych szans realizacji.
Prawdopodobnie niezbyt jasno się wyraziłem, raczej chcę zrobić prostą rzecz, co najwyżej dobrze stuningowaną, bo
przyspieszenie obliczeń jest bardzo ważne.
Cytat: Rysiu w 31 Maj 2013, 13:08
Droga od postawienia serwera BOINC do czegoś takiego o czym piszecie jest bardzo długa i zawiła.
Mogę się mylić, ale przypuszczam że to jest kwestia dobrego kursu i potem małego treningu w celu
nabrania wprawy. Na razie moim problemem jest brak jasnych i zrozumiałych tutoriali. Coś czytam,
jakoś rozumiem, próbuję, nie działa, nie wiem dlaczego nie działa, potem dumam tydzień aż
się zniechęcam. Wszystko zależy jakie gotowce udostępnia BOINC przez swoje API. Jeśli te
gotowce są przyzwoite, to po dobrym kursie przerobię sprawnie każdą aplikację liczącą na
serwer boinc.
Cytat: Rysiu w 31 Maj 2013, 13:08
Jak czytałem mówimy tutaj o serwerze master, który dosyła dane do klientów i o jakimś skalowaniu wątków, wewnętrznych benchmarkach oraz aplikacjach działających na różnej ilości wątków. Niestety 99% z tego trzeba wsadzić do kosza. Nawet najlepsze projekty różnie działają, a różnica między pierwszym projektem, który sobie na szybkiego odpalimy a czołówką najlepszych jest gigantyczna.
Mnie się akurat to wydaje łatwe, pracochłonne, ale łatwe.
Cytat: Rysiu w 31 Maj 2013, 13:08
Do czegoś takiego najprawdopodobniej łatwiej byłoby napisać własny soft w postaci klienta i serwera i udostępnić liczącym. Wtedy mamy całkowitą dowolność i pisząc całość od zera w technologii, którą znamy możemy coś takiego zrobić.
To powinno być łatwiejsze w boinc, bo daje gotowe API. Problem właśnie w tym, że trzeba się nauczyć i konfiguracji i API.
Cytat: Rysiu w 31 Maj 2013, 13:08
Tak napisać, że serwer ma robić X, a klient to będzie sobie pobierać Y i skalować odpowiednio tylko wątki to prosto. Problem jednak zamknie się na tym, że podczas konfiguracji wyskoczy jeden błąd i będzie kaplica. Alarmuję więc - nie twórzmy wielkich teorii o tym jak ma działać serwer BOINC, a dostosujmy się do tego jak jest on skonstruowany.
Można dać zupełnie osobną aplikację gdzieś na stronie www. Aplikacja uruchomi się, przetestuje dany komputer i wyświetli
użytkownikowi jakie parametry należy wpisać w konfiguracji. Nie wydaje się to zbytnio trudne.
Cytat: Rysiu w 31 Maj 2013, 13:08
Koncepcja podstawowej aplikacji BOINC jest szalenie prosta.
1. Serwer tworzy zadanie
2. Klient pobiera aplikację liczącą i zadanie
3. Klient wykonuje obliczenia sekwencyjnie na jednym wątku i zapisuje wyniki do pliku
4. Klient odsyła dane (także plik wyniku) do serwera
5. Serwer analizuje nadesłane dane
Schemat wydaje się prosty. Tak myślę sobie... mogę przygotować zestaw plików-zadań.
Serwer będzie musiał rozdać klientom te pliki-zadania. Klient do każdego pliku-zadania da
plik-odpowiedź. To jest proste, bo serwer nawet nie musiałby robić żadnej analizy. Tylko
pod pliki-zadania i zbierze pliki-odpowiedzi. Wyniki potem można przeanalizować w
aplikacji poza serwerem. Gdzie będą błędy, tam się wrzuci taski ponownie do weryfikacji.
Ale... gdzie miejsce na użytkowników? Gdzie hasła i autoryzacja? Gdzie statystyki użytkowników?
Czyżby to BOINC dawał sam bez żadnych konfiguracji?
Cytat: Rysiu w 31 Maj 2013, 13:08
Nie ma tutaj miejsca na jakąkolwiek komunikację w środku wykonywania zadania. Jedyna znacząca komunikacja to pobieranie zadania i odsyłanie wyników.
Rozumiem. Czyli bardziej zaawansowana komunikacja musiałaby się odbywać przez
podanie specyficznego zadania, np. zadanie zrób benchmark, albo zadanie: ustaw parametry.
Cytat: Rysiu w 31 Maj 2013, 13:08
Zadania także nie mogą być liczone w dziesiątkach czy też setkach na jednym kliencie w jakimś
krótkim odcinku czasowym. Żaden serwer BOINC tego nie obsłuży. Każde zadanie powinno wykonywać
się przynajmniej godzinę.
Tutaj optymalny czas będzie zależał od tego jak zoptymalizuję aplikację. Teraz optymalny task
trwałby na przeciętnym kompie jakieś 30-60tys sekund. Po optymalizacji może trwać 3-6tys
sekund. Jeśli optymalny task będzie zbyt długi albo krótki, to podamy taski nieoptymalne.
Wydłuży to cały proces liczenia, ale nie ma innego wyjścia.
Cytat: Rysiu w 31 Maj 2013, 13:08
Znak zapytania bym postawił przy samych aplikacjach wielowątkowych, pomimo, że takie BOINC wspiera.
To już jest wykonane, a jeśli BOINC to wspiera, to tylko podepniemy. Domyślnie aplikacja wystartuje
w jednym wątku, a jak użytkownik zechce liczyć na kilku wątkach, to sobie zwiększy.
Cytat: Rysiu w 31 Maj 2013, 13:08
Przepraszam za takie oblanie zimną wodą ale niestety tak to wygląda. Oczywiście można zrobić wszystko - pytanie tylko czy ktoś zdoła obejść wszystkie problemy. Wydaje mi się, że nie jest to tego kalibru problem aby pisać pod niego na nowo pół środowiska serwera BOINC.
Nie oblałeś mnie zimną wodą, jestem świadomy tego że pojawią się problemy. Czy warto? Uczymy się, a prosty projekt
może jest lepszy do nauki niż skomplikowany. Jeśli dzięki temu nauczę się stawiać takie aplikacje, to potem będę mógł
Wam coś zrobić i nie tylko. Jestem pewny że warto, natomiast nie wiem czy przebrnę przez te wszystkie materiały które
są dla mnie jak na razie strasznie zawiłe i niejasne.
Pozdrawiam i dzięki Rysiu za wszelkie wyjaśnienia :)
Cytat: sknd w 31 Maj 2013, 17:31
jeszcze powiedz, co ci teraz ewentualnie potestować :)
Nie ma nowej wersji wartej przetestowania. W starej wersji warto poszukać dobrych
wartości dwóch ostatnich parametrów, czym właśnie zajmuje się AXm77. Na jutro
przygotuję nową wersję, a jeśli będzie tego warta, to porównamy z poprzednią.
Pozdrawiam i dzięki.
Cytat: Dario666 w 31 Maj 2013, 17:33
Właśnie o tym mówiłem. Najprostrze rozwiązania są najlepsze ;D , a nie kombinować jak koń pod górę z dzieleniem zadań na duże ilości wątków. Jak widać z wyników ten Opteron na jednym wątku przeliczy na głębokość 10 w około 20 godzin. To jest bardzo dobry czas na uzyskanie 1 rozwiązania,
Myślałem że dobry czas to 1 godzina.
Cytat: Dario666 w 31 Maj 2013, 17:33
które ładnie można odesłać na serwer. Wtedy serwer projektu uzupełnia sobie bazę danych i zapodaje nowe zadania. Jeśli ktoś będzie chciał i będzie miał tyle rdzeni to może i 48 takich zadań na raz liczyć. Na razie chyba nie wiesz jaka jest rzeczywista róznica między rozwiązaniem wielowątkowym, a uruchomieniem wielu procesó 1 wątkowych...
Wiem że 20 aplikacji jednowątkowych policzy to samo zadanie znacznie wolniej niż 1 aplikacja 20 wątkowa. A jeśli te 20 aplikacji
jedno wątkowych uruchomi się na raz, to policzą to samo zadanie koszmarnie wolniej. Natomiast masz rację że nie wiem co
znaczy "znacznie" i "koszmarnie" :) Znacznie może oznaczać 1.5-3.0 raza, koszmarnie być może 5-30 razy.
Ale spokojnie, jak już pisałem, ta sama aplikacja może z powodzeniem działać jako jednowątkowa, podaje się tylko parametr i działa.
Pozdrawiam
P.S.
Panowie, to jest specyficzna aplikacja. To nie jest tak, że jak aplikacja weźmie sobie 1 zadanie, to policzy je 10 razy
szybciej niż 10 zadań. Ta aplikacja skaluje się w specyficzny i trudny do oszacowania sposób. Ale myślę że nie będzie z
tym żadnego problemu. Do pliku tekstowego wsadzi się 5-20 zadań i użytkownik nawet się nie dowie, że jedno zadanie
to kilka zadań.
Nie ma dziś czego testować, więc zróbmy eksperyment. Eksperyment w przybliżeniu pokaże
czy się opłaca pakować do paczki 20 zadań. Poniższy skrypt najpierw liczy 20 razy niezależnie
na głębokość 9 ruchów. Potem liczy raz na głębokość 10 ruchów - to na razie jedyny sposób
na zasymulowanie pliku tekstowego z 20ma zadaniami. Można wpisać inne wartości parametrów,
np depth=8 przyspieszy eksperyment.
#!/bin/sh
#threadMemPerft6 depth max_thread hsize hprobe forget
depth=9
max_thread=4
hsize=10000000
hprobe=8
forget=1000000
bench1=`date +"+%s"`
echo "start" > out.txt
(
echo "setBoard rnbqkbnr/pppppppp/8/8/8/7N/PPPPPPPP/RNBQKB1R b qkQK -; repeat: 1"
echo "threadMemPerft6 $depth $max_thread $hsize $hprobe $forget"
echo "setBoard rnbqkbnr/pppppppp/8/8/8/5N2/PPPPPPPP/RNBQKB1R b qkQK -; repeat: 1"
echo "threadMemPerft6 $depth $max_thread $hsize $hprobe $forget"
echo "setBoard rnbqkbnr/pppppppp/8/8/8/2N5/PPPPPPPP/R1BQKBNR b qkQK -; repeat: 1"
echo "threadMemPerft6 $depth $max_thread $hsize $hprobe $forget"
echo "setBoard rnbqkbnr/pppppppp/8/8/8/N7/PPPPPPPP/R1BQKBNR b qkQK -; repeat: 1"
echo "threadMemPerft6 $depth $max_thread $hsize $hprobe $forget"
echo "setBoard rnbqkbnr/pppppppp/8/8/7P/8/PPPPPPP1/RNBQKBNR b qkQK -; repeat: 1"
echo "threadMemPerft6 $depth $max_thread $hsize $hprobe $forget"
echo "setBoard rnbqkbnr/pppppppp/8/8/8/7P/PPPPPPP1/RNBQKBNR b qkQK -; repeat: 1"
echo "threadMemPerft6 $depth $max_thread $hsize $hprobe $forget"
echo "setBoard rnbqkbnr/pppppppp/8/8/6P1/8/PPPPPP1P/RNBQKBNR b qkQK -; repeat: 1"
echo "threadMemPerft6 $depth $max_thread $hsize $hprobe $forget"
echo "setBoard rnbqkbnr/pppppppp/8/8/8/6P1/PPPPPP1P/RNBQKBNR b qkQK -; repeat: 1"
echo "threadMemPerft6 $depth $max_thread $hsize $hprobe $forget"
echo "setBoard rnbqkbnr/pppppppp/8/8/5P2/8/PPPPP1PP/RNBQKBNR b qkQK -; repeat: 1"
echo "threadMemPerft6 $depth $max_thread $hsize $hprobe $forget"
echo "setBoard rnbqkbnr/pppppppp/8/8/8/5P2/PPPPP1PP/RNBQKBNR b qkQK -; repeat: 1"
echo "threadMemPerft6 $depth $max_thread $hsize $hprobe $forget"
echo "setBoard rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b qkQK -; repeat: 1"
echo "threadMemPerft6 $depth $max_thread $hsize $hprobe $forget"
echo "setBoard rnbqkbnr/pppppppp/8/8/8/4P3/PPPP1PPP/RNBQKBNR b qkQK -; repeat: 1"
echo "threadMemPerft6 $depth $max_thread $hsize $hprobe $forget"
echo "setBoard rnbqkbnr/pppppppp/8/8/3P4/8/PPP1PPPP/RNBQKBNR b qkQK -; repeat: 1"
echo "threadMemPerft6 $depth $max_thread $hsize $hprobe $forget"
echo "setBoard rnbqkbnr/pppppppp/8/8/8/3P4/PPP1PPPP/RNBQKBNR b qkQK -; repeat: 1"
echo "threadMemPerft6 $depth $max_thread $hsize $hprobe $forget"
echo "setBoard rnbqkbnr/pppppppp/8/8/2P5/8/PP1PPPPP/RNBQKBNR b qkQK -; repeat: 1"
echo "threadMemPerft6 $depth $max_thread $hsize $hprobe $forget"
echo "setBoard rnbqkbnr/pppppppp/8/8/8/2P5/PP1PPPPP/RNBQKBNR b qkQK -; repeat: 1"
echo "threadMemPerft6 $depth $max_thread $hsize $hprobe $forget"
echo "setBoard rnbqkbnr/pppppppp/8/8/1P6/8/P1PPPPPP/RNBQKBNR b qkQK -; repeat: 1"
echo "threadMemPerft6 $depth $max_thread $hsize $hprobe $forget"
echo "setBoard rnbqkbnr/pppppppp/8/8/8/1P6/P1PPPPPP/RNBQKBNR b qkQK -; repeat: 1"
echo "threadMemPerft6 $depth $max_thread $hsize $hprobe $forget"
echo "setBoard rnbqkbnr/pppppppp/8/8/P7/8/1PPPPPPP/RNBQKBNR b qkQK -; repeat: 1"
echo "threadMemPerft6 $depth $max_thread $hsize $hprobe $forget"
echo "setBoard rnbqkbnr/pppppppp/8/8/8/P7/1PPPPPPP/RNBQKBNR b qkQK -; repeat: 1"
echo "threadMemPerft6 $depth $max_thread $hsize $hprobe $forget"
echo "quit"
) | ./perft3 >> out.txt
bench2=`date +"+%s"`
echo "bench=$((bench2-bench1))" >> out.txt
bench1=`date +"+%s"`
echo start >> out.txt
depth=$((depth+1))
(
echo "setBoard rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
echo "threadMemPerft6 $depth $max_thread $hsize $hprobe $forget"
echo "quit"
) | ./perft3 >> out.txt
bench2=`date +"+%s"`
echo "bench=$((bench2-bench1))" >> out.txt
threadMemPerft6 10 48 580000000 4 10000000 - nodes:69352859712417 time:1641
threadMemPerft6 10 48 580000000 3 10000000 - nodes:69352859712417 time:1669
4 "wygląda" podobnie do 8, a 3=4 - pomyłka
Jeszcze jedno pytanie: czy hprobe jest zależny od forget i odwrotnie?
Cytat: AXm77 w 31 Maj 2013, 18:49
threadMemPerft6 10 48 580000000 4 10000000 - nodes:69352859712417 time:1641
threadMemPerft6 10 48 580000000 3 10000000 - nodes:69352859712417 time:1669
4 "wygląda" podobnie do 8, a 3=4 - pomyłka
Jeszcze jedno pytanie: czy hprobe jest zależny od forget i odwrotnie?
Niestety hprobe i forget są zależne, a właściwie to wszystkie parametry są od
siebie zależne. Można poszukać najlepszej wartości hprobe dla forget równego
np. 0, 1000, 100000, 1000000, 5000000, 10000000 i 100000000. Parametry
te nie dają dużego przyspieszenia, więc bardziej szczegółowo nie trzeba
sprawdzać - a przynajmniej tak mi się wydaje.
Dzięki za testy i pozdrawiam :)
Cytat: Dario666 w 31 Maj 2013, 17:33
Jeśli ktoś będzie chciał i będzie miał tyle rdzeni to może i 48 takich zadań na raz liczyć. Na razie chyba nie wiesz
jaka jest rzeczywista róznica między rozwiązaniem wielowątkowym, a uruchomieniem wielu procesó 1 wątkowych...
Chyba moje przypuszczenia się potwierdzają. Odpaliłem tamten skrypt z kilku
postów wyżej dla depth=7 ( czyli 8 ) wyżej i są takie wyniki:
start
nodes:3221278282 time:9
nodes:3937354096 time:11
nodes:3926684340 time:12
nodes:3193522577 time:12
nodes:3711123115 time:11
nodes:2860408680 time:11
nodes:3466204702 time:9
nodes:3641432923 time:11
nodes:3199039406 time:10
nodes:2728615868 time:8
nodes:8102108221 time:20
nodes:8039390919 time:19
nodes:7184581950 time:18
nodes:6093248619 time:12
nodes:4199667616 time:12
nodes:3806229124 time:12
nodes:3569067629 time:11
nodes:3579299617 time:11
nodes:3676309619 time:11
nodes:2863411653 time:10
bench=240
start
nodes:84998978956 time:61
bench=61
Czyli 20 zadań na raz liczy 61 sekund, a osobno 240 - cztery razy wolniej. Zobaczymy
jak będzie dla większych głębokości - może dla małych głębokości taka różnica wynika z
dużego narzutu na rozruch.
-----------------------------------------------------------------------------------------------
Na głębokości 8 ( czyli 9 ) przyspieszenie jest
3 krotne dzięki technice pakowania wielu
zadań do jednego pliku:
start
nodes:86659653631 time:63
nodes:108393009416 time:106
nodes:109418317145 time:101
nodes:85849641909 time:84
nodes:102853440161 time:90
nodes:74778417365 time:70
nodes:92281289941 time:82
nodes:99646370024 time:99
nodes:84792070664 time:75
nodes:68094899093 time:62
nodes:263561543780 time:190
nodes:259522947791 time:149
nodes:227220482342 time:176
nodes:176976245463 time:150
nodes:120549219832 time:93
nodes:108697368719 time:92
nodes:97442160946 time:82
nodes:96577095997 time:88
nodes:101265301849 time:72
nodes:74950758099 time:76
bench=2000
start
nodes:2439530234167 time:658
bench=658
-------------------------------------------------------------------------------
Dla głębokości 9/10 wyszło ponad dwa razy szybciej
start
nodes:2470483499345 time:695
nodes:3090773583680 time:937
nodes:3096505857746 time:1135
nodes:2440848135252 time:893
nodes:2948003834105 time:924
nodes:2142832044687 time:857
nodes:2624128147144 time:985
nodes:2853630724145 time:1019
nodes:2418056589775 time:801
nodes:1945020011164 time:684
nodes:7380003266234 time:2464
nodes:7299373354878 time:2435
nodes:6459463242656 time:2274
nodes:5071006040569 time:1399
nodes:3437747391692 time:1072
nodes:3072577495123 time:1012
nodes:2772533545113 time:866
nodes:2774842822463 time:939
nodes:2905552970419 time:1015
nodes:2149477156227 time:780
bench=23186
start
nodes:69352859712417 time:10293
bench=10293
Nie jest to reprezentatywny eksperyment, ale na pewno serię zadań (w tym problemie) można policzyć
szybciej niż pojedynczo. Nawet jak przyspieszenie w ostatecznej wersji będzie tylko 10% to i tak warto.
Pozdrawiam
Kolejny wynik:
threadMemPerft6 10 48 580000000 5 1 - nodes:69352859712417 time:2854
Tak dla porównania:
threadMemPerft6 10 48 580000000 5 1 - nodes:69352859712417 time:2854
threadMemPerft6 10 48 580000000 5 1000 - nodes:69352859712417 time:1631
threadMemPerft6 10 48 580000000 5 1000000 - nodes:69352859712417 time:1617
threadMemPerft6 10 48 580000000 5 10000000 - nodes:69352859712417 time:1613
threadMemPerft6 10 48 580000000 5 1000000000 - nodes:69352859712417 time:1615
Także oprócz 1 to nie ma drastycznych różnic (0 nie chciało odpalić |-?)
Cytat: mariotti w 31 Maj 2013, 18:20
Eksperyment w przybliżeniu pokaże
czy się opłaca pakować do paczki 20 zadań. Poniższy skrypt najpierw liczy 20 razy niezależnie
na głębokość 9 ruchów. Potem liczy raz na głębokość 10 ruchów - to na razie jedyny sposób
na zasymulowanie pliku tekstowego z 20ma zadaniami. Można wpisać inne wartości parametrów,
np depth=8 przyspieszy eksperyment.
Wydaje mi się, że ta metoda nie jest zbyt reprezentacyjna. Wg mnie powinno się uruchomić na raz np. 20 procesów na głębokość X, i porównać to z czasem działania 1 procesu 20 wątkowego. Ważne jest, by procesy 1-wątkowe pracowały jednocześnie, bo wtedy muszą podzielić się ilością RAMu itp.
depth=8, procek e3-1230v2 w pelni obciążony boincem ;)
start
nodes:86659653631 time:117
nodes:108393009416 time:159
nodes:109418317145 time:163
nodes:85849641909 time:131
nodes:102853440161 time:137
nodes:74778417365 time:116
nodes:92281289941 time:138
nodes:99646370024 time:147
nodes:84792070664 time:124
nodes:68094899093 time:88
nodes:263561543780 time:395
nodes:259522947791 time:375
nodes:227220482342 time:304
nodes:176976245463 time:255
nodes:120549219832 time:148
nodes:108697368719 time:156
nodes:97442160946 time:126
nodes:96577095997 time:142
nodes:101265301849 time:132
nodes:74950758099 time:115
bench=3468
start
nodes:2439530234167 time:2378
bench=2378
Wyniki dla:
#!/bin/sh
(
echo threadMemPerft5 10 4 50000000 8 10000000
echo quit
) | ./perft2 >> out.txt
(
echo threadMemPerft2 10 4 6250000 8 6
echo quit
) | ./perft2 >> out.txt
echo done
nodes:69352859712417 time:37182
nodes:69352859712417 time:40806
chyba się pogubiłem... Gdzie jest plik perft3?
Cytat: Dario666 w 31 Maj 2013, 22:24
Wydaje mi się, że ta metoda nie jest zbyt reprezentacyjna. Wg mnie powinno się uruchomić na raz np. 20 procesów na głębokość X, i porównać to z czasem działania 1 procesu 20 wątkowego. Ważne jest, by procesy 1-wątkowe pracowały jednocześnie, bo wtedy muszą podzielić się ilością RAMu itp.
Nie jest reprezentatywna, ale z innych powodów. Tak przeprowadzony eksperyment jak proponujesz,
jeszcze dobitniej wykaże, że opłaca się pakować wiele zadań do jednego pliku.
Pozdrawiam
Cytat: krzyszp w 31 Maj 2013, 22:34
chyba się pogubiłem... Gdzie jest plik perft3?
Post #140
Materiały o stawianiu serwera są dość dobre, po angielsku - trzeba przekopywać BOINCową wikipedię. Niestety z doświadczenia wiem, że dla kogoś kto nie ma jeszcze wiedzy na temat działania serwera, to ciężki temat.
Taki telegraficzny skrót, co potrzeba na start:
Pierwsza rzecz której potrzebujesz, to działająca aplikacja. Albo z wbudowanym BOINC API, albo z użyciem wrappera (każde rozwiązanie ma zady i walety, ale czasami wrapper jest nawet leszy).
Aplikacja może mieć pliki wejściowe stałe i zmienne. Te stałe można wysyłać razem z aplikacją (ich ewentualny upgrade wykonuje się wtedy zmieniając wersję aplikacji i dorzucając nowe pliki). Pliki wejściowe zmienne mogą być przypisane do konkretnego zadania lub grupy zadań.
Aplikacja składająca się z wielu aplikacji odpalanych jedna po drugiej o wiele łatwiejsza jest do odpalenia z wrapperem, ale nie liczyłbym tu na żadne zaawansowane opcje oskryptowania, bo może się nie udać. Jest możliwość np. uruchomienia 10 razy pod rząd tego samego z różnymi plikami, albo kolejny przebieg z plikami wejściowymi z poprzedniego przebiegu [o ile ich nazwy są z góry ustalone].
Aplikacja do działania po stronie klienta potrzebuje templatek. Są dwie, wejściowa i wyjściowa. Pierwsza opisuje stan przed uruchomieniem aplikacji, pozwala na takie bajery, jak przypisanie plikom wirtualnych nazw [bardzo przydatne], określa które pliki są stałe, a które przyjdą z zadaniem oraz określa trochę parametrów dla zadania.
Druga działa odwrotnie - służy do zebrania plików wyjściowych, określa które zostaną odesłane do serwera i pod jakimi nazwami. Słowa kluczowe do znalezienia info o tym na wiki BOINCa to input / output templates.
Do dodawania wpisów aplikacji na serwerze służą narzędzia update_versions i xadd, warto rzucić okiem na ich opis na wiki dla samego zrozumienia, jak zbudowane są katalogi aplikacji na serwerze.
Kolejna rzecz potrzebna do działania, to jakiś skrypt do generowania zadań. Zapomnij o tym, że dasz radę robić je ręcznie, może pierwsze kilkanaście ale potem idzie osiwieć.
Są dwie opcje - albo wykorzystuje się create_work i jego parametry linii poleceń (sam korzystam, łatwo go oskryptować, rad@h ma autopilota z wykorzystaniem create_work), albo opcja trudniejsza - napisanie własnego generatora na podstawie przykładu.
Pierwsza, łatwiejsza wersja sprowadza się do napisania skryptu basha który przekaże do create_work odpowiednie parametry (głównie chodzi np. o plik wejściowy, jeśli się zmienia [lub opcja jeszcze trudniejsza - jeśli dla każdego WU jest inny]). Dużo można wywnioskować z wiki czytając opis create_work lub wręcz help jego linii poleceń.
Na takim etapie teoretycznie projekt jest gotowy do wysłania zadań do klientów.
Niestety zadania wrócą i nie będzie z nich jako takiego pożytku, ponieważ potrzebny jest jeszcze validator.
Jeśli zadanie da się zweryfikować z grubsza analizując wynik, polecam przerobienie sample_trivial_validator - jest to pusta templatka z funkcjami które należy uzupełnić.
Jeśli weryfikacja jest bardziej złożona lub np. na podstawie jednego wyniku (z jednego zadania) nie można wyciągnąć bezpośredniego wniosku o poprawności (bo np. potrzeba skończyć cały batch czy coś), najlepiej - zwłaszcza na początku - użyć sample_bitwise_validatora i ustawić quorum na 2 - wtedy validator z automatu porówna dwa wyniki z różnych hostów i to zadecyduje czy zadania zostaną zaliczone jako poprawne. Tutaj czai się pułapka, ponieważ domyślnie oba pliki (z obu hostów) muszą być po prostu identyczne co do bajta.
Zadania z błędami będą wysyłane jeszcze raz, do innych hostów, odbywa się to automatycznie.
Następna rzecz konieczna do zadziałania to assimilator - należy ciutkę go poprawić - praktycznie wystarczy wyedytować w przykładowym ze 2 linijki - żeby 'wyciągał' potrzebne pliki z katalogów tymczasowych i kopiował je do jakiegoś innego katalogu (czy rozkładał po katalogach, wedle uznania administratora).
Mając tyle, można (o ile o czymś nie zapomniałem) uruchomić projekt. Dużo rzeczy na początek może działać z domyślnymi ustawieniami i będzie ok, po prostu konieczności zmian wyjdą w praniu.
P.S. Jeśli chciałbyś pogadać o jakichś szczegółach, zapraszam wieczorami na IRC.
Cytat: AXm77 w 31 Maj 2013, 22:59
Cytat: krzyszp w 31 Maj 2013, 22:34
chyba się pogubiłem... Gdzie jest plik perft3?
Post #140
Dzięki, obliczenia już idą :)
Cytat: TJM w 31 Maj 2013, 23:08
Materiały o stawianiu serwera są dość dobre, po angielsku - trzeba przekopywać BOINCową wikipedię. Niestety z doświadczenia wiem, że dla kogoś kto nie ma jeszcze wiedzy na temat działania serwera, to ciężki temat.
Już raz się przekonałem że ciężki, teraz drugie podejście.
Cytat: TJM w 31 Maj 2013, 23:08
Taki telegraficzny skrót, co potrzeba na start:
Pierwsza rzecz której potrzebujesz, to działająca aplikacja.
Aplikacja niby już jest, trzeba ją jeszcze "tylko" zoptymalizować i dokładniej przetestować.
Cytat: TJM w 31 Maj 2013, 23:08
Albo z wbudowanym BOINC API, albo z użyciem wrappera (każde rozwiązanie ma zady i walety, ale czasami wrapper jest nawet leszy).
Więc jest goły BOINC i jakiś/jakieś wrapper - dobrze wiedzieć na początek.
Cytat: TJM w 31 Maj 2013, 23:08
Aplikacja może mieć pliki wejściowe stałe i zmienne. Te stałe można wysyłać razem z aplikacją (ich ewentualny upgrade wykonuje się wtedy zmieniając wersję aplikacji i dorzucając nowe pliki). Pliki wejściowe zmienne mogą być przypisane do konkretnego zadania lub grupy zadań.
Brzmi zrozumiale, a w przypadku tego projektu zadania zdefiniowane w plikach będą wygodnym rozwiązaniem. Serwer
nie będzie musiał analizować poprzednich wyników, aby przygotować następne. Całą pulę zadań można przygotować raz odgórnie,
za wyjątkiem sprzecznych wyników. Tam gdzie wynik będą sprzeczne, zadania będzie trzeba zwielokrotnić i dodać je ponownie.
Pliki zajmą dużo miejsca, ale chyba zmieszczą się na jednym dysku.
Cytat: TJM w 31 Maj 2013, 23:08
Aplikacja składająca się z wielu aplikacji odpalanych jedna po drugiej o wiele łatwiejsza jest do odpalenia z wrapperem,
W tym projekcie jedna aplikacja powinna załatwić całą sprawę. A na przyszłość: czy można odpalić jeden
plik shell/cmd, a on odpali po kolei wszystko co trzeba?
Cytat: TJM w 31 Maj 2013, 23:08
ale nie liczyłbym tu na żadne zaawansowane opcje oskryptowania, bo może się nie udać. Jest możliwość np. uruchomienia 10 razy pod rząd tego samego z różnymi plikami, albo kolejny przebieg z plikami wejściowymi z poprzedniego przebiegu [o ile ich nazwy są z góry ustalone].
10 razy pod rząd to też dobre i wygodne rozwiązanie, może brzmi sarkastycznie, ale piszę serio.
Cytat: TJM w 31 Maj 2013, 23:08
Aplikacja do działania po stronie klienta potrzebuje templatek. Są dwie, wejściowa i wyjściowa. Pierwsza opisuje stan przed uruchomieniem aplikacji, pozwala na takie bajery, jak przypisanie plikom wirtualnych nazw [bardzo przydatne], określa które pliki są stałe, a które przyjdą z zadaniem oraz określa trochę parametrów dla zadania.
Druga działa odwrotnie - służy do zebrania plików wyjściowych, określa które zostaną odesłane do serwera i pod jakimi nazwami. Słowa kluczowe do znalezienia info o tym na wiki BOINCa to input / output templates.
Plik wejściowy będzie jeden. Wyjściowy też jeden. Aplikacja... nie wiem jaka będzie, mogę ją dostosować
na wiele różnych sposobów. Największa wygoda to plik shell lub cmd który uruchomi to co jest potrzebne.
Idealnie jakby plik shell dostał jako parametr nazwę pliku wejściowego i uruchomił to co trzeba.
Cytat: TJM w 31 Maj 2013, 23:08
Do dodawania wpisów aplikacji na serwerze służą narzędzia update_versions i xadd, warto rzucić okiem na ich opis na wiki dla samego zrozumienia, jak zbudowane są katalogi aplikacji na serwerze.
Ok, rzucę okiem.
Cytat: TJM w 31 Maj 2013, 23:08
Kolejna rzecz potrzebna do działania, to jakiś skrypt do generowania zadań. Zapomnij o tym, że dasz radę robić je ręcznie, może pierwsze kilkanaście ale potem idzie osiwieć.
Są dwie opcje - albo wykorzystuje się create_work i jego parametry linii poleceń (sam korzystam, łatwo go oskryptować, rad@h ma autopilota z wykorzystaniem create_work), albo opcja trudniejsza - napisanie własnego generatora na podstawie przykładu.
Aplikacja ma już w sobie gotowy taki generator zadań. Trzeba go tylko przekonwertować do
jakiegoś docelowego formatu.
Cytat: TJM w 31 Maj 2013, 23:08
Pierwsza, łatwiejsza wersja sprowadza się do napisania skryptu basha który przekaże do create_work odpowiednie parametry (głównie chodzi np. o plik wejściowy, jeśli się zmienia [lub opcja jeszcze trudniejsza - jeśli dla każdego WU jest inny]). Dużo można wywnioskować z wiki czytając opis create_work lub wręcz help jego linii poleceń.
Z tego na razie nie rozumiem za dużo, poczytam na wiki. Czy create_work to program po
stronie klienta?
Cytat: TJM w 31 Maj 2013, 23:08
Na takim etapie teoretycznie projekt jest gotowy do wysłania zadań do klientów.
Niestety zadania wrócą i nie będzie z nich jako takiego pożytku, ponieważ potrzebny jest jeszcze validator.
Jeśli zadanie da się zweryfikować z grubsza analizując wynik, polecam przerobienie sample_trivial_validator - jest to pusta templatka z funkcjami które należy uzupełnić.
Brzmi ciekawie i nie wydaje się zbytnio trudne.
Cytat: TJM w 31 Maj 2013, 23:08
Jeśli weryfikacja jest bardziej złożona lub np. na podstawie jednego wyniku (z jednego zadania) nie można wyciągnąć bezpośredniego wniosku o poprawności (bo np. potrzeba skończyć cały batch czy coś), najlepiej - zwłaszcza na początku - użyć sample_bitwise_validatora i ustawić quorum na 2 - wtedy validator z automatu porówna dwa wyniki z różnych hostów i to zadecyduje czy zadania zostaną zaliczone jako poprawne. Tutaj czai się pułapka, ponieważ domyślnie oba pliki (z obu hostów) muszą być po prostu identyczne co do bajta.
Zadania z błędami będą wysyłane jeszcze raz, do innych hostów, odbywa się to automatycznie.
Może uda się tak ustawić, żeby porównał tylko pierwsze 100 bajtów w plikach?
Alby żeby porównał tylko N pierwszych wierszy w pliku tekstowym?
Cytat: TJM w 31 Maj 2013, 23:08
Następna rzecz konieczna do zadziałania to assimilator - należy ciutkę go poprawić - praktycznie wystarczy wyedytować w przykładowym ze 2 linijki - żeby 'wyciągał' potrzebne pliki z katalogów tymczasowych i kopiował je do jakiegoś innego katalogu (czy rozkładał po katalogach, wedle uznania administratora).
Nie rozumiem. Czy chodzi o kopiowanie plików z wynikami? Czy o parowanie input-output?
Cytat: TJM w 31 Maj 2013, 23:08
Mając tyle, można (o ile o czymś nie zapomniałem) uruchomić projekt. Dużo rzeczy na początek może działać z domyślnymi ustawieniami i będzie ok, po prostu konieczności zmian wyjdą w praniu.
W sumie to całkiem podobnie sobie to wszystko wyobrażałem, pozostaje zagadką dla mnie, dlaczego
poprzednio sobie nie poradziłem - może nie mam smykałki do konfiguracji i administracji :)
Cytat: TJM w 31 Maj 2013, 23:08
P.S. Jeśli chciałbyś pogadać o jakichś szczegółach, zapraszam wieczorami na IRC.
Przyjrzę się wszystkiemu z bliska, spróbuję zrobić, a jak nie będzie szło, to
poproszę Cię o dalszą pomoc.
Cytat: krzyszp
nodes:69352859712417 time:37182
nodes:69352859712417 time:40806
Czyli
dwójka została z tyłu. Dwójka od piątki różni się drobiazgiem, a prawie godzina
różnicy w czasie wykonania. Piątka od szóstki różni się zasadniczo, ale
2 i
5 są bardzo podobne. Może w
dwójce trudniej jest znaleźć optymalne parametry. Gdy już ruszy aplikacja jako projekt boinc, to zrobimy
lepsze testy. Spróbuję napisać hybrydę z dwójki i szóstki :) Dzięki za testy!
Cytat: AXm77
Tak dla porównania:
threadMemPerft6 10 48 580000000 5 1 - nodes:69352859712417 time:2854
threadMemPerft6 10 48 580000000 5 1000 - nodes:69352859712417 time:1631
threadMemPerft6 10 48 580000000 5 1000000 - nodes:69352859712417 time:1617
threadMemPerft6 10 48 580000000 5 10000000 - nodes:69352859712417 time:1613
threadMemPerft6 10 48 580000000 5 1000000000 - nodes:69352859712417 time:1615
Także oprócz 1 to nie ma drastycznych różnic (0 nie chciało odpalić |-?)
Dzięki za testy, widać wszystko jak na dłoni.
Faktycznie różnice są znikome. Zero nie ma sensu w threadMemPerft
2, w
6 ma
sens, ale z powodu mojego niedopatrzenia pozostała blokada na zero z wersji
2 - przepraszam
za zamieszanie.
Myślę że jak na początkowy etap aplikacja została porządnie przetestowana, a w dodatku
wiemy który algorytm jest najlepszy i wiemy, że sprawdza się on tak samo dobrze na
różnych konfiguracjach sprzętowych. Dziękuję wszystkim za pomoc. Teraz spróbuję
zrobić wersję testową opartą na BOINC, a także przyspieszę program liniowo. Zajmie
mi to trochę czasu, ale nie ma tego złego... przez ten czas może jeszcze wpadnie mi
jakiś pomysł na lepsze wykorzystanie pamięci RAM. O przyspieszeniu liniowym nie ma co
rozmawiać, to po prostu nudna i ciężka robota, tak więc wątek teraz pójdzie w
kierunku konfiguracji serwera BOINC :)
Zamieszczam najnowszą wersję tabelki:
------------------------------------------------------------------------------------------------------------------
Wersja | Procesor | polecenie | wynik | czas | user
------------------------------------------------------------------------------------------------------------------
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 1000000 | 69352859710032! | 63547s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 1 0 | 69352859712417ok | 41515s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 0 | 69352859712417ok | 30042s |
1 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 200 | 69352859712417ok | 25889s |
2[1]| Phenom II 1050T 2.4GHz | threadMemPerft5 10 6 250000000 8 1000000 | 69352859712417ok | 24071s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 12 10000000 | 69352859712417ok | 18111s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 50000000 | 69352859712417ok | 17781s |
0 | Phenom II 1050T 2.4GHz | threadMemPerft 10 8 250000000 8 10000000 | 69352859712417ok | 17768s |
2 | Phenom II 1050T 2.4GHz | threadMemPerft5 10 6 250000000 12 1000000 | 69352859712417ok | 15643s |
2 | Phenom II 1050T 2.4GHz | threadMemPerft5 10 6 250000000 5 1000000 | 69352859712417ok | 15251s |
2 | Phenom II 1050T 2.4GHz | threadMemPerft5 10 6 250000000 8 1000000 | 69352859712417ok | 15186s |
3 | Phenom II 1050T 2.4GHz | threadMemPerft6 10 6 250000000 8 1000000 | 69352859712417ok | 13618s |
3 | Phenom II 1050T 2.4GHz | threadMemPerft6 10 6 250000000 8 10000000 | 69352859712417ok | 13599s |
0 | Q6600 | threadMemPerft 10 5 50000000 8 1000000 | 69352859712417ok | 42144s | krzyszp
2 | Q6600 | threadMemPerft2 10 4 6250000 8 6 | 69352859712417ok | 40806s | krzyszp
2 | Q6600 | hreadMemPerft5 10 4 50000000 8 10000000 | 69352859712417ok | 37182s | krzyszp
2 | Q6600 | threadMemPerft5 10 4 50000000 8 10000000 | 69352859712417ok | 37149s | krzyszp
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 0 | 69352859712417ok | 21051s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 200 | 69352859712417ok | 16967s |
0 | i7 950 @3.07GHz | threadMemPerft2 10 5 56250000 8 1 | 69352859712417ok | 13667s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 1000000 | 69352859712417ok | 12173s |
2 | i7 950 @3.07GHz | threadMemPerft5 10 4 450000000 8 10000000 | 69352859712417ok | 12144s |
0 | i7 950 @3.07GHz | threadMemPerft 10 5 450000000 8 10000000 | 69352859712417ok | 12092s |
2 | i7 950 @3.07GHz | threadMemPerft5 10 5 450000000 8 10000000 | 69352859712417ok | 11475s |
2 | i7 950 @3.07GHz | threadMemPerft5 10 5 450000000 5 10000000 | 69352859712417ok | 11396s |
3 | i7 950 @3.07GHz | threadMemPerft6 10 5 450000000 8 30000000 | 69352859712417ok | 10359s |
3 | i7 950 @3.07GHz | threadMemPerft6 10 5 450000000 8 10000000 | 69352859712417ok | 10341s |
3 | i7 950 @3.07GHz | threadMemPerft6 10 5 450000000 4 1000000 | 69352859712417ok | 10293s |
0 | e3-1230 v2 3.3ghz | threadMemPerft 10 6 259200000 8 200 | 69352859712417ok | 16895s | sknd
2[2]| e3-1230 v2 3.3ghz | threadMemPerft 10 6 259200000 5 10000000 | 69352859712417ok | 13683s | sknd
0 | e3-1230 v2 3.3ghz | threadMemPerft2 10 6 32400000 8 1 | 69352859712417ok | 13085s | sknd
2 | e3-1230 v2 3.3ghz | threadMemPerft5 10 4 259200000 8 10000000 | 69352859712417ok | 12730s | sknd
0 | e3-1230 v2 3.3ghz | threadMemPerft2 10 6 32400000 8 7 | 69352859712417ok | 11709s | sknd
2 | Q9400 | threadMemPerft2 10 4 6250000 8 6 | 69352859712417ok | 34954s | patyczak
2 | Q9400 | threadMemPerft5 10 4 50000000 8 10000000 | 69352859712417ok | 32666s | patyczak
2 | AMD 48core | threadMemPerft5 10 4 580000000 8 1000000 | 69352859712417ok | 19820s | AXm77
3 | AMD 48core | threadMemPerft6 10 4 580000000 8 1000000 | 69352859712417ok | 18154s | AXm77
2 | AMD 48core | threadMemPerft5 10 8 580000000 8 1000000 | 69352859712417ok | 10352s | AXm77
3 | AMD 48core | threadMemPerft6 10 8 580000000 8 1000000 | 69352859712417ok | 9095s | AXm77
2 | AMD 48core | threadMemPerft5 10 16 580000000 8 1000000 | 69352859712417ok | 5362s | AXm77
3 | AMD 48core | hreadMemPerft6 10 16 580000000 8 1000000 | 69352859712417ok | 4593s | AXm77
2 | AMD 48core | threadMemPerft5 10 24 580000000 8 1000000 | 69352859712417ok | 3709s | AXm77
3 | AMD 48core | threadMemPerft6 10 24 580000000 8 1000000 | 69352859712417ok | 3080s | AXm77
3 | AMD 48core | threadMemPerft6 10 48 580000000 1 10000000 | 69352859712417ok | 2921s | AXm77
2 | AMD 48core | threadMemPerft5 10 32 580000000 8 1000000 | 69352859712417ok | 2883s | AXm77
3 | AMD 48core | threadMemPerft6 10 32 580000000 8 1000000 | 69352859712417ok | 2383s | AXm77
2 | AMD 48core | threadMemPerft6 10 48 580000000 5 1 | 69352859712417ok | 2854s | AXm77
2 | AMD 48core | threadMemPerft5 10 52 580000000 8 1000000 | 69352859712417ok | 2074s | AXm77
3 | AMD 48core | threadMemPerft6 10 48 580000000 3 10000000 | 69352859712417ok | 1669s | AXm77
2 | AMD 48core | threadMemPerft5 10 48 580000000 8 1000000 | 69352859712417ok | 2065s | AXm77
3 | AMD 48core | threadMemPerft6 10 52 580000000 8 1000000 | 69352859712417ok | 1658s | AXm77
3 | AMD 48core | threadMemPerft6 10 48 580000000 8 1000000 | 69352859712417ok | 1642s | AXm77
3 | AMD 48core | threadMemPerft6 10 48 580000000 4 10000000 | 69352859712417ok | 1641s | AXm77
3 | AMD 48core | threadMemPerft6 10 48 580000000 5 1000000 | 69352859712417ok | 1617s | AXm77
2 | AMD 48core | threadMemPerft6 10 48 580000000 5 1000 | 69352859712417ok | 1631s | AXm77
2 | AMD 48core | threadMemPerft6 10 48 580000000 5 1000000 | 69352859712417ok | 1617s | AXm77
2 | AMD 48core | threadMemPerft6 10 48 580000000 5 1000000000 | 69352859712417ok | 1615s | AXm77
2 | AMD 48core | threadMemPerft6 10 48 580000000 5 10000000 | 69352859712417ok | 1613s | AXm77
------------------------------------------------------------------------------------------------------------------
[1] - z tej wersji prawdopodobnie zapomniałem usunąć asercje i spowolniły program.
[2] - dwa rdzenie komputera były obciążone
Na konfigurację serwera proponuję nowy wątek. Przyda się kiedyś komuś bez potrzeby szukania po wątkach "zabawowych" ;)
Cytat: Szopler w 01 Czerwiec 2013, 10:45
Na konfigurację serwera proponuję nowy wątek. Przyda się kiedyś komuś bez potrzeby szukania po wątkach "zabawowych" ;)
Spróbujemy :)
Cytat: mariotti w 02 Czerwiec 2013, 05:35
Cytat: Szopler w 01 Czerwiec 2013, 10:45
Na konfigurację serwera proponuję nowy wątek. Przyda się kiedyś komuś bez potrzeby szukania po wątkach "zabawowych" ;)
Spróbujemy :)
Spróbowałem i na razie nie wiem z tego nic. Masakra :/
Przeglądałeś tą stronę?
http://www.spy-hill.net/myers/help/boinc/Create_Project.html (http://www.spy-hill.net/myers/help/boinc/Create_Project.html)
gdzies na naszej wiki jest chyba tutorial jak postawic serwer BOINCa na debianie.....
Cytat: Troll81 w 03 Czerwiec 2013, 18:13
gdzies na naszej wiki jest chyba tutorial jak postawic serwer BOINCa na debianie.....
Dzięki za pomoc i linki, będę dalej próbował. Jak na razie rozumiem to co napisał TJM i
niestety nic więcej :/ No ale może w końcu załapię.
Pozdrawiam
Cytat: AXm77 w 03 Czerwiec 2013, 15:43
Przeglądałeś tą stronę?
http://www.spy-hill.net/myers/help/boinc/Create_Project.html (http://www.spy-hill.net/myers/help/boinc/Create_Project.html)
Ten materiał w moim odczuciu jest trochę lepszy, przejrzałem i trochę zrozumiałem.
Spróbuję jutro znaleźć czas i wczytam się dokładniej, potem dam znać, czy coś z tego
wynikło
Pozdrawiam
http://www.boincatpoland.org/wiki/Instalacja_serwera_BOINC_na_systemie_Debian_Wheezy
work in progres :D jak chcesz to dopisz cos od siebie.... bo u mnie temat zaginął w gąszczu codzienności....
Cytat: Troll81 w 04 Czerwiec 2013, 18:20
http://www.boincatpoland.org/wiki/Instalacja_serwera_BOINC_na_systemie_Debian_Wheezy
work in progres :D jak chcesz to dopisz cos od siebie.... bo u mnie temat zaginął w gąszczu codzienności....
Jak ja bez znajomości zagadnienia zacząłbym o nim pisać, to dopiero wyszedłby bełkot :D
Zapraszam do zapoznania się z tematem więc i poszerzenia łopatologa....
Cytat: Troll81 w 05 Czerwiec 2013, 18:01
Zapraszam do zapoznania się z tematem więc i poszerzenia łopatologa....
Próbuję zapoznać się... ale idzie to koszmarnie powoli. Wczoraj, po kilkugodzinnej
próbie rozszyfrowania jakiegoś angielskiego tekstu, "dowiedziałem" się, że po
aktualizacji pakietów systemu boinc, trzeba sprawdzić czy w systemie operacyjnym
są pakiety w wersjach wymaganych przez nowe pakiety boinc. No dobra... może
kiedyś uniknę jakiegoś zaskoczenia, ale żeby unikać, to trzeba najpierw mieć coś
działającego ;-)
Pozdrawiam
Na jakiej licencji jest MySQL do zastosowań w BOINC?
Z tego co pamiętam, MySQL był darmowy do:
- darmowych projektów,
- wszelkich aplikacji webowych.
A co z zastosowaniami w projektach BOINC?
Pozdrawiam
Jest na GPL, więc spokojnie można używać do wszystkich projektów, jedyynie przy rozpowszechnianiu MySQL z Twoją aplikacją ona również musi być na GPL.Zaznaczam, że to występuje tylko wtedy, gdy pliki MySQL (nie bazy jako takie!) rozpowszechniasz z Twoim programem.
Cytat: krzyszp w 07 Czerwiec 2013, 15:42
Jest na GPL, więc spokojnie można używać do wszystkich projektów, jedyynie przy rozpowszechnianiu MySQL z Twoją aplikacją ona również musi być na GPL.Zaznaczam, że to występuje tylko wtedy, gdy pliki MySQL (nie bazy jako takie!) rozpowszechniasz z Twoim programem.
Coś mi się zdaje że to jest znacznie bardziej skomplikowane, dlatego ja kilka lat temu
przerzuciłem się całkowicie na Postgresa i mam z tym spokój. Idealnie byłoby, jakby
BOINCa skonfigurować do pracy z Postgresem, ale pewnie się nie da.
Zdaje się, że nawet w Stanach są sprzeczne wyroki spowodowane sprzeczną interpretacją tego
mglistego określenia z licencji GPL, a mianowicie chodzi o sformułowanie "utwory zależne". Jeśli
utwór jest zależny od czegoś na GPL, to w chwili publikowania, odbiorcy mają prawo do otrzymania
źródeł itd. Chyba nigdy nie będzie dla mnie jasne i oczywiste gdzie jest granica oddzielająca zależne od
niezależne. Podobnie nie jest dla mnie oczywiste kiedy dochodzi do publikacji utworu, a kiedy nie, np.
czy prezentacja wyników w htmlu na stronie www jest już publikacją czy nie jest?
Pozdrawiam
To, że w Stanach są kontrowersje, to mnie nie dziwi - ich prawodawstwo jest chore...
Jedno jest pewne - jeśli serwer chodzi u Ciebie i nie includujesz jego bibliotek w swoim progsie, to masz pełne prawo komercyjnie soft rozprowadzać. Wiem, bo konsultowałem się z prawnikiem na ten temat, gdyż soft mojej firmy tak działa...
Wg licencji GNU GPL, jeśli chcesz korzystać w swoim programie z oprogramowania będącego na takiej licencji to twój program też musi być na licencji GPL. Tak więc musisz udostępnić żródła tego programu. Chyba, że jest oprogramowanie bazowe jest na licencji LGPL, ale tu głównie chodzi o biblioteki dołączanie dynamiczne...
CytatPodobnie nie jest dla mnie oczywiste kiedy dochodzi do publikacji utworu, a kiedy nie, np.
czy prezentacja wyników w htmlu na stronie www jest już publikacją czy nie jest?
Jeśli twój program działa jako strona WWW to jest to publikacja, a jeśli tylko jest to pokazanie jego możliwości to nie jest to publikowanie.
Dario, wyraziłeś się nieprecyzyjnie...
Założenie jest takie, że dopóki nie załączasz kodu źródłowego lub wynikowego programu objętego licencją GPL do swojego programu, również poprzez linkowanie statyczne oraz nie rozprowadzasz żadnej części tego kodu wraz z Twoim, to nie podlegasz pod postanowienia tej licencji...
1. Czyli, jeżeli stawiasz u siebie serwer MySQL, a twój program się z nim łączy - wszystko jest ok, nie musisz udostępniać źródeł.
2. Wypadek jak wyżej, ale Twoj program wykorzysztuje np. mysql_connector includowany w kodzie - w tym momencie podlegasz pod GPL i musisz udostępnić kod.
Dodam, że nic nie stoi na przeszkodzie, abyś w OBYDWU przypadkach sprzedawał swój program (a nawet serwer MySQL), ale w drugim przypadku masz OBOWIĄZEK udostępnić klientowi kod źródłowy i Twój program automatycznie jest wtedy na licencji GPL.
Cytat: krzyszp w 07 Czerwiec 2013, 18:11
Założenie jest takie, że dopóki nie załączasz kodu źródłowego lub wynikowego programu objętego licencją GPL do swojego programu, również poprzez linkowanie statyczne oraz nie rozprowadzasz żadnej części tego kodu wraz z Twoim, to nie podlegasz pod postanowienia tej licencji...
Dzięki za wyjaśnienia :)
Cytat: krzyszp w 07 Czerwiec 2013, 18:11
Dodam, że nic nie stoi na przeszkodzie, abyś w OBYDWU przypadkach sprzedawał swój program (a nawet serwer MySQL), ale w drugim przypadku masz OBOWIĄZEK udostępnić klientowi kod źródłowy i Twój program automatycznie jest wtedy na licencji GPL.
Zgadza się. Tego faktu do niedawna nie wiedziałem, gdyż kilka osób powtórzyło mi
zgodnie, że nie można sprzedawać. Nie wiem dlaczego ten mit się tak łatwo
rozpowszechnił.
Pozdrawiam
Ja bym się z tym nie zgodził. W licencji GPL jest informacja, że programu takiego nie można sprzedawać, bo wtedy nie jest już to "wolne oprogramowanie" tylko komercyjne. Na to pozwala tylko licencja BSD lub X11.
Cytat: Dario666 w 08 Czerwiec 2013, 19:54
Ja bym się z tym nie zgodził. W licencji GPL jest informacja, że programu takiego nie można sprzedawać, bo wtedy nie jest już to "wolne oprogramowanie" tylko komercyjne.
Sorry, ale bzdury opowiadasz ;)
Nie ma zapisu o zakazie sprzedaży w żadnej wersji GPL. "Wolne" oznacza "wolne źródła", a nie "darmowe" - "free as 'freedom' not as 'free beer'".
To podaj program na licencji GPL za który trzeba zapłacić.
Cytat: Dario666 w 08 Czerwiec 2013, 22:35
To podaj program na licencji GPL za który trzeba zapłacić.
Red Hat Enterprise :)
Edit:
Dla rozrywki odbiję też piłeczkę - podaj paragraf licencji GPL (obojętnie której wersji) w którym jest napisane, że NIE MOŻESZ sprzedawać programu na licencji GPL...
Cytat: Dario666 w 08 Czerwiec 2013, 19:54
Ja bym się z tym nie zgodził. W licencji GPL jest informacja, że programu takiego nie można sprzedawać, bo wtedy nie jest już to "wolne oprogramowanie" tylko komercyjne. Na to pozwala tylko licencja BSD lub X11.
W GPL jest coś w rodzaju "obojętnie czy sprzedajesz czy udostępniasz za darmo" -
dla mnie to znaczy że licencja GPL może dotyczyć zarówno programów komercyjnych jak i
darmowych. GPL głównie ma na celu:
- unikanie odpowiedzialności przez programistów za ewentualne błędy w programach
- zapewnienie klientom dostępu do źródeł, chociażby w celu update gdy autor się wypnie
- zabezpieczenie autorom praw autorskich do wszystkich fragmentów kodu które
utworzyli; nie można wziąć programu na GPL i go sprzedać/dać komuś wprowadzając
tego kogoś w błąd, że ktoś inny (np. sprzedający) jest autorem.
O zakazie sprzedaży w licencji nic nie ma, a wielu ludzi twierdzi że nie można
sprzedawać - nie wiem czemu bo to jest jasne. Zagmatwane jest określenie "utwory zależne".
Całkiem sensowną interpretację podał:
Cytat: krzyszp w 07 Czerwiec 2013, 18:11
Założenie jest takie, że dopóki nie załączasz kodu źródłowego lub wynikowego programu objętego licencją GPL do swojego programu, również poprzez linkowanie statyczne oraz nie rozprowadzasz żadnej części tego kodu wraz z Twoim, to nie podlegasz pod postanowienia tej licencji...
Aby mieć absolutną pewność, to najlepiej jeszcze poprosić prawnika o kilka wyroków w
sprawach sądowych. Ja takich wyroków na razie nie widziałem, ale też nigdy nie starałem
się ich znaleźć.
Pozdrawiam
P.S.
Może zamieszanie spowodowanie jest tym, że nie można sprzedawać
źródeł programu, za źródła
można pobierać opłatę nie większą niż cena nośnika.
Masz rację, a jednocześnie się mylisz :)
1. Były już sprawy sądowe dotyczące programów GPL - walczyła o to FSF (http://di.com.pl/news/20805,0,Skype_nie_uwolnil_sie_od_warunkow_GPL.html - jeden przykład, http://gpl-violations.org/).
2. Wolno sprzedawać kod (zarówno źródła jak i kod wynikowy) na licencji GPL:
a) po cenie nośnika, jeśli kod nie jest Twój;
b) w dowolnej cenie, jeśli jesteś choćby w części autorem kodu - zwróć uwagę na ceny wspomnianego przeze mnie Red Hat'a ;)
Komercyjna sprzedaż programów na licencji GPL jest rzadkością, gdyż jest bardzo trudne - raz sprzedany program szybko powoduje "wyciek" kodu, który nabywca może (i zwykle to robi) udostępnić za darmo. Np. w przypadku Red Hat'a robią to twórcy CentOS'a, który jest klonem tego systemu i tylko branding ma zmieniony ze względu na fakt, że nazwa i logotyp Red Hat są zastrzeżonymi znakami towarowymi.
Cytat: krzyszp w 09 Czerwiec 2013, 09:35
Masz rację, a jednocześnie się mylisz :)
Hmmm
Cytat: krzyszp w 09 Czerwiec 2013, 09:35
1. Były już sprawy sądowe dotyczące programów GPL - walczyła o to FSF (http://di.com.pl/news/20805,0,Skype_nie_uwolnil_sie_od_warunkow_GPL.html - jeden przykład, http://gpl-violations.org/).
Może wyraziłem się niezbyt jasno. Więc jeszcze raz: na pewno nie chodzi mi o to, że jest
sprawą dyskusyjną, czy trzeba załączać treść licencji czy nie - a ta sprawa sądowa była głównie o to.
Licencję trzeba załączyć, więc sprawę mogli przegrać już o to. Podobnie na życzenie klienta
trzeba udostępnić kod. Z materiału w tym artykule wynika że nie postarali się o udostępnienie. To
wszystko we mnie też nie wywołuje żadnych wątpliwości. Więc ta sprawa sądowa dotyczy czegoś
innego niż mojego zmartwienia :)
Cytat: krzyszp w 09 Czerwiec 2013, 09:35
2. Wolno sprzedawać kod (zarówno źródła jak i kod wynikowy) na licencji GPL:
a) po cenie nośnika, jeśli kod nie jest Twój;
O to samo mi chodziło, chyba znowu coś napisałem niezrozumiale :)
Cytat: krzyszp w 09 Czerwiec 2013, 09:35
b) w dowolnej cenie, jeśli jesteś choćby w części autorem kodu - zwróć uwagę na ceny
wspomnianego przeze mnie Red Hat'a ;)
Jeśli produkt opublikowaliśmy, to nie możemy sprzedać źródeł po cenie wyższej niż cena
nośnika ( nie mam pewności czy można wziąć pieniądze za cenę opakowania i koszty
dostarczenia jeśli wysyła się kurierem albo pocztą - ale to mało ważne ). Natomiast
jeśli produktu nie opublikowaliśmy, to licencja, w sensie wynikających z niej
obowiązków, nie obowiązuje - mamy tylko same prawa z niej płynące.
Cytat: krzyszp w 09 Czerwiec 2013, 09:35
Komercyjna sprzedaż programów na licencji GPL jest rzadkością, gdyż jest bardzo trudne - raz sprzedany program szybko powoduje "wyciek" kodu, który nabywca może (i zwykle to robi) udostępnić za darmo. Np. w przypadku Red Hat'a robią to twórcy CentOS'a, który jest klonem tego systemu i tylko branding ma zmieniony ze względu na fakt, że nazwa i logotyp Red Hat są zastrzeżonymi znakami towarowymi.
Osobiście nie mam rzetelnych danych na ten temat, ale byłem kilka razy
przekonywany, że nie jest rzadkością, chociażby dlatego że zbudowanie aplikacji
ze źródeł może być trudne. Drugim powodem przemawiającym za tym że
często dochodzi do sprzedaży na licencji GPL, może być to że klientom jednak nie
zależy na dalszym udostępnianiu kodu - więc po kupieniu zatrzymują kod dla
siebie.
Tak czy inaczej, ja widzę że się zgadzamy co do najważniejszych faktów :)
Moje zmartwienia polegają na czymś innym. Mianowicie na tym, że
nie wiem jak w sprawach sądowych były interpretowane dwa określenie. Po
pierwsze jak sądy wyznaczają granicę pomiędzy tym co
opublikowanie a
nieopublikowane.
Po drugie jak sądy wyznaczają granicę pomiędzy tym co jest
utworem zależnym a
utworem niezależnym. Przeczytałem to co napisałeś kilka postów wyżej na
temat utworów zależnych i zrozumiałem. Chodzi mi o to, że nie znam spraw sądowych
w których spierano się o to, czy utwór jest zależny czy nie jest zależny. I tak samo
względem publikacji. W jakich sprawach spierano się o to, czy utwór był już publikowany
czy też nie.
Pozdrawiam :)
Wydaje mi się, że kwestia tego, czy utwór był opublikowany jest dość prosta - jeśli dany utwór został choć w jednym egzemplarzu sprzedany/oddany to uznaje się za opublikowany.
Warto wspomnieć, że nie musisz w takim przypadku udostępniać kodu wszystkim - masz ten obowiązek tylko w stosunku do osoby, której kod udostępniłeś!
Natomiast spraw sądowych o to jest faktycznie mało, gdyż firmy "przyłapane" na rozpowszechnianiu utworu objętego GPL a nie udostępniające kodu źródłowego zazwyczaj (w 99,9% przypadków) po upomnieniu i zagrożeniu procesem przez FSF (gpl-violations) po prostu udostępniają kod - tak było np. w przypadku MS i (chyba) narzędzia USB Download Tool.
Natomiast, co do utworów zależnych, to faktycznie jest to trochę bardziej skomplikowane. Na własny użytek, mam własny sposób.
Moje programy korzystają z narzędzia (biblioteki) VBMySQLDirect* objętej licencją GPL, ale nie załączam jej w swoich programach. Po prostu informuję klienta, że taką bibliotekę musi samodzielnie zainstalować u siebie.
Generalnie, jeżeli nie pomyliłem terminów, to można bez problemów odwoływać się do takich bibliotek, ale nie można ich linkować statycznie.
*VBMySQLDirect oferuje do 100x szybszego połączenia z MySQL niż biblioteki z Oracle - sprawdziłem to eksperymentalnie na dużych bazach...
Serwer BOINC można spokojnie stawiać na MySQL.
Co do includowania bibliotek MySQL to przecież w aplikacji liczącej nic takiego nie powinno być dodawane. Mamy więc problem z głowy.
Ogólnie dyskusja zeszła na trochę inny temat.
Cytat: krzyszp w 09 Czerwiec 2013, 10:42
Wydaje mi się, że kwestia tego, czy utwór był opublikowany jest dość prosta - jeśli dany utwór został choć w jednym egzemplarzu sprzedany/oddany to uznaje się za opublikowany.
Niepokoją mnie te wszelkie zastosowania w których bezpośrednio publikowane są wyniki
działania aplikacji, a nie sama aplikacja. Przykładowo można na nośniku udostępniać
tylko aplikację kliencką która zaprezentuje wyniki działania serwera. Jednak cały utwór to
komplet: serwer i klient. Gdy serwer nie opuszcza mojego lub wynajmowanego przeze mnie
komputera, to wydaje się, że źródeł serwera nie muszę udostępniać - choćby był zależny od
oprogramowania GPL - ale pewności nie mam.
Cytat: krzyszp w 09 Czerwiec 2013, 10:42
Warto wspomnieć, że nie musisz w takim przypadku udostępniać kodu wszystkim - masz ten obowiązek tylko w stosunku do osoby, której kod udostępniłeś!
Tak też i ja rozumiem GPL - dlatego pisałem o takiej możliwości, w której nikt z wąskiego grona klientów
nie rozpowszechni kodu źródłowego dalej.
Cytat: krzyszp w 09 Czerwiec 2013, 10:42
Natomiast spraw sądowych o to jest faktycznie mało, gdyż firmy "przyłapane" na rozpowszechnianiu utworu objętego GPL a nie udostępniające kodu źródłowego zazwyczaj (w 99,9% przypadków) po upomnieniu i zagrożeniu procesem przez FSF (gpl-violations) po prostu udostępniają kod - tak było np. w przypadku MS i (chyba) narzędzia USB Download Tool.
Jeśli firmy nie zdecydowały się wejść na drogę sądową, to też dużo mówi, dużo więcej
niż opinia prawnika postawiona na bazie samej znajomości prawa. Chodzi po prosto o te
wszystkie sporne sytuacje, gdy ktoś uważał że utwór już był opublikowany, a
ktoś inny że jeszcze nie był i to samo względem zależności.
Cytat: krzyszp w 09 Czerwiec 2013, 10:42
Natomiast, co do utworów zależnych, to faktycznie jest to trochę bardziej skomplikowane. Na własny użytek, mam własny sposób.
Moje programy korzystają z narzędzia (biblioteki) VBMySQLDirect* objętej licencją GPL, ale nie załączam jej w swoich programach. Po prostu informuję klienta, że taką bibliotekę musi samodzielnie zainstalować u siebie.
Generalnie, jeżeli nie pomyliłem terminów, to można bez problemów odwoływać się do takich bibliotek, ale nie można ich linkować statycznie.
Chyba masz rację, ja myślę tak samo.
Cytat: krzyszp w 09 Czerwiec 2013, 10:42
*VBMySQLDirect oferuje do 100x szybszego połączenia z MySQL niż biblioteki z Oracle - sprawdziłem to eksperymentalnie na dużych bazach...
Sto razy to bardzo dużo.
Pozdrawiam
Cytat: Rysiu w 09 Czerwiec 2013, 11:27
Serwer BOINC można spokojnie stawiać na MySQL.
Co do includowania bibliotek MySQL to przecież w aplikacji liczącej nic takiego nie powinno być dodawane. Mamy więc problem z głowy.
Ogólnie dyskusja zeszła na trochę inny temat.
BOINC jest na licencji LGPL i korzysta z MySQL który jest na licencji GPL - tego
to już zupełnie nie rozumiem :) Przecież licencja GPL jest licencją wirusową, więc
BOINC też powinien być na licencji GPL. Czyżby sposób w jaki korzysta z MySQL
nie powodował, że w myśl licencji GPL jest
utworem zależnym?
Może dyskusja zeszła na inny temat, ale oprogramowanie BOINC jest w jakimś
stopniu zależne od GPL i LGPL - więc warto dokładnie wiedzieć jakie mamy
prawa i obowiązki.
Pozdrawiam
Cytat: mariotti w 09 Czerwiec 2013, 11:35
Cytat: krzyszp w 09 Czerwiec 2013, 10:42
Wydaje mi się, że kwestia tego, czy utwór był opublikowany jest dość prosta - jeśli dany utwór został choć w jednym egzemplarzu sprzedany/oddany to uznaje się za opublikowany.
Niepokoją mnie te wszelkie zastosowania w których bezpośrednio publikowane są wyniki
działania aplikacji, a nie sama aplikacja. Przykładowo można na nośniku udostępniać
tylko aplikację kliencką która zaprezentuje wyniki działania serwera. Jednak cały utwór to
komplet: serwer i klient. Gdy serwer nie opuszcza mojego lub wynajmowanego przeze mnie
komputera, to wydaje się, że źródeł serwera nie muszę udostępniać - choćby był zależny od
oprogramowania GPL - ale pewności nie mam.
To możesz mieć pewność ;)
Jak rozumiem, sytuacja jest taka, że serwer projektu (baza danych, czy cokolwiek innego) działa na oprogramowaniu GPL (Apache, MySQL, itd) natomiast Twój program ma być zamknięto-źródłowy, tak?
W takim razie, o ile nie załączasz do klienta żadnych bibliotek objętych licencją GPL (a ja nie widzę w tym przypadku takiej potrzeby) to nie musisz udostępniać swoich źródeł. Dodatkowo, możesz dowolnie modyfikować oprogramowanie na serwerze i również nie ma konieczności udostępniania źródeł (wszak nie udostępniasz
kodu serwera).
Reasumując -spokojnie możesz zamknąć źródła.
Domyślam się, że chcesz chronić swój algorytm?
Serwer BOINC korzysta z MySQL, ale go
nie zawiera - zachodzi tutaj taka sama sytuacja jak w przypadku mojego oprogramowania (sam doinstalowujesz, czyli "zaopatrujesz" się w MySQL).
Cytat: krzyszp w 09 Czerwiec 2013, 11:45
To możesz mieć pewność ;)
OK :)
Cytat: krzyszp w 09 Czerwiec 2013, 11:45
Reasumując -spokojnie możesz zamknąć źródła.
Domyślam się, że chcesz chronić swój algorytm?
Jeśli chodzi o algorytmy we wszelkich projektach związanych z szachami, to zawsze
"chroniłem" je przez około 2-3 lata, potem udostępniałem wszystko za darmo i zupełnie
bez żadnych ograniczeń - tak samo będzie w tym projekcie. Spowodowane jest to tym,
że czasami na różnych imprezach, mogę zostać poproszony o udowodnienie że jestem
autorem, a jest trochę trudniej gdy można fragmenty kodu wygooglać :)
Raczej wybiegłem myślami w przyszłość. Co jakbym kiedyś miał dla kogoś napisać
jakiś algorytm w środowisku BOINC i ten ktoś chciałby żeby kod został zamknięty?
Cytat: krzyszp w 09 Czerwiec 2013, 11:45
Serwer BOINC korzysta z MySQL, ale go nie zawiera - zachodzi tutaj taka sama sytuacja jak w przypadku mojego oprogramowania (sam doinstalowujesz, czyli "zaopatrujesz" się w MySQL).
Ok.
Dzięki i pozdrawiam
Wróćmy do problemów technicznych....
No więc często gdy coś czytam, to napotykam w opisach archaiczne
wersje systemów, narzędzi i kompilatorów - co napawa mnie przerażeniem.
Przykładowo na tej stronie:
http://www.spy-hill.net/myers/help/boinc/boinc-on-linux.html
mamy problem kompilatora gcc-2.9, a u mnie na kompie jest
kompilator w wersji 4.6.1, pomimo że nigdy u siebie go nie
aktualizowałem.
Podobnie, spotkałem się już kilkakrotnie z informacją, że BOINC z systemu CSV
przeszedł na SVN, a tymczasem BOINC do kontroli wersji wykorzystuje już GIT -
i to wszystko napisane nie w moim ojczystym języku - co będzie dalej to
już sobie wyobrażam :)
Pozdrawiam
Cytat: mariotti w 09 Czerwiec 2013, 12:41
i to wszystko napisane nie w moim ojczystym języku - co będzie dalej to
już sobie wyobrażam :)
No i sobie wyobraziłem ;)
delete_file.cpp:40:25: fatal error: svn_version.h: Nie ma takiego pliku ani katalogu
compilation terminated.
make[1]: *** [delete_file.o] Błąd 1
make[1]: Opuszczenie katalogu `/home/x/Dokumenty/c/boinc_repo/sched'
make: *** [all-recursive] Błąd 1
Ciekawe co to za błąd i jak sobie z nim poradzić.
Pozdrawiam
Brak pliku svn_version.h?
Cytat: krzyszp w 09 Czerwiec 2013, 13:57
Brak pliku svn_version.h?
To na pewno. Pytanie dlaczego go nie ma, skoro ściągnąłem świeżą
wersję z gita. Może tutorial przestarzały... Odpaliłem jeszcze raz, tym razem samo
"make" bez tych parametrów które podają w tutorialu i zakończyło się bez
błędów.
Teraz próbuje opanować skrypt make_project.
Pozdrawiam
Cytat: mariotti w 09 Czerwiec 2013, 14:04
Teraz próbuje opanować skrypt make_project.
Coś zrobiłem... nie do końca wiem co :)
./make_project --delete_prev_inst --drop_db_first --project_root /home/x/boinc_test_0 --db_host localhost --db_user xxxx --db_passwd xxxx boinc_test_0
Creating project 'boinc_test_0' (short name 'boinc_test_0'):
PROJECT_ROOT = /home/x/boinc_test_0/
URL_BASE = http://localhost6.localdomain6/
HTML_USER_URL = http://localhost6.localdomain6/boinc_test_0/
HTML_OPS_URL = http://localhost6.localdomain6/boinc_test_0_ops/
KEY_DIR = /home/x/boinc_test_0/keys/
DB_NAME = boinc_test_0
DB_HOST = localhost
Delete /home/x/boinc_test_0/? [y/N] y
Deleting /home/x/boinc_test_0/
Continue? [Y/n] y
Creating directories
Generating encryption keys
Copying files
Setting up database
Writing config files
Linking CGI programs
PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib/php5/20090626/mcrypt.so' - /usr/lib/php5/20090626/mcrypt.so: cannot open shared object file: No such file or directory in Unknown on line 0
PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib/php5/20090626/mcrypt.so' - /usr/lib/php5/20090626/mcrypt.so: cannot open shared object file: No such file or directory in Unknown on line 0
update_translations finished
Done installing default daemons.
Done creating project. Please view
/home/x/boinc_test_0/boinc_test_0.readme
for important additional instructions.
Tak jakby zabrakło pliku: /usr/lib/php5/20090626/mcrypt.so. Ciekawe czemu akurat
w takim podkatalogu go szuka? Tak oznaczają wersje czy co?
Niemniej coś działa .Nie bardzo wiem co działa, ale działa :)
Wpisałem w przeglądarkę sugerowany url:
http://localhost6.localdomain6/
i mam:
It works!
This is the default web page for this server.
The web server software is running but no content has been added, yet.
Nie widzę odpowiednich zmian w plikach konfiguracyjnych apache... a stronę
podał - masakra jakaś.
Pozdrawiam
mcrypt nie jest czasami używany do generowania sum kontrolnych plików?
Cytat: krzyszp w 09 Czerwiec 2013, 14:39
mcrypt nie jest czasami używany do generowania sum kontrolnych plików?
Coś w tym rodzaju :)
http://www.php.net/manual/en/intro.mcrypt.php
Nigdy tego nie używałem, przynajmniej świadomie :)
Pozdrawiam
Poczytałem sobie instrukcję konfiguracji web-serwera:
http://www.spy-hill.net/myers/help/boinc/httpd-conf.html
Nie wiem czy zrozumiałem, wydaje mi się, że większość tak. Jednak
nie piszę dlatego żeby poinformować o tym że czytałem. Dochodzę
do wniosku, że ktoś kto nie miał wcześniej do czynienia z konfiguracją
web-serwera nie jest w stanie zrozumieć tej instrukcji. Ja miałem
takie doświadczenia, ale raczej w małym stopniu.
Ogólny wniosek z tego jest taki, że do postawienia serwera
BOINC trzeba się znać na... chyba na wszystkim.
Po pierwsze trzeba się znać na:
a) danym zagadnieniu które chce się policzyć
b) programowaniu rozproszonym i optymalizacji w programowaniu rozproszonym
c) programowaniu niskopoziomowym i optymalizacji kodu (jakiś C/C++/Fortran/Asembler/CUDA i konkurencja/MMX i spółka/itd)
Po drugie:
a) konfiguracji systemu Linux, zwłaszcza na zabezpieczeniach, instalacji, konfiguracji pakietów oprogramowania, itd
b) konfiguracji webserwera, konkretnie Apache
c) konfiguracji mysql
d) języku SQL
e) języku PHP, HTML, JavaScript i co tam jeszcze potrzebne do robienia aplikacji webowych
f) znajomość takich drobiazgów jak język xml czy skrypty powłoki też nie zawadzi
Dopiero wtedy można:
a) poznać i skonfigurować samo środowisko
b) nauczyć się frameworków i API dla C/C++/PHP - aby to było możliwe raczej trzeba mieć doświadczenia w innych frameworkach
c) napisać aplikację serwerową
d) napisać aplikację kliencką pod każdy system "osobno" - w cudzysłowie, bo czasami można pisać przenośnie.
Trzeba jeszcze dobrze czytać po angielsku i domyślać się co w opisach i tutorialach jest już nieaktualne :)
Gdy zaczynałem, to myślałem że jest to takie środowisko, do którego może przysiąść zupełnie każdy
programista, nawet z małym doświadczeniem. Tymczasem zakres zagadnień na których trzeba się
chociaż w średnim stopniu znać jest spory. Nie chcę w ten sposób powiedzieć że się wycofuję ani nic
podobnego. Chodzi mi o to, że środowisko do obliczeń rozproszonych wykorzystywane na tak wielką skalę,
powinno być już dawno przez kogoś lepiej zintegrowane. Właśnie to powinno wyglądać tak, że ktoś
instaluje jakiś pakiet softu i po prostu pisze kod serwera i klienta. Przecież takie zintegrowanie jest
jak najbardziej możliwe - choć bardzo pracochłonne, ale doprowadzenie BOINC do takiego stanu w
jakim jest obecnie, też było pracochłonne.
Pozdrawiam
Kontynuując...
Próbowałem kilka razy utworzyć projekt przy pomocy skryptu 'make_project'.
Wciąż były takie lub inne problemy, ale w końcu się udało. Dodałem lokalną
sub-domenę do DNS, wygenerowałem hasła dla operatora projektu i widzę
dwie strony: jedną dla użytkowników, drugą dla operatorów.
Trochę mnie dziwi że na stronie nie ma nazwy projektu, trzeba nazwę nadać przy
pomocy jakiegoś 'Project Management' - nie mam bladego pojęcia czy to jakiś program,
czy jakiś dział na tej stronie dla operatorów... Pewnie za jakiś czas się wyjaśni.
Trochę tylko głupio że make_projekt nie nadaje nazwy, skoro ją pobiera jako
parametr.
Ogólnie ciężkie to wszystko. Gdy się wejdzie na stronę dla operatorów to pełno
jakiś opcji, na razie nie mam bladego pojęcia do czego one są. Baza danych
pustego projektu BOINC ma 36 tabel. Oczywiście to nie zawsze jest miarodajne,
ale gdy aplikacja ma 8 tabel, to już może być całkiem skomplikowaną aplikacją.
No ale cóż... będzie trzeba przez to wszystko w bólu przebrnąć... Dobrze że
chociaż witryny projektu działają :D
Pozdrawiam
Baza danych Magento ~360 tabel.
Program do prowadzenia działalności gospodarczej (bez księgowości) - ~70tablel
Mój najbardziej rozbudowany program - 175 tabel.
Im bardziej optymalizujesz zapis informacji w bazie (poprzez atomizację), tym większa ilość tabel powstaje, a przynajmniej tak wynika z mojej praktyki...
dasz radę! czekamy na jakieś testowe WU ;)
Cytat: krzyszp w 11 Czerwiec 2013, 11:44
Baza danych Magento ~360 tabel.
Program do prowadzenia działalności gospodarczej (bez księgowości) - ~70tablel
Mój najbardziej rozbudowany program - 175 tabel.
To bardzo dużo jak na moje programistyczne doświadczenia. Zwykle jak klepałem
jakiś projekt przez 200-300 roboczo-godzin to baza "rozrasta" się może do 8-10 tabel.
Dużo zależy od tego jaki projekt i jak mocno baza jest znormalizowana. Teraz wklepujemy z
kumplem od pół roku pewien projekcik i baza ma 20 tabel, w tym około 5 tabel jest do
wywalenia po zmianach projektowych. Czasami patrzę na gołe instalację frameworków
PHP np. OpenCart, Concreate, Joomla, WordPress i tam 70 tabel to raczej minimum.
No cóż... pewnie te table są potrzebne, a ja jakoś przypadkiem trafiałem tylko na projekty w
których 10 tabel załatwiało sprawę :)
Cytat: krzyszp w 11 Czerwiec 2013, 11:44
Im bardziej optymalizujesz zapis informacji w bazie (poprzez atomizację), tym większa ilość tabel powstaje, a przynajmniej tak wynika z mojej praktyki...
Nie wiem jak rozumiesz atomizację. W przypadku bazy danych były postacie normalne.
Kiedyś pamiętałem która postać co oznacza :D Jeśli nie mylę pojęć, to ja w każdym projekcie
dążę trzeciej postaci normalnej, no i wychodzi mi średnio do 10 tabel.
Cytat: sknd w 11 Czerwiec 2013, 12:55
dasz radę! czekamy na jakieś testowe WU ;)
Dzięki za doping! Za jakiś czas się okaże czy dam radę. Niby z dnia na dzień wiem o
BOINC coraz więcej. Przy poprzednim podejściu utknąłem z powodu jakiś problemów z
Pythonem. Od tamtej porty kompletnie nic nie zmieniałem przy Pythonie, a za drugim
podejściem problem jakoś się nie pojawił... może teraz mam lepszą/nowszą wersję
BOINC - nie wiem. Tak czy inaczej, pusta aplikacja, taka bezpośrednio po instalacji,
lokalnie na moim kompie zadziałała.
Zastanawiam się co dalej. Mam laptopa na procesorze N270. W maksymalnym stresie
pobiera 17Watt mocy - idealny do zastosowań 24-godzinnych na dobę :) Komputer na
jakimś mobilnym procesorze i3 pewnie byłby jeszcze lepszy, ale jedyny egzemplarz jaki
mam, jest mi potrzebny do pracy. Może będę musiał kupić jakiegoś laptopa z I3. Laptopy
zwykle ma słabe dyski, może od razu powinienem kupić jakiś zewnętrzny dysk na USB 3.0.
Adres IP mam stały, ale jednak co kilka tygodni zdarza się że mój provider internetowy
go zmienia. Była jakaś taka usługa... zapomniałem jak się nazywała... chyba home-ip?
Instaluje się na kompie program, który wysyła do serwera bieżący adres IP, a serwer w
czasie rzeczywistym przypisuje ten adres IP do domeny. Potem jeszcze na routerze
trzeba coś skonfigurować, żeby router wiedział do którego kompa z sieci lokalnej przekazywać
przychodzące pakiety... Znowu coś do przebrnięcia, ale tym sposobem byłby komputer w
domu ze stałą domeną i z możliwością instalowania serwerów. Alternatywą jest wykupienie
gdzieś jakiegoś serwera dedykowanego, ale z tego co pamiętam, jest to koszt powyżej
150zł miesięcznie i za każde dodatkowe urządzenie (np. N-ty dysk) trzeba dopłacać. Jak się
kupi laptopa, to po roku się zwróci.
Na takim domowym serwerku będzie trzeba postawić Linuxa, MySqla, Apache, Pythona, trochę
bibliotek, no i BOINC - chyba taki sobie wyznaczę następny etap.
Hmmm... a może polecicie mi jakiś zestaw do powyższego zastosowania? W sumie to wystarczy płyta,
procesor, pamięć, dysk USB. Na dysku bym zainstalował Linuxa, potem bym wszystko skonfigurował
przez jakiś rdesktop - pewnie wyszłoby taniej niż cały laptop.
Pozdrawiam
no-ip.com :)
Natomiast serwer BOINC może Ci pomóc utrzymać Fundacja - do tego (m.in.) jest powołana :)
Co do atomizacji, to rozumiem ją jako jak najmocniejsze sprowadzenie informacji do najmniej mozliwej wartości, np. tabele klient-towar-rachunek:
Tabela klienta:
IDklienta
Imie
Nazwisko
Adres
itd (adres w wielu polach, dalsze dane, itd)
Tabela Faktury:
IDfaktury
Nrfaktury
IDklienta
IDtowaru
Tabela Towary:
IDTowaru
Nazwa
Ilosc
W ten sposób już masz trzy tabele (oczywiście bardzo je uprościłem), które pozwalają na pewną atomizację, ale gdy klient może mieć kilka adresów (np. filie) to już potrzebujesz nowej tabeli z adresami, dodaj do tego kwestie adresów wysyłkowych, kontakty z klientem (np. lista wiadomości), itd szybko przekraczasz założone 10 tabel - taka atomizacja wymusza/powoduje rozbicie danych na jak najmniejsze części co daje potem wygodę i elastyczność w ich wykorzystaniu. W dodatku ja mówię o znacznie więcej niż 300 roboczogodzinach, takie systemy rozwijają się latami :)
Jako przykład napisze tylko, że dobry system firmowy gromadzi i obrabia dane nie tylko o towarach, ale także pojazdy i maszyny (a to bardzo różne "sprawy" z punktu widzenia programisty), zarządzanie załogą, CRM, zakupy, itd - sama lista zadań jest większa niż 10 pozycji ( a przecież na każdą z nich przeznaczysz więcej niż jedną tabelę).
Cytat: krzyszp w 11 Czerwiec 2013, 16:38
no-ip.com :)
Dzięki za przypomnienie :)
Cytat: krzyszp w 11 Czerwiec 2013, 16:38
Natomiast serwer BOINC może Ci pomóc utrzymać Fundacja - do tego (m.in.) jest powołana :)
Na czym ta pomoc polega i co trzeba zrobić żeby ją uzyskać? Właściwie to na dziś
planowałem (jednak) wykupienie jakiegoś serwera wirtualnego, a następnie chciałem
na nim wystawić na świat jakąś pustą instalację.
Cytat: krzyszp w 11 Czerwiec 2013, 16:38
Co do atomizacji, to rozumiem ją jako jak najmocniejsze sprowadzenie informacji do najmniej mozliwej wartości, np. tabele klient-towar-rachunek:
To mówimy o takiej samej postaci :)
Cytat: krzyszp w 11 Czerwiec 2013, 16:38
W ten sposób już masz trzy tabele (oczywiście bardzo je uprościłem), które pozwalają na pewną atomizację, ale gdy klient może mieć kilka adresów (np. filie) to już potrzebujesz nowej tabeli z adresami, dodaj do tego kwestie adresów wysyłkowych, kontakty z klientem (np. lista wiadomości), itd szybko przekraczasz założone 10 tabel - taka atomizacja wymusza/powoduje rozbicie danych na jak najmniejsze części co daje potem wygodę i elastyczność w ich wykorzystaniu. W dodatku ja mówię o znacznie więcej niż 300 roboczogodzinach, takie systemy rozwijają się latami :)
Jako przykład napisze tylko, że dobry system firmowy gromadzi i obrabia dane nie tylko o towarach, ale także pojazdy i maszyny (a to bardzo różne "sprawy" z punktu widzenia programisty), zarządzanie załogą, CRM, zakupy, itd - sama lista zadań jest większa niż 10 pozycji ( a przecież na każdą z nich przeznaczysz więcej niż jedną tabelę).
W systemach zintegrowanych jest jak mówisz, ilość tabel szybko się rozrasta. Ja zwykle
pracowałem przy mniejszych projektach.
Pozdrawiam
Nie mogę się wypowiadać w imieniu Fundacji, ale mam dość dobre pojęcie co i jak robi, więc wnioskując z tego, że obecnie utrzymuje serwer Radioactive@Home oraz OProject myślę, że mogła by także pomóc w utrzymaniu Twojego serwera projektu (masz już nazwę?).
Najlepiej zwróć się bezpośrednio do którejś z osób z zarządu (wszystkie są obecne na forum: Cyfron, Tobas, Goofyx). Możesz też użyć formularza kontaktowego/danych ze strony Fundacji: http://boincpolska.org/
Cytat: krzyszp w 13 Czerwiec 2013, 09:53
Nie mogę się wypowiadać w imieniu Fundacji, ale mam dość dobre pojęcie co i jak robi, więc wnioskując z tego, że obecnie utrzymuje serwer Radioactive@Home oraz OProject myślę, że mogła by także pomóc w utrzymaniu Twojego serwera projektu (masz już nazwę?).
Najlepiej zwróć się bezpośrednio do którejś z osób z zarządu (wszystkie są obecne na forum: Cyfron, Tobas, Goofyx). Możesz też użyć formularza kontaktowego/danych ze strony Fundacji: http://boincpolska.org/
W takim razie za jakiś czas zwrócę się do kogoś o pomoc w tej kwestii.
Na razie będę miał serwer wirtualny za 20zł / miesiąc + domena 50zł / na rok - to
w sumie są grosze.
Kupiłem specjalny dysk na work-units do głębokości 16 ruchów. Roboczy plik
będzie miał rozmiar 200GB, więc na 17 ruchów miałby rozmiar 5TB - ale do
takiej głębokości raczej nie dojdziemy. Zastanawiam się czy takie narzędzia
jak sort i uniq z powłoki linuxa radzą sobie z takimi dużymi plikami. Jak nie,
to będę musiał użyć sqlite - to podobno najszybsza baza danych.
Nad nazwą projektu i domeny jeszcze myślę... może po prostu perft, albo
perft-test. Może jedn domena na kilka projektów - docelowo chcę
uruchomić zupełnie inny i bardziej ambitny projekt niż zliczanie węzłów.
Szkoda że computer-chess.com jest zajęta :/
Pozdrawiam
Cytat: mariotti w 13 Czerwiec 2013, 13:47Jak nie, to będę musiał użyć sqlite - to podobno najszybsza baza danych.
Chyba najszybsza do użycia, bo najprostsza, ale przetwarzanie czegokolwiek na tym może być problematyczne. A uniq i sort powinny sobie poradzić o ile jesteś w stanie zapewnić wystarczająco dużo pamięci :P
1. Szybki VPS to IMHO "minimalne minimum" aby serwer BOINC na tym chodził...
2. BOINC posługuje sié MySQL'em i aby nie komplikować spraw zatrzymałbym sié na nim... Nie wiem jak sqlite sié zachowa z taká ilościá danych (natomiast MySQL wiem, pracuje dobrze z bazá ~400GB).
Jeśli VPS, a nie dedyk, to polecam Ultimahost - majá tam fajne VPS'y oparte o dyski SSD za 69pln miesiécznie (mam, korzystam, działa bardzo sprawnie konwertujác ebooki i liczác WCG).
Cytat: Karlik w 13 Czerwiec 2013, 14:21
Cytat: mariotti w 13 Czerwiec 2013, 13:47Jak nie, to będę musiał użyć sqlite - to podobno najszybsza baza danych.
Chyba najszybsza do użycia, bo najprostsza, ale przetwarzanie czegokolwiek na tym może być problematyczne.
Dlaczego przetwarzanie czegokolwiek na sqlite jest problematyczne?
Cytat: Karlik w 13 Czerwiec 2013, 14:21
A uniq i sort powinny sobie poradzić o ile jesteś w stanie zapewnić wystarczająco dużo pamięci :P
Widzę że sort ma w opcjach katalog tymczasowy. Nie wiem, ale wnioskuję z tego, że sort umie
pracować także gdy pamięci jest mało.
Tak czy inaczej... nie umiem sobie poradzić przy użyciu samych poleceń sort i
uniq, więc sięgam po sqlita :D
Pozdrawiam
Cytat: mariotti w 13 Czerwiec 2013, 14:29
Tak czy inaczej... nie umiem sobie poradzić przy użyciu samych poleceń sort i
uniq, więc sięgam po sqlita :D
Eee, po MySQL? ;)
Czy ja nie zrozumiałem? ;)
Cytat: krzyszp w 13 Czerwiec 2013, 14:28
1. Szybki VPS to IMHO "minimalne minimum" aby serwer BOINC na tym chodził...
Na początek musimy się zadowolić rozwiązaniem najtańszym. Wydaje mi się, że
do testów wystarczy każdy kiepski wirtual. Na takim podrzędnym wirtualu zrobimy:
1) instalację i konfigurację serwera BOINC
2) testy poprawności na głębokości 12-13 ruchów
3) testy poprawności na kluczach różnej długości
4) optymalizację kodu
Jeśli projekt szczęśliwie dotrwa do ostatniego punktu, to wtedy pomyślimy nad
lepszym/droższym hostingiem.
Cytat: krzyszp w 13 Czerwiec 2013, 14:28
2. BOINC posługuje sié MySQL'em i aby nie komplikować spraw zatrzymałbym sié na nim...
Nie wiem jak sqlite sié zachowa z taká ilościá danych (natomiast MySQL wiem, pracuje
dobrze z bazá ~400GB).
SQLIte to będzie tylko pośrednie narzędzie do wygenerowania WU. Gdy WU będą gotowe,
to (o ile rozumiem jak działa serwer BOINC) doda się je do specjalnych katalogów, a do bazy
mysql trafiają tylko bieżące WU.
Cytat: krzyszp w 13 Czerwiec 2013, 14:28
Jeśli VPS, a nie dedyk, to polecam Ultimahost - majá tam fajne VPS'y oparte o dyski SSD za 69pln miesiécznie (mam, korzystam, działa bardzo sprawnie konwertujác ebooki i liczác WCG).
Jeśli projekt ruszy pełną gębą, to pomyślimy nad jakimś dedykiem z dobrym RAIDem :D
Pozdrawiam
Cytat: krzyszp w 13 Czerwiec 2013, 14:44
Cytat: mariotti w 13 Czerwiec 2013, 14:29
Tak czy inaczej... nie umiem sobie poradzić przy użyciu samych poleceń sort i
uniq, więc sięgam po sqlita :D
Eee, po MySQL? ;)
Czy ja nie zrozumiałem? ;)
SQLIte prawdopodobnie jest najszybszą bazą, bo oferuje najmniejszą funkcjonalność, więc
po SQLita. Napiszę programik narzędziowy do wygenerowania WU. Gdy będą gotowe, to
doda się do serwera BOINC tak jak BOINC tego wymaga. A jeśli dobrze zdążyłem się
zorientować, to BOINC wymaga aby WU leżały w specjalnych katalogach, do bazy
trafiają WU chyba tylko na czas przetwarzania - gdy są bieżącymi WU. Ale mogę się
mylić :)
Pozdrawiam
Jakby ktoś chciał spojrzeć w kod, to na dole załączam źródło programu
do generowania (a właściwie do grupowania i optymalizowania) work-units.
Program grupuje w jednym pliku tekstowym chunk zadań. Jedno
zadanie (zadanie to w zasadzie to samo co układ do przeszukania)
mieści się w jednym wierszu. Wszystkie zadania są do programu
podawane na standardowe wejście. Zadania mogą wiele razy się
powtarzać, więc program usuwa powtórzenia, a na końcu każdego
wiersza dopisuje ilość powtórzeń. Dodatkowo program do każdego pliku
dopisuje depth na jaką będą przeszukiwane zadania-układy. Bardzo
ważne jest, aby zadania były pogrupowane zgodnie z kolejnością w jakiej
zostały podane do programu na standardowe wejście - więc program
zachowuje kolejność.
Program w zasadzie tylko pośredniczy pomiędzy źródłem zadań a bazą
SQLite. Całą brudną robotę robi baza SQLite.
Program właściwie może pracować na dowolnych danych, byle jedno
zadanie mieściło się w jednym wierszu - więc może komuś jeszcze się
przyda takie narzędzie. Wystarczy program skompilować, przekierować
do niego dowolny plik z wierszami, wpisać chunk i wiersze zostaną
pogrupowane w plikach. Parametr depth pewnie nikomu się nie przyda, ale
można łatwo usunąć ze źródła.
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QVariant>
#include <QDir>
#include <QDebug>
#include <QFile>
#include <cstdlib>
#include <iostream>
void startTransaction( QSqlDatabase &db ) {
QString q = QString("BEGIN");
QSqlQuery query( db );
if( !query.exec( q ) ) qCritical() << query.lastError().text();
}
void commitTransaction( QSqlDatabase &db ) {
QString q = QString("COMMIT");
QSqlQuery query( db );
if( !query.exec( q ) ) qCritical() << query.lastError().text();
}
QSqlDatabase connectDB( const QString &db_path ) {
if( QFile::exists(db_path) )
QFile(db_path).remove();
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName( db_path );
if( ! db.open() )
qCritical() << "Cant open connection to database";
return db;
}
void createDB( QSqlDatabase &db ) {
QSqlQuery query( db );
{
QString q =
"CREATE TABLE Fens ("
"id INTEGER NOT NULL PRIMARY KEY ASC AUTOINCREMENT, " // klucz główny
"fen VARCHAR(70) NOT NULL, " // układ
"repeat INTEGER NOT NULL " // powtórzenia
")";
if( ! query.exec( q ) )
qCritical() << q.toAscii().constData() << query.lastError().text().toAscii().constData();
}
{
QString q = "CREATE UNIQUE INDEX IdxFens ON Fens(fen)";
if( ! query.exec( q ) )
qCritical() << q.toAscii().constData() << query.lastError().text().toAscii().constData() ;
}
}
//void incOrInsert( QSqlDatabase &db , const char fen[] ) {
// QSqlQuery query( db );
// QString q = QString("SELECT count(*) as cnt FROM Fens WHERE fen='%1'").arg(fen);
// if( ! query.exec( q ) ) Q_ASSERT_X( false , q.toAscii().constData() , query.lastError().text().toAscii().constData() );
// if( ! query.next() ) Q_ASSERT_X( false , q.toAscii().constData() , query.lastError().text().toAscii().constData() );
// if( query.value(0).toLongLong() > 0 )
// q = QString("UPDATE Fens SET count=count+1 WHERE fen='%1'").arg(fen);
// else
// q = QString("INSERT INTO Fens (fen,repeat) VALUES ('%1',1)").arg(fen);
// std::cout<<q.toAscii().constData()<<std::endl;
// if( ! query.exec( q ) ) Q_ASSERT_X( false , q.toAscii().constData() , query.lastError().text().toAscii().constData() );
//}
void incOrInsert( QSqlDatabase &db , const char fen[] ) {
QSqlQuery query( db );
QString q = QString("SELECT * FROM Fens WHERE fen='%1'").arg(fen);
if( ! query.exec( q ) ) qCritical() << q.toAscii().constData() << query.lastError().text().toAscii().constData() ;
if( query.next() )
q = QString("UPDATE Fens SET repeat=repeat+1 WHERE fen='%1'").arg(fen);
else
q = QString("INSERT INTO Fens (fen,repeat) VALUES ('%1',1)").arg(fen);
// if( ++nr % 1000 == 0 )
// std::cout<<nr<<" "<<q.toAscii().constData()<<std::endl;
if( ! query.exec( q ) ) qCritical() << q.toAscii().constData() << query.lastError().text().toAscii().constData() ;
}
long long numberUnique( QSqlDatabase &db ) {
QSqlQuery query( db );
QString q = QString("SELECT count(*) AS cnt FROM Fens");
if( ! query.exec( q ) ) qCritical() << q.toAscii().constData() << query.lastError().text().toAscii().constData() ;
if( ! query.next() ) qCritical() << q.toAscii().constData() << query.lastError().text().toAscii().constData() ;
const long long uniq = query.value(0).toLongLong();
std::cout<<"number of unique: " << uniq << std::endl;
return uniq;
}
void allSum( QSqlDatabase &db ) {
QSqlQuery query( db );
QString q = QString("SELECT sum(repeat) AS cnt FROM Fens");
if( ! query.exec( q ) ) qCritical() << q.toAscii().constData() << query.lastError().text().toAscii().constData() ;
if( ! query.next() ) qCritical() << q.toAscii().constData() << query.lastError().text().toAscii().constData() ;
std::cout<<"all sum: " << query.value(0).toLongLong() << std::endl;
}
void maxRepeat( QSqlDatabase &db ) {
QSqlQuery query( db );
QString q = QString("SELECT fen, repeat FROM Fens WHERE repeat = (SELECT max(repeat) FROM Fens)");
if( ! query.exec( q ) ) qCritical() << q.toAscii().constData() << query.lastError().text().toAscii().constData() ;
std::cout<<"max repeated:"<<std::endl;
for( int i=1 ; query.next() ; i++ )
std::cout<<i<<". "<<query.value(0).toString().toAscii().constData()<<" rep:"<<query.value(1).toInt()<< std::endl;
std::cout<<"------------------"<<std::endl;
}
void saveWorkUnit( QSqlDatabase &db , const char out_dir[] , const long long start , const long long end , const int depth ) {
QSqlQuery query( db );
QString q = QString("SELECT fen, repeat FROM Fens WHERE id>=%1 AND id<%2").arg(start).arg(end);
if( ! query.exec( q ) ) qCritical() << q.toAscii().constData() << query.lastError().text().toAscii().constData() ;
QString content = QString("%1\n").arg(depth);
while( query.next() )
content += query.value(0).toString() + ";" + query.value(1).toString() + "\n";
const QString f_name = QString("%1/wu_%2_%3.txt").arg(out_dir).arg(start,10,10,QChar('0')).arg(end,10,10,QChar('0'));
QFile file( f_name );
if( ! file.open(QFile::WriteOnly|QFile::Truncate) )
qCritical() << f_name.toAscii().constData() ;
file.write( content.toAscii().constData() );
file.close();
}
void panic(QtMsgType type, const char *msg) {
abort();
}
int main(int argc, char *argv[]) {
qInstallMsgHandler(panic);
if( argc != 5 ) {
std::cout<<"using:"<<std::endl;
std::cout<<"wu_test_perft db_path dir depth chunk"<<std::endl;
qCritical();
}
if( ! QDir().exists(argv[2]) ) {
if( ! QDir().mkpath(argv[2]) )
qCritical() << "cant create dir: " << argv[2];
}
int depth;
{
bool ok;
depth = QString(argv[3]).toInt(&ok);
if( !ok || depth < 1 )
qCritical() << "invalid depth";
}
int chunk;
{
bool ok;
chunk = QString(argv[4]).toInt(&ok);
if( !ok || chunk < 1 )
qCritical() << "invalid chunk";
}
QSqlDatabase db = connectDB( argv[1] );
createDB( db );
startTransaction(db);
char fen[1024];
for( long long i=1 ; ! std::cin.getline( fen , 1024 ).fail() ; i++ ) {
int len = strlen(fen)-1;
while( len>=0 && ( fen[len] == ' ' || fen[len] == '\t' || fen[len] == '\n' || fen[len] == '\r' ) )
fen[len--] = 0;
incOrInsert( db , fen );
std::cout<<"\rcreating "<<i;
}
std::cout<<std::endl;
const long long uniq = numberUnique(db);
allSum(db);
maxRepeat(db);
commitTransaction(db);
for( long long i=1 ; i<=uniq ; i+=chunk ) {
const long long start = i;
const long long end = qMin( start + chunk , uniq );
saveWorkUnit( db , argv[2] , start , end , depth );
std::cout<<"\rsaving "<<end;
}
std::cout<<std::endl;
db.close();
// QFile(argv[1]).remove(); // drop db sqlite
return 0;
}
Pozdrawiam
P.S.
Serwer wirtualny wykupiłem, domenę wykupiłem, więc niedługo będzie coś online :)
Proponuję dla każdego kto mnie wspierał w tym projekcie, jakieś strony-wizytówki w
tej samej domenie co projekt - oczywiście jeśli uda się projekt postawić na nogach :)
Oszacowałem że work-unity będą się generowały przez około 75 dni.
Taki okres czasu to sporo, ale odrzuciłby wszystkie powtarzające się
zadania na głębokości 8 ruchów. Łączny transfer wszystkich zadań to
około 2-3GB - czyli w sam raz.
Można też wygenerować work-unity na głębokość 7 ruchów, to zajęłoby
tylko 2.5 doby. Niestety takie podejście nie odrzuci tak dużo układów
jak poprzednie i nie wykorzysta łącz internetowych które dziś są
dość szybkie, bo łączny transfer byłby tylko 0.3GB.
Zastanawiam się czy warto napisać algorytm generowania work-unitów
ręcznie, bez pośrednictwa SQLita. Ciekawe jak szybko by to działało
bez bazy danych. Jakby dało się przyspieszyć z 3 razy, to generowanie
zadań da wersji 8-ruchowej zajęłoby tylko 25 dni. Niestety dodatkowy
nakład pracy i czasu na takie obliczenia jeszcze bardziej opóźni premierę
projektu.
Więc chyba pozostanę przy wersji 7-ruchowej. Może na 17go będą gotowe
work-unity, może do tej pory będę wiedział jak się je dodaje do serwera :)
Pozdrawiam
W trakcie generowania work-units wyczerpały się bufory ram.
Po wyczerpaniu oszacowanie czasu wzrosło 3 krotnie :/ Musiałem
przerwać i przenieść generator na osobny komputer. Tak więc
czekamy na work-unity, a w międzyczasie spróbuję zainstalować
BOINCa na serwerze wirtualnym.
Pozdrawiam
Podaj jakiś adres, żeby można było śledzić postępy :)
Cytat: krzyszp w 15 Czerwiec 2013, 14:40
Podaj jakiś adres, żeby można było śledzić postępy :)
Na chwilę obecną nic nie jest zrobione, więc nic nie można zobaczyć ani
śledzić. Wykupiony jest tylko serwer i domena. Domena
http://computer-chess.com była zajęta, to wykupiłem http://computer
s-chess.com .
W wolnej chwili podepnę domenę, zainstaluję apache, mysqla i boinca. Myślę
też, żeby na wordpresie uruchomić jakąś witrynę projektu. To wszystko wymaga
czasu, którego mam diabelnie mało, a teraz jeszcze się okazało, że generowanie
work-unitów (a właściwie to optymalizacja work-unitów ) będzie trwała z tydzień.
Niemniej mam nadzieję że w przeciągu kliku dni pojawi się jakaś aplikacja
szkieletowa pod domeną: http://computers-chess.com.
Pozdrawiam
P.S.
A może doradzicie jakiś algorytm do optymalizacji WU?
Treść zadania:
Program dostaje na standardowe wejście ogromną ilość wierszy. Są trzy
wersje zadania, różniące się ilością wierszy: 119060324, 3195901860, 84998978956.
Unikalnych wierszy jest odpowiednio:9417681, 96400068, 988187354. Jeden
wiersz ma rozmiar około 60-70bajtów. Unikalne wiersze trzeba zapisać na
dysku w takiej kolejności w jakiej przychodzą na standardowe wejście. Dodatkowo za
każdym wierszem musi być zapisana ilość jego wystąpień. Jeśli źródło wierszy
się wyczerpie, to nie ma przeszkód aby wszystkie wiersze dostać na standardowe
wejście jeszcze raz w tej samej kolejności. Natomiast nie można przeglądać
wierszy od tyłu i nie można poprosić o wiersz zadanym numerze - no chyba że
ktoś ma 8TB wolnego miejsca na dysku i sobie najpierw wszystkie wiersze zapisze :D
W skrócie: trzeba zapisać unikalne wiersze w takiej kolejności jak przychodzą
do programu, a z każdym wierszem trzeba jeszcze zapisać ilość powtórzeń.
Na bazie SQLite to zadanie w wersji drugiej będzie się wykonywało prawdopodobnie
cały tydzień. Jakby ktoś chciał rzucić okiem na ostatnią wersję tego programiku i
może coś doradzić, to załączam kod:
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QVariant>
#include <QDir>
#include <QDebug>
#include <QDateTime>
#include <QFile>
#include <cstdlib>
#include <iostream>
#include <iomanip>
void startTransaction( QSqlDatabase &db ) {
QString q = QString("BEGIN");
QSqlQuery query( db );
if( !query.exec( q ) ) qCritical() << query.lastError().text();
}
void commitTransaction( QSqlDatabase &db ) {
QString q = QString("COMMIT");
QSqlQuery query( db );
if( !query.exec( q ) ) qCritical() << query.lastError().text();
}
QSqlDatabase connectDB( const QString &db_path ) {
if( QFile::exists(db_path) )
QFile(db_path).remove();
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName( db_path );
if( ! db.open() )
qCritical() << "Cant open connection to database";
return db;
}
void createDB( QSqlDatabase &db ) {
QSqlQuery query( db );
{
QString q =
"CREATE TABLE Fens ("
"id INTEGER NOT NULL PRIMARY KEY ASC AUTOINCREMENT, " // klucz główny
"fen VARCHAR(70) NOT NULL, " // układ
"repeat INTEGER NOT NULL " // powtórzenia
")";
if( ! query.exec( q ) )
qCritical() << q.toAscii().constData() << query.lastError().text().toAscii().constData();
}
{
QString q = "CREATE UNIQUE INDEX IdxFens ON Fens(fen)";
if( ! query.exec( q ) )
qCritical() << q.toAscii().constData() << query.lastError().text().toAscii().constData() ;
}
{
QString q = "PRAGMA synchronous=OFF";
if( ! query.exec( q ) )
qCritical() << q.toAscii().constData() << query.lastError().text().toAscii().constData() ;
}
{
QString q = "PRAGMA cache_size=3000000";
if( ! query.exec( q ) )
qCritical() << q.toAscii().constData() << query.lastError().text().toAscii().constData() ;
}
{
QString q = "PRAGMA temp_store=2";
if( ! query.exec( q ) )
qCritical() << q.toAscii().constData() << query.lastError().text().toAscii().constData() ;
}
{
QString q = "PRAGMA journal_mode=OFF";
if( ! query.exec( q ) )
qCritical() << q.toAscii().constData() << query.lastError().text().toAscii().constData() ;
}
}
void incOrInsert( QSqlDatabase &db , const char fen[] ) {
QSqlQuery query( db );
QString q = QString("SELECT COUNT(*) FROM Fens WHERE fen='%1'").arg(fen);
if( ! query.exec( q ) ) qCritical() << q.toAscii().constData() << query.lastError().text().toAscii().constData() ;
if( ! query.next() ) qCritical() << q.toAscii().constData() << query.lastError().text().toAscii().constData() ;
if( query.value(0).toInt() > 0 )
q = QString("UPDATE Fens SET repeat=repeat+1 WHERE fen='%1'").arg(fen);
else
q = QString("INSERT INTO Fens (fen,repeat) VALUES ('%1',1)").arg(fen);
if( ! query.exec( q ) ) qCritical() << q.toAscii().constData() << query.lastError().text().toAscii().constData() ;
}
long long numberUnique( QSqlDatabase &db ) {
QSqlQuery query( db );
QString q = QString("SELECT count(*) AS cnt FROM Fens");
if( ! query.exec( q ) ) qCritical() << q.toAscii().constData() << query.lastError().text().toAscii().constData() ;
if( ! query.next() ) qCritical() << q.toAscii().constData() << query.lastError().text().toAscii().constData() ;
const long long uniq = query.value(0).toLongLong();
std::cout<<"number of unique: " << uniq << std::endl;
return uniq;
}
void allSum( QSqlDatabase &db ) {
QSqlQuery query( db );
QString q = QString("SELECT sum(repeat) AS cnt FROM Fens");
if( ! query.exec( q ) ) qCritical() << q.toAscii().constData() << query.lastError().text().toAscii().constData() ;
if( ! query.next() ) qCritical() << q.toAscii().constData() << query.lastError().text().toAscii().constData() ;
std::cout<<"all sum: " << query.value(0).toLongLong() << std::endl;
}
void maxRepeat( QSqlDatabase &db ) {
QSqlQuery query( db );
QString q = QString("SELECT fen, repeat FROM Fens WHERE repeat = (SELECT max(repeat) FROM Fens)");
if( ! query.exec( q ) ) qCritical() << q.toAscii().constData() << query.lastError().text().toAscii().constData() ;
std::cout<<"max repeated:"<<std::endl;
for( int i=1 ; query.next() ; i++ )
std::cout<<i<<". "<<query.value(0).toString().toAscii().constData()<<" rep:"<<query.value(1).toInt()<< std::endl;
std::cout<<"------------------"<<std::endl;
}
void panic(QtMsgType type, const char *msg) {
(void)type;
(void)msg;
abort();
}
int main(int argc, char *argv[]) {
qInstallMsgHandler(panic);
if( argc != 2 ) {
std::cout<<"using:"<<std::endl;
std::cout<<"wu_test_perft db_path"<<std::endl;
qCritical();
}
QSqlDatabase db = connectDB( argv[1] );
createDB( db );
startTransaction(db);
QDateTime bench = QDateTime::currentDateTime();
char fen[1024];
for( long long i=1 ; ! std::cin.getline( fen , 1024 ).fail() ; i++ ) {
int len = strlen(fen)-1;
while( len>=0 && ( fen[len] == ' ' || fen[len] == '\t' || fen[len] == '\n' || fen[len] == '\r' ) )
fen[len--] = 0;
incOrInsert( db , fen );
if( i % 10000 == 0 ) {
// const double percent = i * 100.0 / 4865609.0; // depth=5
// const double percent = i * 100.0 / 119060324.0; // depth=6
const double percent = i * 100.0 / 3195901860.0; // depth=7
// const double percent = i * 100.0 / 84998978956.0; // depth=8
const QDateTime curr = QDateTime::currentDateTime();
const double elapsed = curr.toTime_t() - bench.toTime_t();
std::cout<<"\rtotal: "<<i<<";";
std::cout<<" percent: "<<std::setprecision(2)<<std::fixed<<percent<<"%;";
std::cout<<" all time: "<<std::setprecision(2)<<std::fixed<< ( elapsed/percent * 100.0 )<<"s;";
std::cout<<" time left: "<<std::setprecision(2)<<std::fixed<< ( elapsed/percent * (100.0 - percent) )<<"s";
}
}
std::cout<<std::endl;
numberUnique(db);
allSum(db);
maxRepeat(db);
commitTransaction(db);
db.close();
return 0;
}
1. W jakiej postaci wiersze "przychodzą"? Są generowane, czy też to np. plik?
2. Jeśli są w pliku, to dlaczego zadania policzenia nie zrzucisz na bazę?
Jeżeli już wszystkie liczby będziesz miał w db, to robisz SELECT COUNT i SELECT DISTINCT i masz odpowiedzi na swoje pytania...
Sorki, jeżeli coś źle zrozumiałem :)
Ps. Serwer BOINC postawi swoją stronę, więc chyba nie ma sensu stawiać dodatkowej. Na radioaktywnym zbudowaliśmy taką dodatkową stronę główną i chyba to się okazało bez sensu...
No dokładnie. To sensu nie ma. Dobry opis i logo można wrzucić na stronę ./boinc Dodatkowa to dodatkowy problem.
8TB... a ile po kompresji gzipem, tarem czy innym rarem? Można przesyłać zadania skopmpresowane, rozkompresować u klienta, policzyć, skompresować wynik i odesłać na serwer.
Cytat: krzyszp w 15 Czerwiec 2013, 20:13
1. W jakiej postaci wiersze "przychodzą"? Są generowane, czy też to np. plik?
Są generowane, więc można je także zapisać do pliku. Jednak taki plik
zajmuje sporo miejsca. Nie wiem czy lepiej zapisywać w pliku, czy
wiele razy wygenerować od nowa :)
Cytat: krzyszp w 15 Czerwiec 2013, 20:13
2. Jeśli są w pliku, to dlaczego zadania policzenia nie zrzucisz na bazę?
Właśnie przerzuciłem na bazę, dokładnie na bazę SQLite. Tamten program, którego
źródło załączyłem powyżej, sam nie robi nic, wszystko jest przerzucone na bazę.
Cytat: krzyszp w 15 Czerwiec 2013, 20:13
Jeżeli już wszystkie liczby będziesz miał w db, to robisz SELECT COUNT i SELECT DISTINCT i masz odpowiedzi na swoje pytania...
Jakby wszystkie dane były już w bazie, to w grę wchodzi mniej/więcej
takie zapytanie:
SELECT
DISTINCT ON (row),
row,
(select min(nr) from table as t2 where t2.row = t1.row) as min_nr,
(select count(*) from table as t3 where t3.row = t1.row) as cnt
FROM
table as t1
ORDER BY
min_nr;
Tabela ma tylko dwa pola:
nr - bigint
row - varchar(70)
Są trzy wersje tabeli, różniące się ilością rekordów:
1) 119.060.324
2) 3.195.901.860
3) 84.998.978.956
Nie wiem czy jakaś baza poradzi sobie w rozsądnym czasie z drugą wersją :)
Jeśli w ogóle nie uda się tego policzyć dla wersji trzeciej, to nic złego się nie
stanie. Ale wersję drugą, czyli 3mld rekordów, trzeba jakoś policzyć.
Cytat: krzyszp w 15 Czerwiec 2013, 20:13
Sorki, jeżeli coś źle zrozumiałem :)
To chyba ja mam tendencję do mętnego opisywania :) Gdy się coś napisze, to
wypada włożyć napisany tekst do szuflady, przetrzymać go tam chociaż przez
tydzień, a po tygodniu gruntownie go przeredagować. Ja piszę z doskoku, czasami
będąc bardzo zmęczony, czasami niedowidzący, więc miło że w ogóle macie
ochotę czytać moje wypociny :D
Cytat: krzyszp w 15 Czerwiec 2013, 20:13
Ps. Serwer BOINC postawi swoją stronę, więc chyba nie ma sensu stawiać dodatkowej. Na radioaktywnym zbudowaliśmy taką dodatkową stronę główną i chyba to się okazało bez sensu...
Hmmm, a to pomyślimy jeszcze jak to będzie ze stronami. Zauważyłem że BOINC instaluje dwie
witryny, jedną dla userów, drugą dla operatorów.
Generalnie projekty szachowe chciałbym rozwijać przez wiele lat w różnych kierunkach (jeśli tylko
czas i zdrówko pozwolą), więc jakaś główna strona powstanie, a na niej będą odnośniki do projektów
szczegółowych. Obecny projekt, o którym rozmawiamy od początku w tym wątku, czyli zliczanie
węzłów w drzewie gry, właśnie ma być jednym z kierunków. Może za rok będę gotowy
na jakiś bardziej ambitny projekt związany z szachami. Ambitnych zagadnień jest sporo, chociażby
tuning końcówek, tuning debiutów, no i to co mnie najbardziej kręci: szachy w pełni oparte na
technikach sztucznej inteligencji. Wszystkie te projekty nadają się w miarę dobrze na BOINC.
Ale w dłuższej perspektywie na stronie może także zamieszczę jakieś projekty zupełnie
nie związane z BOINC.
Cytat: Szopler w 15 Czerwiec 2013, 20:37
No dokładnie. To sensu nie ma. Dobry opis i logo można wrzucić na stronę ./boinc Dodatkowa to dodatkowy problem.
8TB... a ile po kompresji gzipem, tarem czy innym rarem? Można przesyłać zadania skopmpresowane, rozkompresować u klienta, policzyć, skompresować wynik i odesłać na serwer.
Są tak jakby dwa rodzaje kompresji :D
Pierwsza kompresja ma zliczyć powtórzenia. Niektóre zadania będą się powtarzały
wiele razy, np. to samo zadanie może powtórzyć się aż 500 razy. Nie ma sensu
wysyłać 500 razy tego samego zadania, wystarczy wysłać raz do policzenia i drugi raz
do weryfikacji.
Druga kompresja, to upakowanie zadań po około 10-300 sztuk do jednej paczki i
zastosowanie zipa.
Pierwsza kompresja (szacunkowo) zmniejszy rozmiar danych 80 razy. Druga
około 10 razy. Więc obie razem zmniejszą te 8TB 800 razy. Więc zostanie
około 5-10GB danych.
Ta cała męka z optymalizacją work-unitów jest w dwóch celach. Pierwszy cel
jest właśnie taki, aby z 8TB zrobiło się 5-10GB.
Drugi cel jest bardziej skomplikowany.... w skrócie przyspieszy obliczenia,
być może nawet dwukrotnie :D
Pozdrawiam
Mam bazę z 8,8mld rekordów, w 20-kilku tabelach, każdy rekord jest większy, niż Ty używasz. Cala baza ma w chwili obecnej ok 400GB (293,2GB dane i 103.3GB indeksy), całość chodzi... wolno ;) niemniej jakoś działa :)
Cytat: krzyszp w 15 Czerwiec 2013, 22:10
Mam bazę z 8,8mld rekordów, w 20-kilku tabelach, każdy rekord jest większy, niż Ty używasz. Cala baza ma w chwili obecnej ok 400GB (293,2GB dane i 103.3GB indeksy), całość chodzi... wolno ;) niemniej jakoś działa :)
Na pewno Twoja baza działa i to dobrze, ale w jednym zapytaniu
nie wyciągasz z bazy 96400068 albo 988187354 rekordów - w dodatku
posortowanych po wyniku innego podzapytania :)
Nie dowiemy się czy Twój pomysł jest dobry, jeśli nie sprawdzimy
go w praktyce. Naprawdę nie mam bladego pojęcia ile czasu
zajmie tamto zapytanie z kilku postów powyżej. Trzeba do tabeli
dodać 3mld rekordów i uruchomić.
Pozdrawiam
Mam jeszcze jedną prośbę. Polećcie mi jakiś serwer wirtualny.
Na początek do testów ważne jest tylko to, żeby był tani.
Jakiś kupiłem i nie mogę zrobić nic. Z poziomu panelu ani nie
mogę przeinstalować systemu, ani zresetować, a administrator
podgląda moje hasła i wysyła w niezaszyfrowanych e-mailach :D
Pozdrawiam
Już polecałem - polecę jeszcze raz ;)
ultimahost.pl
Co do bazy, to generalnie na niej leci głownie
select * from tabela where Time = xxx
oraz np.
select max(Time) from tabela... gdzie jest 378'432'617 rekordów w tabeli
Także też ma co robić :)
Cytat: krzyszp w 15 Czerwiec 2013, 23:21
Już polecałem - polecę jeszcze raz ;)
ultimahost.pl
Zamówiłem, jutro zapłacę. Nie przysłali mi hasła mailem - może
to naprawdę profesjonalne usługi ;-)
Cytat: krzyszp w 15 Czerwiec 2013, 23:21
Co do bazy, to generalnie na niej leci głownie
select * from tabela where Time = xxx
oraz np.
select max(Time) from tabela... gdzie jest 378'432'617 rekordów w tabeli
Także też ma co robić :)
Indeksy świetnie pełnią rolę w zapytaniach które zaprezentowałeś. U mnie indeksy
choć pomogą, to prawdopodobnie nie załatwią sprawy, bowiem tabela ma za
dużo danych i zapytanie wyciąga za dużo danych.
Pozdrawiam.
P.S.
Właśnie widzę że na drugim kompie programik do wygenerowania work-units wywalił po
kilkunastu godzinach pracy. Nie mam pojęcia jaka jest przyczyna... może SQLite
ma problemy na tamtym kompie, może jest wrażliwy na jakieś specyficzne parametry.
Programik jest mały, więc raczej błędów nie narobiłem... Kurde czuję że czeka
mnie ręczne wyrzeźbienie jakiegoś programu do optymalizacji WU :/ Wszystko
idzie źle, ale wierzę że w końcu się uda.
Zapomniałem dodać, że u tego samego usługodawcy jest wykupiony dedyk dla radioaktywnego i cóż... działa świetnie :)
Cytat: krzyszp w 16 Czerwiec 2013, 00:27
Zapomniałem dodać, że u tego samego usługodawcy jest wykupiony dedyk dla radioaktywnego i cóż... działa świetnie :)
Fajnie. Ale niestety i tak i tak trzeba poczekać. Nie wiem czemu na stacjonarnym kompie ten
programik do optymalizowana WU pada. Na laptopie działa, ale laptopa potrzebuję do pracy,
nie mogę tam zostawić włączonego generatora. Pewne będę musiał napisać jakiś
program bez pośrednictwa bazy.
Pozdrawiam
Cytat: mariotti w 16 Czerwiec 2013, 09:18
Fajnie. Ale niestety i tak i tak trzeba poczekać...
Zmniejszyłem rozmiar bufora RAM w SQLite i odpaliłem ten programik do
optymalizacji WU. Na zmniejszonym buforze mam oszacowanie czasu 670tys
sekund i rośnie. Jeśli się tym razem nie wywali, to za niecałe 10 dni będzie
materiał na WU. Jeśli się wywali znowu, to nie wiem... będzie trzeba opracować
jakiś specjalny algorytm do tego zadania.
Pozdrawiam
albo podeślij komuś z nas do odpalenia i podesłania Ci samej bazy :)
Cytat: krzyszp w 16 Czerwiec 2013, 17:09
albo podeślij komuś z nas do odpalenia i podesłania Ci samej bazy :)
W obecnej wersji ma to sens, jedynie w przypadku gdy ktoś dysponuje
bardzo szybkim dyskiem. Zwłaszcza bardzo ważne jest, aby losowy ( w losowych
miejscach dysku ) odczyt i zapis małych porcji danych był szybki. Takie wymagania
spełniają jedynie niektóre dyski SSD, albo macierze dyskowe z bardzo
dużym buforem RAM. Jak ktoś ma taki sprzęt, to możemy spróbować :D
Raczej będzie trzeba napisać dobry algorytm. Jeśli WU na serwerze mają być
policzone na głębokość ośmiu ruchów, to na jednym kompie na bazie SQLite będą
się generowały rok czasu :D
Osiem ruchów to byłby wypas, zwłaszcza jakbyśmy doszli do (łącznej)
głębokości 16 (lub więcej) ruchów. Jakby na serwerze leżały work-unity
policzone już na 8 ruchów, to klient dostawałby zadania do policzenia na
głębokość od 4-8 ruchów. Łącznie dawałoby to głębokość od 12 do 16
ruchów. Jakby ktoś chciał liczyć długo, to by brał dużą paczkę, jakby ktoś
miał mało czasu albo wolny komputer, to by brał małą paczkę.
Ponadto wraz z głębokością (z tą głębokością na której WU są przygotowane
na serwerze) rosną oszczędności. Przy głębokości:
6 ruchów oszczędność wynosi: 92,09%
7 ruchów: 96,98%
8 ruchów: 98,84%
dla ponad 8 nie mam danych :)
Więc chyba warto przeliczyć WU na te 8 ruchów, a tym czasem nie mogę
się uporać z głębokością 7 :) Ciekawe jest to, że dla głębokości 6 ruchów
można policzyć ( o ile dobrze pamiętam ) w kilkadziesiąt sekund, bo całość mieści
się w RAM :)
Baza bez kompresji dla 8 ruchów będzie miała rozmiar około 60GB, ale podejrzewam
że skompresuje się 15-krotnie. Więc transfer na jedno przeliczenie wyniósłby
4GB - więc akurat.
Trochę przeraża mnie ilość paczek. Jakby w paczce było 1000 zadań, to
ilość paczek wynosiłaby około 1mln. Jednak 1000 zadań dla zoptymalizowanego
programu to raczej mała ilość. Może da się upakować po 10tys zadań do jednej
paczki. W takim przypadku byłoby to 100tys paczek.
Wszystko ładnie, pięknie, ale pozostaje problem wyboru unikalnych
zadań z bagatela 85mld :)
Pozdrawiam
Na małym buforze program też się wywalił. Nie mam bladego
pojęcia jaka jest przyczyna. Program tylko wczytuje wiersze ze
standardowego wejścia, sprawdza czy wiersz jest unikalny, następnie
go dodaje do bazy lub lub zwiększa licznik powtórzeń - czyli
banał.
Nie wiem czy coś mam źle z konfiguracją SQLite, czy może jakaś
usterka w bashu... może coś z moim komputerem źle, może ja mam
jakiś błąd w kodzie, ale jaki mogę mieć błąd w tych paru linijkach kodu :/
Niestety muszę zawiesić prace na około tydzień, aż będę miał trochę w
wolnego czasu, żeby wklepać ręcznie cały algorytm do optymalizacji
work-units.
Spróbuj podesłać obecny program do paru chętnych, może wygeneruje próbki, przy okazji dowiesz się w ciągu tygodnia, czy masz problem z programem, czy z komputerem .
Cytat: AXm77 w 17 Czerwiec 2013, 13:57
Spróbuj podesłać obecny program do paru chętnych, może wygeneruje próbki, przy okazji dowiesz się w ciągu tygodnia, czy masz problem z programem, czy z komputerem .
Ok. Jestem strasznie zalatany, ale przygotuję wszystko wieczorem lub jutro rano.
Podejrzewam że będą problemy z bibliotekami. Program perft się nie zmienił, ale dodatkowy
program korzysta z biblioteki QT, ze sterownika do SQLita no i z samej
bazy SQLite. Nie wiem czy da się to wszystko wkompilować statycznie. Możliwe
że każdy chętny będzie musiał sobie zainstalować środowisko i skompilować
sam. Niemniej spróbować możemy. Właściwie to można już pobrać środowisko
QTCreator i skompilować ostatnie źródło które podwałem.
Z drugiej strony zastanawiam się czy jest sens uruchamiania tego programu na zwykłych komputerach,
bowiem on nawet w optymistycznym przypadku wygeneruję bazę tylko dla 7 ruchów. Bazy
8-ruchowej nie da rady nawet w kilka miesięcy. De facto baza 7-ruchowa nie jest taka zła, w
mniejszych (łącznych) głębokościach jest nawet lepsza, ale w dłuższej perspektywie 8-ruchowa da
większe możliwości. Jakby ktoś miał dostęp do super-szybkiej macierzy
dyskowej to wtedy byłby wielki sens, bo ja bym zaoszczędził dużo czasu na pisaniu
specjalistycznego programu, całą robotę za mnie by odwaliła baza i dobry sprzęt.
No ale przygotuję i zobaczymy jak to się zachowa. Skrypt ma opcje do wygenerowania bazy
dla dowolnej ilości ruchów, można uruchomić testy dla 4 i 5 ruchów - trwają one krótko.
Pozdrawiam i dzięki za zainteresowanie.
root@krzyszp-OptiPlex-330:/home/krzyszp/Szachy# gcc -o generuj szachy.c
szachy.c:1:24: fatal error: QSqlDatabase: No such file or directory
compilation terminated.
Możesz dołączyć resztę plików projektu?
Mogę próbować, ale po SSH...
Cytat: krzyszp w 17 Czerwiec 2013, 14:32
root@krzyszp-OptiPlex-330:/home/krzyszp/Szachy# gcc -o generuj szachy.c
szachy.c:1:24: fatal error: QSqlDatabase: No such file or directory
compilation terminated.
Możesz dołączyć resztę plików projektu?
Mogę próbować, ale po SSH...
Pisałem pół godziny szczegółową instrukcję, po czym otrzymałem wiadomość
że załącznik się nie wysłał, a mojej instrukcji już nie było :) Napiszę za jakiś
czas jeszcze raz, teraz nie mogę. Przepraszam.
---------------------------------------------------------------------------------------------------------
No więc jeszcze raz:
Najwygodniej zainstalować jakieś GUI na serwerze. Następnie logujemy się
np. przez vncviewer i instalujemy środowisko qtcretor. W środowisku zakładamy
nowy projekt typu konsola i wklejamy kod do pliku main.cpp. Srodowisko samo
zbuduje polecenia do kompilacji.
Jeśli nie można zainstalować qtcratora, to zapisujemy źródło jako plik main.cpp.
Następnie kompilujemy i linkujemy (dwoma poleceniami):
g++ -c -m64 -pipe -O2 -Wall -W -D_REENTRANT -DQT_WEBKIT -DQT_NO_DEBUG -DQT_SQL_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++-64 -I../wu_test_perft -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtSql -I/usr/include/qt4 -I. -o main.o ../wu_test_perft/main.cpp
g++ -m64 -Wl,-O1 -o wu_test_perft main.o -L/usr/lib/x86_64-linux-gnu -lQtSql -lQtCore -lpthread
Otrzymujemy w ten sposób program
wu_test_perft.
Uruchamiamy go komendą z nazwą bazy danych, np.:
./wu_test_perft db.sqlite
Program czeka na wiersze, trzeba je podać na standardowe wejście.
Wiersze nie mogą być dłuższe niż 70 bajtów. Kończymy podawanie
wierszy znakiem końca pliku Ctrl+D. Zrzut z mojego ekranu:
ls -l
-rw-rw-r-- 1 x x 7345 2013-06-15 13:07 main.cpp
-rwxrwxr-x 1 x x 2140238 2013-06-17 15:04 perft4
g++ -c -m64 -pipe -O2 -Wall -W -D_REENTRANT -DQT_WEBKIT -DQT_NO_DEBUG -DQT_SQL_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/qt4/mkspecs/linux-g++-64 -I../wu_test_perft -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtSql -I/usr/include/qt4 -I. -o main.o ../wu_test_perft/main.cpp
g++ -m64 -Wl,-O1 -o wu_test_perft main.o -L/usr/lib/x86_64-linux-gnu -lQtSql -lQtCore -lpthread
/wu_test_perft db.sqlite
aaa
bbb
ccc
aaa
aaa
ddd
ddd
[crtl+d]
number of unique: 4
all sum: 7
max repeated:
1. aaa rep:3
------------------
ls -l
razem 2244
-rw-r--r-- 1 x x 4096 2013-06-17 16:09 db.sqlite
-rw-rw-r-- 1 x x 7345 2013-06-15 13:07 main.cpp
-rw-rw-r-- 1 x x 59008 2013-06-17 16:09 main.o
-rwxrwxr-x 1 x x 2140238 2013-06-17 15:04 perft4
-rwxrwxr-x 1 x x 50557 2013-06-17 16:09 wu_test_perft
Jako źródła wierszy używamy programu perft4. Łączymy oba programy skryptem powłoki:
(
(
echo printLeafs 4
echo quit
) | ./perft4
) | ./wu_test_perft db.sqllite
U mnie wygląda to tak, widać że program z 197281 WU sporo odrzucił, zostało tylko:72078
number of unique: 72078
all sum: 197281
max repeated:
1. rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w qkQK - rep:16
------------------
Jeśli zadziała, to w powyższym skrypcie zwiększamy czwórkę na 7
echo printLeafs 7
Program w trakcie działania będzie wyświetlał statystyki i oszacowanie końcowego czasu.
W źródle programu można zmienić rozmiar cache w bazie SQLite:
QString q = "PRAGMA cache_size=xxxxxx";
Opis komendy jest na tej stronie:
http://www.sqlite.org/pragma.html#pragma_cache_size
Poprzednia instrukcja była bardziej szczegółowa, ale może ta też wystarczy :)
Pozdrawiam
Cytat: mariotti w 17 Czerwiec 2013, 15:30
Napiszę za jakiś czas jeszcze raz, teraz nie mogę. Przepraszam.
No problem ;)
Cytat: krzyszp w 17 Czerwiec 2013, 16:02
Cytat: mariotti w 17 Czerwiec 2013, 15:30
Napiszę za jakiś czas jeszcze raz, teraz nie mogę. Przepraszam.
No problem ;)
Można też work-units zrzucić do pliku testowego out.txt takim skryptem:
(
echo printLeafs 4
echo quit
) | ./perft4 > out.txt
Dla głębokości 7, trzeba wpisać:
echo printLeafs 7
Następnie można jakimiś innymi narzędziami zrealizować to samo zadanie :)
Pozdrawiam
rnbqkb1r/ppppp1pp/7n/5p2/8/7N/PPPPPPPP/RNBQKBR1 w qkQ -
rnbqkb1r/pppppp1p/6pn/8/8/7N/PPPPPPPP/RNBQKBR1 w qkQ -
rnbqkb1r/pppppp1p/7n/6p1/8/7N/PPPPPPPP/RNBQKBR1 w qkQ -
r1bqkb1r/pppppppp/n6n/8/8/7N/PPPPPPPP/RNBQKBR1 w qkQ -
r1bqkb1r/pppppppp/2n4n/8/8/7N/PPPPPPPP/RNBQKBR1 w qkQ -
rnbqkb1r/pppppppp/8/8/6n1/7N/PPPPPPPP/RNBQKBR1 w qkQ -
rnbqkbnr/pppppppp/8/8/8/7N/PPPPPPPP/RNBQKBR1 w qkQ -
rnbqkb1r/pppppppp/8/5n2/8/7N/PPPPPPPP/RNBQKBR1 w qkQ -
rnbqkbr1/pppppppp/7n/8/8/7N/PPPPPPPP/RNBQKBR1 w qQ -
?
Cytat: krzyszp w 17 Czerwiec 2013, 17:46
rnbqkb1r/ppppp1pp/7n/5p2/8/7N/PPPPPPPP/RNBQKBR1 w qkQ -
rnbqkb1r/pppppp1p/6pn/8/8/7N/PPPPPPPP/RNBQKBR1 w qkQ -
rnbqkb1r/pppppp1p/7n/6p1/8/7N/PPPPPPPP/RNBQKBR1 w qkQ -
r1bqkb1r/pppppppp/n6n/8/8/7N/PPPPPPPP/RNBQKBR1 w qkQ -
r1bqkb1r/pppppppp/2n4n/8/8/7N/PPPPPPPP/RNBQKBR1 w qkQ -
rnbqkb1r/pppppppp/8/8/6n1/7N/PPPPPPPP/RNBQKBR1 w qkQ -
rnbqkbnr/pppppppp/8/8/8/7N/PPPPPPPP/RNBQKBR1 w qkQ -
rnbqkb1r/pppppppp/8/5n2/8/7N/PPPPPPPP/RNBQKBR1 w qkQ -
rnbqkbr1/pppppppp/7n/8/8/7N/PPPPPPPP/RNBQKBR1 w qQ -
?
Wszystko się zgadza, to są dane wejściowe dla aplikacji liczącej :)
Pozdrawiam
P.S.
U mnie tak to wygląda:
cat go2.sh
(
echo printLeafs 7
echo quit
) | ./perft4 > 'all_rows.txt'
time ./go2.sh
real 120m19.033s (dwie godziny sam zapis, bez żadnego przetwarzania!)
user 41m47.965s
sys 76m9.274s
ls -l
-rw-rw-r-- 1 x x 195013386079 2013-06-17 18:32 all_rows.txt
head -n 20 all_rows.txt
rnbqkbnr/2pppppp/1p6/p7/PP6/8/2PPPPPP/RNBQKBNR b qkQK -
rnbqkbnr/2pppppp/1p6/p7/P7/1PP5/3PPPPP/RNBQKBNR b qkQK -
rnbqkbnr/2pppppp/1p6/p7/P1P5/1P6/3PPPPP/RNBQKBNR b qkQK -
rnbqkbnr/2pppppp/1p6/p7/P7/1P1P4/2P1PPPP/RNBQKBNR b qkQK -
rnbqkbnr/2pppppp/1p6/p7/P2P4/1P6/2P1PPPP/RNBQKBNR b qkQK -
rnbqkbnr/2pppppp/1p6/p7/P7/1P2P3/2PP1PPP/RNBQKBNR b qkQK -
rnbqkbnr/2pppppp/1p6/p7/P3P3/1P6/2PP1PPP/RNBQKBNR b qkQK -
rnbqkbnr/2pppppp/1p6/p7/P7/1P3P2/2PPP1PP/RNBQKBNR b qkQK -
rnbqkbnr/2pppppp/1p6/p7/P4P2/1P6/2PPP1PP/RNBQKBNR b qkQK -
rnbqkbnr/2pppppp/1p6/p7/P7/1P4P1/2PPPP1P/RNBQKBNR b qkQK -
rnbqkbnr/2pppppp/1p6/p7/P5P1/1P6/2PPPP1P/RNBQKBNR b qkQK -
rnbqkbnr/2pppppp/1p6/p7/P7/1P5P/2PPPPP1/RNBQKBNR b qkQK -
rnbqkbnr/2pppppp/1p6/p7/P6P/1P6/2PPPPP1/RNBQKBNR b qkQK -
rnbqkbnr/2pppppp/1p6/p7/P7/NP6/2PPPPPP/R1BQKBNR b qkQK -
rnbqkbnr/2pppppp/1p6/p7/P7/1PN5/2PPPPPP/R1BQKBNR b qkQK -
rnbqkbnr/2pppppp/1p6/p7/P7/1P3N2/2PPPPPP/RNBQKB1R b qkQK -
rnbqkbnr/2pppppp/1p6/p7/P7/1P5N/2PPPPPP/RNBQKB1R b qkQK -
rnbqkbnr/2pppppp/1p6/p7/P7/1P6/1BPPPPPP/RN1QKBNR b qkQK -
rnbqkbnr/2pppppp/1p6/p7/P7/BP6/2PPPPPP/RN1QKBNR b qkQK -
rnbqkbnr/2pppppp/1p6/p7/P7/1P6/R1PPPPPP/1NBQKBNR b qkK -
cat go3.sh
wc -l < all_rows.txt
./go3.sh
3195901860 (ilość wierszy perfekcyjna, tyle ile węzłów na głębokości 7 ruchów)
real 105m41.485s (niecałe 2h na samo zliczenie wierszy)
user 2m9.580s
sys 4m7.959s
Odpaliłem
Cytat: krzyszp w 17 Czerwiec 2013, 19:44
Odpaliłem
Dzięki.
P.S.
BOINC uzależnia, obiecałem sobie szlaban na kilka dni, a wciąż się tym zajmuję :D
Cytat: mariotti w 17 Czerwiec 2013, 19:46
BOINC uzależnia, obiecałem sobie szlaban na kilka dni, a wciąż się tym zajmuję :D
oj prawda :)
Ja na próbę włączyłem i już 12-13 lat siedzę w temacie ;)
Cytat: krzyszp w 17 Czerwiec 2013, 21:24
Cytat: mariotti w 17 Czerwiec 2013, 19:46
BOINC uzależnia, obiecałem sobie szlaban na kilka dni, a wciąż się tym zajmuję :D
oj prawda :)
Ja na próbę włączyłem i już 12-13 lat siedzę w temacie ;)
Wow!
Myślę podświadomie cały czas o tym algorytmie do optymalizacji WU.
Algorytm koncepcyjnie jest całkiem prosty, jednak w realizacji będzie
kilka pułapek, więc na szybko go nie zrobię ale za parę dni tak.
Obliczenia na komputerach z taśmami magnetycznymi od jakiegoś
czasu wyszły z mody, ale gdy danych jest dużo, to trzeba wrócić do
korzeni :D
No chyba że ktoś czytający ten wątek rozwiąże problem zanim ja
się wezmę do roboty :) Teoretycznie można go rozwiązać przy
pomocy dwóch poleceń powłoki sort i jednego uniq. W praktyce
nie wiem ile to zajmie czasu. Wiem na pewno, że dla depth=8
może zająć 8TB miejsca na dysku i następne 8-16TB na pliki
tymczasowe :/
Pozdrawiam
Cytat: mariotti w 17 Czerwiec 2013, 19:46
Odpaliłem
Zakończył się.
W wyniku mam plik all_rows.txt 94.1GB
Spakować i wystawić na ftp'a?
Cytat: krzyszp w 17 Czerwiec 2013, 21:40
Zakończył się.
W wyniku mam plik all_rows.txt 94.1GB
Spakować i wystawić na ftp'a?
Oj nie, to zaledwie początek zadania.
Teraz trzeba usunąć powtarzające się wiersze. Przy każdym wierszu trzeba
dopisać ile razy się ten wiersz powtarza. W dodatku kolejność wierszy musi
być zachowana.
Można to zrealizować np. tak:
1) Do każdego wiersza dodać numer kolejny (np. po średniku).
2) Dane posortować po tym co jest przed średnikiem
3) Przy pomocy komendy uniq usunąć duplikaty
4) zapamiętać ilość duplikatów (np. po drugim średniku)
5) Posortować po numerze kolejnym
6) Wywalić numer kolejny z wierszy
Wiem że to jest całkiem żmudne zadanie, jeśli nie jesteś pasjonatem
obróbki dużych plików tekstowych, to zostaw. Ja to dokończę za jakiś czas.
Dane u mnie też się ładnie generują, problem jest z dalszą obróbką.
Pozdrawiam
Cytat: krzyszp w 17 Czerwiec 2013, 21:40
Cytat: mariotti w 17 Czerwiec 2013, 19:46
Odpaliłem
Zakończył się.
W wyniku mam plik all_rows.txt 94.1GB
Spakować i wystawić na ftp'a?
A jeszcze jedno, czy program nie wywalił się w połowie, albo nie
zabrakło miejsca na dysku? Nie pasuje mi rozmiar pliku. U mnie
dla depth=7 plik ma rozmiar 195013386079bajtów i zawiera 3195901860 wierszy.
Pozdrawiam
A nie wiem, zaraz sprawdzę, tylko mam mały problem :)
W międzyczasie napisałem sobie program w VB który czyta plik po linii o zapisuje dane do bazy (tak jak Ty to napisałeś w c, ale ja w VB)... Ale z rozpędu podałem mu plik przez sieć i teraz mam zagwozdkę, co z tym fantem zrobić XD
Co do miejsca, to możliwe że tak, dopiero zauważyłem, że mam zajęte 100% na tej partycji, już odpalam tam, gdzie miejsca więcej :)
Zapomniałem dopisać - oczywiście, programik też wyszukuje duplikaty i je zlicza.
Open "\\Serwerek\all_rows.txt" For Input As #1
Do While Not EOF(1)
i = i + 1
Me.txtLinia.Text = "Linia: " & i
Line Input #1, strTemp
sSQL = "SELECT * FROM dane WHERE line = '" & strTemp & "'"
rsS.OpenRs sSQL, cnM
If rsS.RecordCount = 0 Then
rsS.AddNew
rsS.Fields("line") = strTemp
rsS.Fields("repeat") = 0
Else
rsS.Fields("repeat") = CInt(rsS.Fields("repeat")) + 1
End If
rsS.Update
rsS.CloseRecordset
Loop
Close #1
Cytat: krzyszp w 17 Czerwiec 2013, 22:38
Zapomniałem dopisać - oczywiście, programik też wyszukuje duplikaty i je zlicza.
I jak idzie? :D
Ja niby napisałem w bashu, ale pozostał jakiś błąd :/
file2='tmp.txt'
file1='out.txt'
(
echo printLeafs 4
echo quit
) | ./perft4 > $file1
gawk '{printf "%s;%s\n",$0,NR}' $file1 > $file2
cat $file2 | sort -k1 -t';' --stable > $file1
gawk -F';' '{ if(field==$1){sum++} else { if(NR!=1) {printf "%s;%d\n",row,sum} sum=1; row=$0; field=$1 } } END{ printf "%s;%d\n",$0,sum}' $file1 | sort -k2 -n -t';' > $file2
gawk -F';' '{printf "%s;%s\n",$1,$3}' $file2 > $file1
rm $file2
head -20 $file1
wc -l $file1
Poprawny wynik to 72078, a u mnie wyświetla 72090. Chyba tego nie da się
zrobić na przysłowiowym kolanie, trzeba przysiąść porządnie i użyć porządnych
narzędzi.
Pozdrawiam
Cytat: mariotti w 17 Czerwiec 2013, 23:56
Cytat: krzyszp w 17 Czerwiec 2013, 22:38
Zapomniałem dopisać - oczywiście, programik też wyszukuje duplikaty i je zlicza.
I jak idzie? :D
powoli :)
Generują się jeszcze dane, potem muszę przesłać plik na dysk lokalny (co chwilę potrwa) i dopiero potem rozpocznę import.
Zastanawia mnie, jaki jest maksymalny rozmiar linii (znaków)? Przydałoby się, aby ograniczyć rozmiar bazy bo i tak obawiam się, że przy 800GB wolnego miejsca na partycji może pojawić się problem (nie mam pojęcia, ile powtórzeń odpadnie)...
Cytat: krzyszp w 18 Czerwiec 2013, 00:01
powoli :)
Jeszcze jest opcja, żeby ten plik basha poprawić, a następnie dobrze sparametryzować
polecenie
sort - może zadziała w miarę szybko. Niestety ja nie umiem, nie mam
zbyt dużego doświadczenia w bashu.
Cytat: krzyszp w 18 Czerwiec 2013, 00:01
Generują się jeszcze dane, potem muszę przesłać plik na dysk lokalny (co chwilę potrwa) i dopiero potem rozpocznę import.
Sporo z tym zabawy... podejrzewam że i tak będzie trzeba napisać specjalistyczny program :/
Cytat: krzyszp w 18 Czerwiec 2013, 00:01
Zastanawia mnie, jaki jest maksymalny rozmiar linii (znaków)?
Założyłem że rozmiar linii maksymalnie wynosi 70 znaków, hmmm może to błędne założenie :/
Pod linuxem można sprawdzić takim poleceniem:
awk ' { if ( length > x ) { x = length; y = $0 } }END{ printf "%s:lenght:%d\n",y,x }' nazwa_pliku
Sprawdzenie trochę to potrwa :/
Można do awk przekierować wiersze prosto z programu - powinno znacznie przyspieszyć.
Cytat: krzyszp w 18 Czerwiec 2013, 00:01
Przydałoby się, aby ograniczyć rozmiar bazy bo i tak obawiam się, że przy 800GB wolnego miejsca na partycji może pojawić się problem (nie mam pojęcia, ile powtórzeń odpadnie)...
Według danych jakie posiadam będzie 96400068 unikalnych wierszy. 50GB powinno wystarczyć
łącznie z indeksami.
Pozdrawiam
No niestety, ja też jestem wyrobnik - w zasadzie VB6 i .NET, trochę (mało) PHP i to w zasadzie wszystko...
Niemniej, jak się dane wygenerują i zaimportują do bazy, to polowa za nami.
Też przyjąłem, że max 70 znaków (sprawdzone kawałki mieszczą się w 60), więc powinno być dobrze.
Jak chcesz, to po całej operacji dam Ci dostęp do gotowej bazy, żeby nie przerabiać znowu tego samego...
Cytat: krzyszp w 18 Czerwiec 2013, 00:22
No niestety, ja też jestem wyrobnik - w zasadzie VB6 i .NET, trochę (mało) PHP i to w zasadzie wszystko...
VB6 i .NET do typowych zastosowań to bardzo dobry komplet :) Ja raczej C++, a to w
zwykłych zastosowaniach jest zbyt niskopoziomowe.
Cytat: krzyszp w 18 Czerwiec 2013, 00:22
Niemniej, jak się dane wygenerują i zaimportują do bazy, to polowa za nami.
Też przyjąłem, że max 70 znaków (sprawdzone kawałki mieszczą się w 60), więc powinno być dobrze.
Dla pewności lepiej sprawdzę i potem wkleję wynik.
Cytat: krzyszp w 18 Czerwiec 2013, 00:22
Jak chcesz, to po całej operacji dam Ci dostęp do gotowej bazy, żeby nie przerabiać znowu tego samego...
Dodałeś do tabeli jakieś pole auto-inc? Kolejne wiersze muszą mieć kolejny numerek :)
Pozdrawiam
Cytat: mariotti w 18 Czerwiec 2013, 00:30
Dodałeś do tabeli jakieś pole auto-inc? Kolejne wiersze muszą mieć kolejny numerek :)
Oczywiście :)
Line też mają index (unique)- wydłuży to mocno import do bazy, ale przyśpieszy SELECT podczas wyszukiwania.
CREATE TABLE IF NOT EXISTS `dane` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Line` varchar(70) NOT NULL,
`Repeat` int(6) NOT NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `Line` (`Line`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
Nie jestem tylko pewien, czy nie trzeba było 'Line' zdefiniować jako Char(70)...
Cytat: krzyszp w 18 Czerwiec 2013, 00:32
Nie jestem tylko pewien, czy nie trzeba było 'Line' zdefiniować jako Char(70)...
O ile pamiętam, char różni się od varchar tylko tym, że char dokleja białe znaki
na końcu, a varchar ma znak końca linii? Jeśli pamiętam dobrze, to oba typy
w naszym przypadku będą zachowywały się bardzo podobnie.
Co do długości wiersza, to ten programik:
(
(
echo printLeafs 5
echo quit
) | ./perft4
) | awk ' { if ( length > x ) { x = length; y = $0 } }END{ printf "%s:lenght:%d\n",y,x }'
Daje taki wynik:
rnbqkbnr/p1p1pppp/1p1p4/8/8/1P1P1P2/P1P1P1PP/RNBQKBNR b qkQK -:lenght:62
Więc długość najdłuższego wiersza przy depth=5 wynosi 62 znaki.
Dla depth=7 jeszcze się liczy :D
Pozdrawiam
CytatVARCHAR stores a variable number of bytes for only the space required by the content.
CHAR stores a fixed size of however many bytes you specify for your table, no matter how many characters occupy a field of this type per row
Faktycznie, w naszym przypadku różnica będzie minimalna.
CytatVARCHAR stores a variable number of bytes for only the space required by the content.
CHAR stores a fixed size of however many bytes you specify for your table, no matter how many characters occupy a field of this type per row
Mnie to zawsze myliło. Nie wiem jak Ty rozumiesz to zdanie.
Space content nie tyczy się miejsca na dysku, ale miejsca na
dane, czyli miejsca na napis. VARCHAR nie tylko nie oszczędza
miejsca na dysku (jakby mogło sugerować space required), ale wręcz
zużywa go więcej :)
Tutaj ktoś dobrze przedstawił problem:
http://www.sqlblog.pl/2012/01/optymalizacja-rozmiaru-tabel-char-vs-varchar
ale na koniec wyciągnął złe wnioski, bo jest więcej przesłanek za używaniem
char :)
Pozdrawiam
Ja rozumiem to w ten sposób, że jeśli długość ciągu się mocno/często zmienia, to opłaca się varchar, w przeciwnym wypadku char i kompresja tabeli :)
Sytuację komplikuje to, że przy stałej długości wiersza szybciej przebiega indeksowanie i przeszukiwanie tabel - ale nie mam tutaj nic na poparcie tej tezy poza moimi odczuciami z pracy, więc traktuj to z przymrużeniem oka ;)
Cytat: krzyszp w 18 Czerwiec 2013, 01:07
Ja rozumiem to w ten sposób, że jeśli długość ciągu się mocno/często zmienia, to opłaca się varchar, w przeciwnym wypadku char i kompresja tabeli :)
Sytuację komplikuje to, że przy stałej długości wiersza szybciej przebiega indeksowanie i przeszukiwanie tabel - ale nie mam tutaj nic na poparcie tej tezy poza moimi odczuciami z pracy, więc traktuj to z przymrużeniem oka ;)
A jak to było z porównywaniem? W char chyba "a" jest równe "a ", chyba zawsze dokleja spacje?
Najdłuższą linię można odszukać również z pomocą wc.
wc -L
Nie mam tych danych wejściowych, żeby to sprawdzić, czy to nie oto idzie.
nl dane | sort -t$'\t' -k2 | uniq -cd -f2 | sort -n -k2
Dziwię się, że operujesz na tych danych bez żadnej kompresji, te dane powinny dobrze się kompresować 7-10x, a to mogłoby przyśpieszyć wszelkie operacje dyskowe. Dane na wejściu dekompresujesz.
Ewentualnie zrobić split i operować na mniejszych porcjach (sort|uniq), następnie połączyć i ponownie (sort|uniq).
Cytat: mariotti w 18 Czerwiec 2013, 01:11
A jak to było z porównywaniem? W char chyba "a" jest równe "a ", chyba zawsze dokleja spacje?
Nic o tym nie wiem :)
Może to kwestia użytego connectora?
Nigdy nie napotkałem takiego problemu...
Ps. Nie zaglądasz na IRC? Można na żywo pogadać na serwerze: irc.ircnet.pl kanał: #boinc@poland...
Cytat: buninek w 18 Czerwiec 2013, 01:14
Najdłuższą linię można odszukać również z pomocą wc.
wc -L
Dzięki
Cytat: buninek w 18 Czerwiec 2013, 01:14
Nie mam tych danych wejściowych, żeby to sprawdzić, czy to nie oto idzie.
nl dane | sort -t$'\t' -k2 | uniq -cd -f2 | sort -n -k2
Chyba nie o to, albo ja coś źle robię:
(
echo printLeafs 3
echo quit
) | ./perft4 | nl | sort -t$'\t' -k2 | uniq -cd -f1 | sort -n -k2 > out.txt
wc -l out.txt #powinno dać 5362
(
echo printLeafs 4
echo quit
) | ./perft4 | nl | sort -t$'\t' -k2 | uniq -cd -f1 | sort -n -k2 > out.txt
wc -l out.txt #powinno dać 72078
Cytat: buninek w 18 Czerwiec 2013, 01:14
Dziwię się, że operujesz na tych danych bez żadnej kompresji, te dane powinny dobrze się kompresować 7-10x, a to mogłoby przyśpieszyć wszelkie operacje dyskowe. Dane na wejściu dekompresujesz.
Ewentualnie zrobić split i operować na mniejszych porcjach (sort|uniq), następnie połączyć i ponownie (sort|uniq).
Dane wyjściowe i tak i tak muszę mieć w formacie bez kompresji. Natomiast do danych wejściowych
jest generator, w ogóle nie trzeba ich nigdzie zapisywać ani kompresować. Wygenerować wejście
można tak:
(
echo printLeafs 3
echo quit
) | ./perft4
Docelowo
echo printLeafs 3 ma być zastąpione
echo printLeafs 7, a w wersji
ambitnej
echo printLeafs 8.
Pozdrawiam
Cytat: krzyszp w 18 Czerwiec 2013, 01:15
Cytat: mariotti w 18 Czerwiec 2013, 01:11
A jak to było z porównywaniem? W char chyba "a" jest równe "a ", chyba zawsze dokleja spacje?
Nic o tym nie wiem :)
Może to kwestia użytego connectora?
Nigdy nie napotkałem takiego problemu...
Ps. Nie zaglądasz na IRC? Można na żywo pogadać na serwerze: irc.ircnet.pl kanał: #boinc@poland...
Dużo czasu poszło na rozwiązania "na kolanie" :) Przez ten czas może
bym zrobił porządny program :) Mam kupę pracy. Robię sobie dwa dni
całkowitego szlabanu na BOINCa. Potem zobaczymy co zrobił Twój
programik. Jeśli do tego czasu nie zakończy działania, to wklepię coś
w C++, bez bazy danych :)
Pozdrawiam
P.S.
A irca... nie nauczyłem się jeszcze obsługiwać pod linuxem :)
Uniq powinen działać od drugiego pola. Pierwsze pole to numer linii, rozdielony spacjami i tabulatorem.
W międzyczasie poprawiłem z
uniq -cd -f1
na
uniq -cd -f2
Przed sortem proponuje użyć
LC_ALL=C sort
Cytat: buninek w 18 Czerwiec 2013, 01:41
Uniq powinen działać od drugiego pola. Pierwsze pole to numer linii, rozdielony spacjami i tabulatorem.
W międzyczasie poprawiłem z
uniq -cd -f1
na
uniq -cd -f2
Zdaje się, że uniq jako fields traktuej wszystko rozdzielone białymi znakami. Wiersze
nie zawierają tabulatorów, ale zawierają spacje i chyba dlatego nie działa. W manie
nie znalazłem jak można zdefiniować separator dla uniq - a to by rozwiązało problem i to
w bardzo elegancki sposób. Inna sprawa czy byłby to też sposób wydajny :)
Pozdrawiam i dobranoc, bo jestem 20tą godzinę na nogach :)
Dokumentacja rozszerzona znajduje się w info coreutils.
info uniq
"Fields are sequences of non-space non-tab characters that are separated from each other by at least one space or tab."
uniq -f2 oznacza ni mniej, ni więcej - pomiń pierwsze pole, zacznij od drugiego porównywać wszystko.
To powinno dać prawidłowy wynik. Porównałem to z wu_test_perft i wynnik był identyczny.
nl pos.txt | LC_ALL=C sort -t$'\t' -k2 | uniq -cd -f2 | LC_ALL=C sort -n -k2
Standardowo nl, startuje z numeracją tylko 100000 linii, przy większej trzeba zwiększyć poprzez parametr -w.
Nie mam pojęcia jak sort radzi sobie z gigantycznymi porcjami danych. Warto zwrócić uwagę na możliwość kompresji tymczasowych plików poprzez
--compress-program=PROG oraz
--parallel=N (change the number of sorts run concurrently to N).
Zacząłem zapis do bazy danych, ale dwie rzeczy mocno spowalniają operację: zapis rekordów pojedynczo przez sieć oraz odpalenie programu w debuggerze (nie wiem jak się zachowa przy tak wielkim pliku). Niestety dziś nie mogę go w czasie dnia zostawić bez nadzoru.
Wieczorem dam znać jaki wynik.
Cytat: buninek w 18 Czerwiec 2013, 02:02
Dokumentacja rozszerzona znajduje się w info coreutils.
info uniq
"Fields are sequences of non-space non-tab characters that are separated from each other by at least one space or tab."
uniq -f2 oznacza ni mniej, ni więcej - pomiń pierwsze pole, zacznij od drugiego porównywać wszystko.
W takim razie powinno działać.
Cytat: buninek w 18 Czerwiec 2013, 02:02
To powinno dać prawidłowy wynik. Porównałem to z wu_test_perft i wynnik był identyczny.
nl pos.txt | LC_ALL=C sort -t$'\t' -k2 | uniq -cd -f2 | LC_ALL=C sort -n -k2
U mnie nie działa:
./go.sh
72078 out1.txt # prawidłowa ilość wierszy
6799 out2.txt # nieprawidłowa
cat go.sh
depth=4
(
echo printLeafs $depth
echo quit
) | ./perft4 | sort | uniq > out1.txt
wc -l out1.txt
(
echo printLeafs $depth
echo quit
) | ./perft4 | nl | LC_ALL=C sort -t$'\t' -k2 | uniq -cd -f2 | LC_ALL=C sort -n -k2 > out2.txt
wc -l out2.txt
Poniższy skrypt też nie działa, a realizuje tylko część zadania.
depth=4
(
(
(
(
echo printLeafs $depth
echo quit
) | ./perft4
) | gawk '{printf"%s;%d\n",$0,NR}'
) | sort -t$';' -k1
) | gawk -F';' '{if(field==$1) {sum++} else {printf"%s\n",$0} field=$1}' > out1.txt
wc -l out1.txt
Znajduje za dużo wierszy, bo aż 72090. Unikalnych jest tylko 72078.
Nie wiem dlaczego nie działa, to prosty skrypt. Pierwsze gawk dodaje do
każdego wiersza średnik i numer kolejny. Sort sortuje po tym co jest
przed średnikiem. Drugi gawk wyświetla wiersz, pod warunkiem że ta
część do średnika różni się od wiersza bezpośrednio nad nim.
Cytat: buninek w 18 Czerwiec 2013, 02:02
Nie mam pojęcia jak sort radzi sobie z gigantycznymi porcjami danych. Warto zwrócić uwagę na możliwość kompresji tymczasowych plików poprzez
Sort ma możliwość wskazania plików tymczasowych. Jeszcze nie wiem co robi w tych
plikach tymczasowych, ale jeśli robi w nich merge-sort, to rozwiąże to zadanie bardzo
szybko. W połączeniu z kompresją może być jeszcze lepiej.
Pozdrawiam
Cytat: krzyszp w 18 Czerwiec 2013, 10:11
Zacząłem zapis do bazy danych, ale dwie rzeczy mocno spowalniają operację: zapis rekordów pojedynczo przez sieć oraz odpalenie programu w debuggerze (nie wiem jak się zachowa przy tak wielkim pliku). Niestety dziś nie mogę go w czasie dnia zostawić bez nadzoru.
Wieczorem dam znać jaki wynik.
Ciekawy jestem jak to się zachowa. Dziś i jutro mam urwanie głowy. Jak
"rozwiązania na kolanie" nie zadziałają, to w piątek/sobotę napiszę porządny
program do tego zadania.
Pozdrawiam
Bym zapomniał.
Najdłuższy wiersz przy depth=7 ma 66 znaków. Sprawdzenie
tego trwało 181 minut.
Załączam skrypt który to policzył. Gdy uruchamiałem skrypt, to
jeszcze nie znałem wc -L i dlatego w awk. Mam nadzieję że nie ma bugów:
cat go2.sh
(
(
echo printLeafs 7
echo quit
) | ./perft4
) | awk ' { if ( length > x ) { x = length; y = $0 } }END{ printf "%s:lenght:%d\n",y,x }'
time ./go2.sh
rnbqkbnr/p1p1p1pp/1p1p1p2/8/5B2/1P1P1P2/P1P1P1PP/RN1QKBNR b qkQK -:lenght:66
real 181m5.714s
user 229m47.530s
sys 27m49.140s
Pozdrawiam
Zapomniałem wcześniej napisać - w MySQL pole nie może mieć nazwy 'Repeat' (to komenda SQL), nie wiem jak w sqlite...
Póki co rekordy dodajá sié prawidłowo (w tej chwili jest 70958).
Ps. Przy okazji przypomniałem sobie, że inkrementacja i=i+1 dla integera jest w tym wypadku złym pomysłem - stack overflow ;)
Tak sobie pomyślałem, że jeśli dl depth=7 mamy 195GB na dysku, to jednak lepiej je chyba generować bezpośrednio do bazy w przypadku depth=8...
Pytanie, ile bédzie unikalnych rekordów dla tek ilości danych? (Gdzieś to wcześniej było, ale przegapiłem)
Cytat: krzyszp w 18 Czerwiec 2013, 13:52
Zapomniałem wcześniej napisać - w MySQL pole nie może mieć nazwy 'Repeat' (to komenda SQL), nie wiem jak w sqlite...
Póki co rekordy dodajá sié prawidłowo (w tej chwili jest 70958).
Ps. Przy okazji przypomniałem sobie, że inkrementacja i=i+1 dla integera jest w tym wypadku złym pomysłem - stack overflow ;)
Tabelka ze wszystkimi i unikalnymi:
6 119.060.324 9.417.681
7 3.195.901.860 96.400.068
8 84.998.978.956 988.187.354
9 2.439.530.234.167 10.122.483.176 <-- ekstrapolowane
Więc int32 (31 bitów na dodatnie wartości) wystarczy do depth=8, jeśli
zapisuje się tylko unikalne układy.
SQLite nie burzył się na repeat - dla małych głębokości dał poprawne wyniki.
A co do optymalnego algorytmu na "dyskowym modelu obliczeń", to widzę go tak:
Definiujemy parę:
struct Pair {
short count
char row[70];
};
Tworzymy tablicę tych par, tak dużą jak pozwala pamięć RAM:
Pair pairs[SIZE];
Zapamiętujemy początek tablicy:
start = 0;
Zapamiętujemy koniec tablicy:
end = 0;
Program wczytuje kolejne wiersze ze standardowego wejścia do
zmiennej row;
Jeśli row jest mniejszy niż 70 bajtów, to dokleja zera na końcu row.
Następnie program szuka w tablicy pairs czy dany wiersz się
powtarza. Jeśli się powtarza, to inkrementuje licznik, jeśli nie
to dodaje na koncu:
pairs[end].row = row;
pairs[end].count = 1;
Następnie zwiększa zmienną end:
end = (end + 1) % SIZE;
Jeśli zmienna end równa się start, to zrzuca ostatni element do pliku
if( end == start ) {
save( file , pair[start] );
start = (start + 1) % SIZE;
}
W ten sposób otrzymamy kolejkę cykliczną.
Wąskim gardłem będzie wyszukiwanie w dużej tablicy pairs. Trzeba ją jakoś
zaindeksować. Najszybsza do tego celu będzie jakaś hash-table.
Gdy podawane rekordy na standardowe wejście wyczerpią się, to trzeba
uruchomić drugi program. Drugi program też będzie miał tablicę pairs.
Wpisze do niej układy z początku pliku. Gdy tablica się zapełni, to
będzie musiał iterować do końca pliku wczytując po jednym rekordzie.
Wczytywanie
sekwencyjne jest bardzo szybkie - i to jest istotą
tego algorytmu. Każdy wczytany rekord z pliku, program będzie próbował
odszukać w tablicy pairs. Jeśli znajdzie, to na dysku oznaczy ten rekord
jako usunięty, a w tablicy piars zwiększy count. Gdy osiągnie koniec
pliku, to tablica pairs ze zmienionymi wartościami count zostanie
zapisna na dysku, "dziurka od klucza" zostanie przesunięta za ostatni
element który poprzednio był wczytany do pairs, no i do tablicy
pairs zostaną wczytane następne rekordy. Oczywiście poza tymi
rekordami, które zostały oznaczone jako usunięte.
Para będzie miała rozmiar 72 bajtów. Więc w 6GB pamięci ram zmieści
się około 100mln par. Unikalnych wierszy dla depht=8 jest 988.187.354,
oznacza to, że wystarczy przeiterować po pliku 10 razy minus to co
zostanie odrzucone pierwszym programem. Ponadto każda kolejna
iteracja będzie się zaczynała od dalszych adresów (nie każda będzie
od początku pliku).
Strzelam że koszt wykonania całego programu będzie równy czterem
całkowitym odczytom pliku z danymi. Czyli dla depht=8 może da się
policzyć w 2 dni - o ile się nie mylę :)
Pozdrawiam
P.S.
Jeszcze jest potrzebny trzeci program/procedura do fizycznego usunięcia
wszystkich logicznie oznaczonych jako usunięte :)
Cóż, mój program sié nie sprawdzi... Po kilku godzinach mam 120k rekordów (unikalnych) wiéc dla 96,4kk rekordów potrwa to... długo. Skompilowanie softu nic nie da, bo dalej rekordy dodajá sié po jednym.
Wieczorem przysiádé i przerobie na dodawanie w seriach (np. po 10k rekordów), wtedy powinna być sensowniejsza prédkość, w dodatku skompilujé też program.
Innym rozwiázaniem (chyba lepszym) by był zapis do csv i import całości jednym rzutem do bazy - może tak właśnie zrobié - zobaczé wieczorem.
Cytat: krzyszp w 18 Czerwiec 2013, 16:50
Cóż, mój program sié nie sprawdzi... Po kilku godzinach mam 120k rekordów (unikalnych) wiéc dla 96,4kk rekordów potrwa to... długo. Skompilowanie softu nic nie da, bo dalej rekordy dodajá sié po jednym.
Wieczorem przysiádé i przerobie na dodawanie w seriach (np. po 10k rekordów), wtedy powinna być sensowniejsza prédkość, w dodatku skompilujé też program.
Innym rozwiázaniem (chyba lepszym) by był zapis do csv i import całości jednym rzutem do bazy - może tak właśnie zrobié - zobaczé wieczorem.
Moim zdaniem transfer związany z wieloma małymi zapytaniami nie jest wąskim gardłem.
Wąskim gardłem są
naprowadzenia głowicy na losowe adresy. Dyski talerzowe (w
przeciwieństwie do pamięci RAM i dysków SSD) są przystosowane do sekwencyjnego
odczytu. Potrafią np. szybko odczytać ogromny plik. Ale wyszukiwanie małych porcji
danych na dysku talerzowym jest bardzo wolne, gdyż element mechaniczny (głowica)
musi być mechanicznie pozycjonowana. Elementy mechaniczne są zawsze wolne.
W momencie gdy dajemy
select * form tabela where row = 'row';
to baza danych (na podstawie indeksu) ustala pozycję rekordów.
Następnie głowica jest naprowadzana na tę pozycję. Oczywiście
jest cache dysku, bazy i systemu plików - ale na tak dużych
zbiorach cache szybko się wyczerpuje. Dla 988.187.354 unikalnych
rekordów powiedzmy że mamy 3kkk naprowadzeń głowicy. Jedno naprowadzenie
niech trwa np. 5ms to mam 170 dni na samo naprowadzenie głowicy.
Więc ja bym nie sprawdzał jak działa na wielu danych w jednym zapytaniu, ale
nie wiem na pewno, może coś pomyliłem :D
Pozdrawiam
Nie zapomnij, że ja wciáż mam bardzo mało rekordów, wiéc zapewne i baza i index siedzá w cache.
Natomiast przy okazji robienia bazy danych klimatycznych dla Rysia odkryłem, że najbardziej ekonomiczne (ilosc_rekordow/jednostke_czasu) jest jednoczesne dodawanie 10k rekordów.
Cytat: krzyszp w 18 Czerwiec 2013, 17:18
Nie zapomnij, że ja wciáż mam bardzo mało rekordów, wiéc zapewne i baza i index siedzá w cache.
Racja. W końcu cache się wyczerpie. Gdy ilość rekordów wzrośnie N razy, to czas może
wzrosnąć 10*N.
Cytat: krzyszp w 18 Czerwiec 2013, 17:18
Natomiast przy okazji robienia bazy danych klimatycznych dla Rysia odkryłem, że najbardziej ekonomiczne (ilosc_rekordow/jednostke_czasu) jest jednoczesne dodawanie 10k rekordów.
To muszę o coś zapytać. Jak używasz transakcji? O ile się nie mylę, to większość
baz danych każde jedno zapytanie automatycznie obejmuje transakcją, jeśli
wcześniej tego nie zrobił użytkownik.
Czyli zapytanie:
select coś tam;
Jest równoważne trzem zapytaniom:
begin;
select coś tam;
commit;
Transakcje wymuszają przerzucenie danych z dziennika do plików, a
mało tego, wymuszają jeszcze oczekiwanie aplikacji na upewnienie się, że
system operacyjny zapisał na dysku dane. Z góry przepraszam jeśli
dobrze wiesz o tym, a ja zbędnie tłumaczę.
Natomiast jeśli nie próbowałeś optymalizować transakcji, to cały ten
program do dodawania unikalnych rekordów obejmij transakcją.
Na początku programu, zaraz po połączeniu się do bazy daj
begin,
a zupełnie na końcu daj
commit - mogę się mylić, ale powinno
przyspieszyć 10-100 razy - wszystko zależy od buforów. No chyba
że łącze internetowe jest naprawdę bardzo wolne, to nic nie da.
Pozdrawiam
Cytat: mariotti w 18 Czerwiec 2013, 12:47
U mnie nie działa:
./go.sh
72078 out1.txt # prawidłowa ilość wierszy
6799 out2.txt # nieprawidłowa
cat go.sh
depth=4
(
echo printLeafs $depth
echo quit
) | ./perft4 | sort | uniq > out1.txt
wc -l out1.txt
(
echo printLeafs $depth
echo quit
) | ./perft4 | nl | LC_ALL=C sort -t$'\t' -k2 | uniq -cd -f2 | LC_ALL=C sort -n -k2 > out2.txt
wc -l out2.txt
Jesli możesz wrzuć tu ten plik dla depth=4, sprawdziłbym to jeszcze raz.
Ja tego generatora nie uruchomię z uwagi na system x86.
Cytat: buninek w 18 Czerwiec 2013, 18:01
Jesli możesz wrzuć tu ten plik dla depth=4, sprawdziłbym to jeszcze raz.
Ja tego generatora nie uruchomię z uwagi na system x86.
Nie działa. Zaczynam się bać - proste programy i skrypty nie działają. Czy ja
robię coś źle? Bałem się, że to program perft4 coś psuje, więc uruchomiłem go
w osobnym wierszu - nie pomogło.
head -n 13 go.sh
depth=4
(
echo printLeafs $depth
echo quit
) | ./perft4 > input.txt
cat input.txt | sort | uniq > out1.txt
wc -l out1.txt
cat input.txt | nl | LC_ALL=C sort -t$'\t' -k2 | uniq -cd -f2 | LC_ALL=C sort -n -k2 > out2.txt
wc -l out2.txt
exit
./go.sh
72078 out1.txt
6799 out2.txt
Załączam plik input.txt - ten sam który wygenerował powyższy skrypt.
Plik jest spakowany programem bzip2 - trzeba zmienić nazwę na input.txt.bz2
Załączam także moje wszystkie próby w bashu.
Pozdrawiam
[edit]
Nie można załączać plików z rozszerzeniem sh i przez pomylkę załączyłem plik
out.txt. Załączam teraz go.txt, trzeba zmienić nazwę na go.sh.
nl input | LC_ALL=C sort -t$'\t' -k2 | uniq -c -f1 | LC_ALL=C sort -n -k2 | wc -l
72078
U mnie sort, uniq jest szybsze od sqlite ok 37 razy.
time ( cat input | ./wu_test_perft out.db )
Cytat: buninek w 18 Czerwiec 2013, 18:56
nl input | LC_ALL=C sort -t$'\t' -k2 | uniq -c -f1 | LC_ALL=C sort -n -k2 | wc -l
72078
Wyjaśniło się, tym razem ja przeoczyłem poprawny wynik. Chyba
przywykłem do błędów na dobre. Hehe :)
Cytat: buninek w 18 Czerwiec 2013, 18:56
U mnie sort, uniq jest szybsze od sqlite ok 37 razy.
time ( cat input | ./wu_test_perft out.db )
Zrobię benchmark od głębokości 1 do 6.
Mam wersję tego algorytmu w pamięci RAM, on ledwo daje radę
dla głębokości=6. Niemniej dzięki niemu sprawdzimy jeszcze
poprawność powtórzeń - oba algorytmy muszą dać identyczne wyniki.
Jak będzie wszystko ok, to spróbujemy policzyć dla 7. Szkoda że sort
nie ma paska postępu, nie bedziemy wiedzieli czy się zawiesiło, czy
działa.
Pozdrawiam
Nic nie przeoczyłeś, najzwyczajniej źle były dobrane opcje dla uniq.
Wcześniej było uniq -cd -f2, powinno być jednak uniq -c -f1.
Cytat: buninek w 18 Czerwiec 2013, 19:38
Nic nie przeoczyłeś, najzwyczajniej źle były dobrane opcje dla uniq.
Wcześniej było uniq -cd -f2, powinno być jednak uniq -c -f1.
Racja. Teraz pomieszałem z dobrym wynikiem dla gołego sort i uniq. Zadanie jest
trudne, wymaga zastanowienia, a tak z doskoku to człowiek sam nie wie co robi :)
Benchamrk trwa. Dla depth=5 zakończył, czekamy na depth=6.
cat ./go.sh
depth=$1
(
echo printLeafs $depth
echo quit
) | ./perft4 | nl | LC_ALL=C sort -t$'\t' -k2 | uniq -c -f1 | LC_ALL=C sort -n -k2 > out.txt
wc -l out.txt
x@biglaptop:/media/ATA1TB/tmp$ time ./go.sh 1
20 out.txt
real 0m0.042s
user 0m0.004s
sys 0m0.000s
x@biglaptop:/media/ATA1TB/tmp$ time ./go.sh 2
400 out.txt
real 0m0.016s
user 0m0.004s
sys 0m0.000s
x@biglaptop:/media/ATA1TB/tmp$ time ./go.sh 3
5362 out.txt
real 0m0.048s
user 0m0.028s
sys 0m0.028s
x@biglaptop:/media/ATA1TB/tmp$ time ./go.sh 4
72078 out.txt
real 0m0.820s
user 0m0.784s
sys 0m0.324s
x@biglaptop:/media/ATA1TB/tmp$ time ./go.sh 5
822518 out.txt
real 0m21.362s
user 0m20.549s
sys 0m7.936s
x@biglaptop:/media/ATA1TB/tmp$ time ./go.sh 6
Pozdrawiam
:facepalm2:Wcześniej wspomniałem, że nie jestem pewien jak nl zachowuje się przy numeracji bardzo dużych plików.
Na szybko można sprawdzić czy poprawnie.
seq 1 119060324 | nl | tail -n10
seq 1 3195901860 | nl | tail -n10
Czy nie trzeba dodać
seq 1 119060324 | nl -w9 | tail -n10
seq 1 3195901860 | nl -w10 | tail -n10
Numerować można również cat-em.
man cat
man nl
Edit:
Pasek postępu moża zrobić dzięki pv są również inne rozwiązania. Choć umiejętne skorzystanie z pv w takim potoku nie jest proste.
Tak zupełnie nie dość dokładnie (wręcz bardzo kulawo), to
pv input | nl | LC_ALL=C sort -t$'\t' -k2 | uniq -c -f1 | LC_ALL=C sort -n -k2 > out
Cytat: mariotti w 18 Czerwiec 2013, 19:44
Benchamrk trwa. Dla depth=5 zakończył, czekamy na depth=6.
Benchmark się zakończył. Zrzut z konsoli:
x@biglaptop:/media/ATA1TB/tmp$ cat ./go.sh
depth=$1
(
echo printLeafs $depth
echo quit
) | ./perft4 | nl | LC_ALL=C sort -t$'\t' -k2 | uniq -c -f1 | LC_ALL=C sort -n -k2 > out.txt
wc -l out.txt
x@biglaptop:/media/ATA1TB/tmp$ time ./go.sh 1
20 out.txt
real 0m0.042s
user 0m0.004s
sys 0m0.000s
x@biglaptop:/media/ATA1TB/tmp$ time ./go.sh 2
400 out.txt
real 0m0.016s
user 0m0.004s
sys 0m0.000s
x@biglaptop:/media/ATA1TB/tmp$ time ./go.sh 3
5362 out.txt
real 0m0.048s
user 0m0.028s
sys 0m0.028s
x@biglaptop:/media/ATA1TB/tmp$ time ./go.sh 4
72078 out.txt
real 0m0.820s
user 0m0.784s
sys 0m0.324s
x@biglaptop:/media/ATA1TB/tmp$ time ./go.sh 5
822518 out.txt
real 0m21.362s
user 0m20.549s
sys 0m7.936s
x@biglaptop:/media/ATA1TB/tmp$ time ./go.sh 6
9417683 out.txt
real 25m53.570s
user 9m38.424s
sys 4m7.715s
x@biglaptop:/media/ATA1TB/tmp$ ./perft4
diffLeafs 6 0
diff leafs: = 9417683
max repeat: 479
fen: rnbqkbnr/pppp1ppp/8/4p3/4P3/8/PPPP1PPP/RNBQKBNR w qkQK -
quit
x@biglaptop:/media/ATA1TB/tmp$
Jak widać, obliczenia dla depth=6 trwały 25 minut. Polecenie sort przydzieliło sobie
malutko pamięci ram, może 50MB. Czyli ogólnie pozytywnie.
Mam jakiś dokument, a w nim, że ilość węzłów unikalnych wynosi 941768
1.
Tymczasem w teście wyszło 941768
3. Na końcu zrzutu z konsoli widać
jeszcze jeden wynik 941768
3 - to wersja która realizuje to samo zadanie, ale
w pamięci ram. Więc jeszcze muszę ustalić, czy błąd zawiera ten dokument, czy
program perft4. Ciekawe jaki może być błąd w perft4, jeśli przeszedł tak ogromną
ilość testów na poprawne zliczanie wszystkich (nie unikalnych) węzłów. Tak czy
inaczej, znowu coś dziwnego, ale wybrniemy w końcu :)
Zrobiłem aproksymację, przy założeniu że kolejne głębokości mają złożoność N*LogN, a
N rośnie tak jak ilość węzłów. Wyszło że dla depth=7 policzy w pół doby, a dla
depth=8 w 17 dni. Ciekawe ile taka aproksymacja jest warta :)
Nie zaszkodzi zostawić tego na 1-2 doby, może akurat się uda :)
Pozdrawiam
Może trafił jakiś komunikat, ostrzeżenie, biała linia z sort, uniq, nl.
Może jakoś zweryfikować na szybko grepem, czy nie ma tam nic niepożądanego.
grep -v '.*/.*/.*/.*/.*/.*/.*/.*' wynik
Cytat: buninek w 18 Czerwiec 2013, 20:47
Może trafił jakiś komunikat, ostrzeżenie, biała linia z sort, uniq, nl.
Może jakoś zweryfikować na szybko grepem, czy nie ma tam nic niepożądanego.
grep -v '.*/.*/.*/.*/.*/.*/.*/.*' wynik
Dobry pomysł, takie sprawdzenie nigdy nie zaszkodzi.
Jednak z dwóch innych (lecz niestety zależnych) programów jest wynik z
trójką na końcu. Wynik z trójką na końcu dał algorytm który działa
całkowicie w RAM i Twój algorytm który działa tylko na tekstowych wierszach.
Oba algorytmy korzystają z dobrze przetestowanego "trzonu" do
generowania układów. I oba algorytmy dały taki sam błąd? Może jednak
błąd jest w tym dokumencie - dziwne ale możliwe, będzie trzeba to dokładnie zbadać.
Wracając do Twojego potoku, dodałem bufory ram, a katalog tymczasowy
będzie na drugim dysku:
cat go.sh
depth=$1
(
echo printLeafs $depth
echo quit
) | ./perft4 | nl | LC_ALL=C sort -t$'\t' -k2 -T'./tmp' -S1000000 | uniq -c -f1 | LC_ALL=C sort -n -k2 -T'./tmp' -S1000000 > out.txt
wc -l out.txt
time ./go.sh 6
9417683 out.txt
real 13m32.642s
user 9m54.301s
sys 3m8.344s
Jak widać, nieźle przyspieszyło. Teraz przenoszę wszystko na stacjonarny, dam 6GB RAM i czekamy.
Pozdrawiam
Jeszcze trochę czasu zaoszczędzi się, gdy się ograniczy uniq do znaków ASCII.
Dodaj LC_ALL=C przed uniq.
Porównaj:
time grep -v '.*/.*/.*/.*/.*/.*/.*/.*' wynik
time LC_ALL=C grep -v '.*/.*/.*/.*/.*/.*/.*/.*' wynik
Różnica jest niebagatelna.
Bardzo dobrym zamiennikiem sed-a jest minised. Diabelsko szybki, na ogromnych plikach.
Identycnie jest z cgrepem.
http://www.bell-labs.com/project/wwexptools/cgrep/
Rewelacyjne narzędzie, niezwykle szybkie, duużo szybsze od GNU grepa.
Tym sortem się kiedyś bawiłem całkiem sprawny.
http://billposer.org/Software/msort.html
Cytat: mariotti w 18 Czerwiec 2013, 17:51
Natomiast jeśli nie próbowałeś optymalizować transakcji, to cały ten
program do dodawania unikalnych rekordów obejmij transakcją.
Nie da rady, zabraknie pamięci (w serwerze mam tylko ok.3GB dla bazy).
Podobnie nie ma sensu paczkować rekordów, gdyż obecnie dla każdej linii przed dodaniem leci select, aby sprawdzić, czy nie występuje...
Myślę, że rozwiązanie shellowe będzie znacznie szybsze.
Ps. Na bazie działam przez LAN 1Gb/s
Cytat: buninek w 18 Czerwiec 2013, 21:27
Jeszcze trochę czasu zaoszczędzi się, gdy się ograniczy uniq do znaków ASCII.
Dodaj LC_ALL=C przed uniq.
Porównaj:
time grep -v '.*/.*/.*/.*/.*/.*/.*/.*' wynik
time LC_ALL=C grep -v '.*/.*/.*/.*/.*/.*/.*/.*' wynik
Różnica jest niebagatelna.
Bardzo dobrym zamiennikiem sed-a jest minised. Diabelsko szybki, na ogromnych plikach.
Identycnie jest z cgrepem.
http://www.bell-labs.com/project/wwexptools/cgrep/
Rewelacyjne narzędzie, niezwykle szybkie, duużo szybsze od GNU grepa.
Tym sortem się kiedyś bawiłem całkiem sprawny.
http://billposer.org/Software/msort.html
A ja myślałem naiwnie, że najszybsze są standardowo w linuxie.
Dobrze wiedzieć że są lepsze.
Programik już odpaliłem, działa na drugim kompie. Nie zmienię teraz
w nim nic, po prostu mam masę roboty, terminy, itd. Jutro zobaczymy jaki
będzie efekt działania tego programu. Jak będzie mizerny, to cóż...
zaimplementuję w C++ ten algorytm który opisałem kilka postów
wyżej.
Niepokoi mnie jeszcze ten błąd z trójką na końcu. No ale między innymi
po to będzie testowa wersja na boinc :)
Pozdrawiam
Cytat: krzyszp w 18 Czerwiec 2013, 21:29
Nie da rady, zabraknie pamięci (w serwerze mam tylko ok.3GB dla bazy).
Można też dać begin commit np. co 10k rekordów. Na sqlite taka technika daje
czasami bardzo duże przyspieszenie - zależy od struktury bazy.
Cytat: krzyszp w 18 Czerwiec 2013, 21:29
Podobnie nie ma sensu paczkować rekordów, gdyż obecnie dla każdej linii przed dodaniem leci select, aby sprawdzić, czy nie występuje...
Wszystko się zgadza, prawdopodobnie ten select jest wąskim gardłem całej aplikacji.
Cytat: krzyszp w 18 Czerwiec 2013, 21:29
Myślę, że rozwiązanie shellowe będzie znacznie szybsze.
Ps. Na bazie działam przez LAN 1Gb/s
Shellowe dla deph=6 działa 10 minut na laptopie. Zobaczymy co będzie dla depth=7.
Pozdrawiam
Cytat: mariotti w 18 Czerwiec 2013, 22:14
A ja myślałem naiwnie, że najszybsze są standardowo w linuxie.
Dobrze wiedzieć że są lepsze.
Bez przesady, te standardowe narzędzia są uniwersalne i naprawdę szybkie. To są poprostu zupełnie inne narzędzia.
Przykładowo minised ma 5% możliwości seda. Tylko czasem potrzebujemy tylko tych 2% możliwości, a dużo ważniejsza jest szybkość przy przetworzenie terabajtów danych.
Cgrep to akurat unikalny programik. Tylko znowu ma pewne cechy których nie posiada GNU grep, ale również brakuje mu kilku opcji grepa.
Powstał nie byle gdzie, bo w Bell Labs, a tam pracowali naprawdę łebscy goście. Twórcy UNIXA, języka C, C++, R. Bodajże 7 pracowników tego laboratorium "talentów" zostało nagrodzonych Noblem.
Cytat: buninek w 18 Czerwiec 2013, 22:45
Bez przesady, te standardowe narzędzia są uniwersalne i naprawdę szybkie. To są poprostu zupełnie inne narzędzia.
Przykładowo minised ma 5% możliwości seda. Tylko czasem potrzebujemy tylko tych 2% możliwości, a dużo ważniejsza jest szybkość przy przetworzenie terabajtów danych.
Rozumiem, lepsza wydajność za mniejszą funkcjonalność.
Cytat: buninek w 18 Czerwiec 2013, 22:45
Cgrep to akurat unikalny programik. Tylko znowu ma pewne cechy których nie posiada GNU grep, ale również brakuje mu kilku opcji grepa.
Powstał nie byle gdzie, bo w Bell Labs, a tam pracowali naprawdę łebscy goście. Twórcy UNIXA, języka C, C++, R. Bodajże 7 pracowników tego laboratorium "talentów" zostało nagrodzonych Noblem.
Czytałem kiedyś że twórcy Perla szydzili z grepa... ale chyba zaczynam za bardzo odbiegać :)
Wracając do tematu. Jakbym jednak sam chciał/musiał rzeźbić w C++ programik do optymalizacji WU,
to niby wiem jak to zrobić, ale niepokoi mnie pewien szczegół: Są małe rekordy binarnych danych, mają
rozmiar w okolicach 50 - 100 bajtów. Są one zapisane w ogromnym pliku na dysku talerzowym. Odczytujemy
te rekordy sekwencyjnie w pętli, np. tak:
while( not_end_of_file( file , rekord ) ) {
}
W pętli robimy analizę danych i z dużym prawdopodobieństwem odczytany rekord
trzeba zmodyfikować i zapisać:
while( not_end_of_file( file , rekord ) ) {
if( analiza( rekord ) ) { // prawdopodobieństwo że warunek prawdziwy: 95-99%
modyfikuj( rekord );
cofnij_wskaznik_pliku( file , size(rekord) );
zapisz( file , rekord );
}
}
I teraz moje pytanie: czy powyższy kod jest wydajny? Czy takie ciągłe cofanie o jeden rekord jest szybkie?
Czy może lepiej przeanalizować w porcjach po 10k rekordów, cofnąć wskaźnik pliku o rozmiar całej
porcji i zapisać całą porcję?
Pozdrawiam
W temacie programowania zupełnie nie pomogę. Przy tego typu "prostych" programach potrzebna jest duża wiedza. Nawet mając duże doświadczenie w programowaniu, może okazać się ono niewystarczające.
Spójrz na to, szybka wersja sort | uniq -c | sort -n[r] w C++.
https://gist.github.com/alisaifee/2983201 (https://gist.github.com/alisaifee/2983201)
To jakiś wiekowy kod, bo g++-4.7.3, g++-4.4.4, g++-4.3.4 wywala błąd. Dopiero z g++-4.2.4 powiodła się kompilacja.
Wcale nie taka szybka, tylko 3 razy wolniejsza.
Cytat: buninek w 18 Czerwiec 2013, 23:29
W temacie programowania zupełnie nie pomogę. Przy tego typu "prostych" programach potrzebna jest duża wiedza.
Nawet mając duże doświadczenie w programowaniu, może okazać się ono niewystarczające.
Trzeba długo tuningować takie programiki w różnych warunkach, w różnym sprzęcie - a to
jest katorżnicza robota. W końcu można dobrać zadowalające parametry danego
narzędzia. Pewnie będę musiał sprawdzić w praktyce czy cofanie wskaźnika o jeden
rekord mocno spowalnia.
Cytat: buninek w 18 Czerwiec 2013, 23:29
Spójrz na to, szybka wersja sort | uniq -c | sort -n[r] w C++.
https://gist.github.com/alisaifee/2983201 (https://gist.github.com/alisaifee/2983201)
Widać, że ktoś wszędzie gdzie się dało wykorzystał STL.
Na pierwszy rzut oka zgrabny programik.
Cytat: buninek w 18 Czerwiec 2013, 23:29
To jakiś wiekowy kod, bo g++-4.7.3, g++-4.4.4, g++-4.3.4 wywala błąd. Dopiero z g++-4.2.4 powiodła się kompilacja.
Wcale nie taka szybka, tylko 3 razy wolniejsza.
Yyyy to działa wolniej niż shellowe? :D Nie przeanalizuję na szybko, bo używam na co
dzień innej biblioteki, nie mam wprawy w STLu.
Eksperyment zrobiony na kolanie, też nie starałem się optymalizować.
Wynik: bash: 74 sekundy; specjalistyczny algorytm: 8 sekund - 9 razy szybciej.
Na samym dole listingu kod w C++.
ls -l
razem 2148
-rwx------ 1 x x 52 2013-06-19 01:40 go1.sh
-rwx------ 1 x x 36 2013-06-19 01:40 go2.sh
-rwx------ 1 x x 54 2013-06-19 01:41 go.sh
-rw-rw-r-- 1 x x 1081 2013-06-19 01:39 main.cpp
-rwxrwxr-x 1 x x 2140238 2013-06-19 01:15 perft4
-rwxrwxr-x 1 x x 19042 2013-06-19 01:39 suniq
-rw-rw-r-- 1 x x 289 2013-06-19 00:47 suniq.pro
-rw-rw-r-- 1 x x 15264 2013-06-19 01:19 suniq.pro.user
x@biglaptop:~/Dokumenty/c/suniq$ cat go.sh
(
echo printLeafs 5
echo quit
) | ./perft4 > data.txt
x@biglaptop:~/Dokumenty/c/suniq$ ./go.sh
x@biglaptop:~/Dokumenty/c/suniq$ ls -l
razem 285324
-rw-rw-r-- 1 x x 289969208 2013-06-19 01:42 data.txt
-rwx------ 1 x x 52 2013-06-19 01:40 go1.sh
-rwx------ 1 x x 36 2013-06-19 01:40 go2.sh
-rwx------ 1 x x 54 2013-06-19 01:41 go.sh
-rw-rw-r-- 1 x x 1081 2013-06-19 01:39 main.cpp
-rwxrwxr-x 1 x x 2140238 2013-06-19 01:15 perft4
-rwxrwxr-x 1 x x 19042 2013-06-19 01:39 suniq
-rw-rw-r-- 1 x x 289 2013-06-19 00:47 suniq.pro
-rw-rw-r-- 1 x x 15264 2013-06-19 01:19 suniq.pro.user
x@biglaptop:~/Dokumenty/c/suniq$ cat go1.sh
cat data.txt | sort | uniq -c | sort -nr > out1.txt
x@biglaptop:~/Dokumenty/c/suniq$ time ./go1.sh
real 1m14.931s
user 1m16.465s
sys 0m1.880s
x@biglaptop:~/Dokumenty/c/suniq$ cat go2.sh
cat data.txt | ./suniq r > out2.txt
x@biglaptop:~/Dokumenty/c/suniq$ time ./go2.sh
real 0m8.541s
user 0m8.053s
sys 0m0.800s
x@biglaptop:~/Dokumenty/c/suniq$ ls -l
razem 393324
-rw-rw-r-- 1 x x 289969208 2013-06-19 01:42 data.txt
-rwx------ 1 x x 52 2013-06-19 01:40 go1.sh
-rwx------ 1 x x 36 2013-06-19 01:40 go2.sh
-rwx------ 1 x x 54 2013-06-19 01:41 go.sh
-rw-rw-r-- 1 x x 1081 2013-06-19 01:39 main.cpp
-rw-rw-r-- 1 x x 55292061 2013-06-19 01:44 out1.txt
-rw-rw-r-- 1 x x 55292061 2013-06-19 01:44 out2.txt
-rwxrwxr-x 1 x x 2140238 2013-06-19 01:15 perft4
-rwxrwxr-x 1 x x 19042 2013-06-19 01:39 suniq
-rw-rw-r-- 1 x x 289 2013-06-19 00:47 suniq.pro
-rw-rw-r-- 1 x x 15264 2013-06-19 01:19 suniq.pro.user
x@biglaptop:~/Dokumenty/c/suniq$ head out1.txt
87 rnbqkbnr/pppppppp/8/8/8/4P3/PPPP1PPP/RNBQKBNR b qkQK -
87 rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b qkQK -
79 rnbqkbnr/pppppppp/8/8/3P4/8/PPP1PPPP/RNBQKBNR b qkQK -
75 rnbqkbnr/pppppppp/8/8/8/3P4/PPP1PPPP/RNBQKBNR b qkQK -
56 rnbqkbnr/pppppppp/8/8/8/6P1/PPPPPP1P/RNBQKBNR b qkQK -
56 rnbqkbnr/pppppppp/8/8/8/1P6/P1PPPPPP/RNBQKBNR b qkQK -
56 rnbqkbnr/pppppppp/8/8/6P1/8/PPPPPP1P/RNBQKBNR b qkQK -
56 rnbqkbnr/pppppppp/8/8/2P5/8/PP1PPPPP/RNBQKBNR b qkQK -
56 rnbqkbnr/pppppppp/8/8/1P6/8/P1PPPPPP/RNBQKBNR b qkQK -
52 rnbqkbnr/pppppppp/8/8/8/5N2/PPPPPPPP/RNBQKB1R b qkQK -
x@biglaptop:~/Dokumenty/c/suniq$ head out2.txt
87 rnbqkbnr/pppppppp/8/8/8/4P3/PPPP1PPP/RNBQKBNR b qkQK -
87 rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b qkQK -
79 rnbqkbnr/pppppppp/8/8/3P4/8/PPP1PPPP/RNBQKBNR b qkQK -
75 rnbqkbnr/pppppppp/8/8/8/3P4/PPP1PPPP/RNBQKBNR b qkQK -
56 rnbqkbnr/pppppppp/8/8/2P5/8/PP1PPPPP/RNBQKBNR b qkQK -
56 rnbqkbnr/pppppppp/8/8/8/6P1/PPPPPP1P/RNBQKBNR b qkQK -
56 rnbqkbnr/pppppppp/8/8/6P1/8/PPPPPP1P/RNBQKBNR b qkQK -
56 rnbqkbnr/pppppppp/8/8/8/1P6/P1PPPPPP/RNBQKBNR b qkQK -
56 rnbqkbnr/pppppppp/8/8/1P6/8/P1PPPPPP/RNBQKBNR b qkQK -
52 rnbqkbnr/pppppppp/8/8/8/2N5/PPPPPPPP/R1BQKBNR b qkQK -
x@biglaptop:~/Dokumenty/c/suniq$ cat main.cpp
//Listing całego programu:
#include <cstdio>
#include <cstring>
#include <QHash>
#include <QVector>
#include <QtAlgorithms>
#define MAX_ROW (1024*1024)
struct TData {
QString str;
int cnt;
};
bool lessThatA( const TData &a , const TData &b ) {
return a.cnt > b.cnt;
}
bool lessThatB( const TData &a , const TData &b ) {
return b.cnt < a.cnt;
}
int main( int argc, char *argv[] ) {
QHash<QString,int> hash;
QVector<TData> data;
FILE *f = stdin; // TODO if_exists(argv,file) ? fopen(file) : stdin;
char *buf = new char[MAX_ROW];
while( fgets( buf , MAX_ROW , f ) ) {
QString s(buf);
if( hash.contains(s) ) {
data[ hash[s] ].cnt ++ ;
} else {
hash.insert( s , data.size() );
TData tmp;
tmp.str = s;
tmp.cnt = 1;
data.append( tmp );
}
}
qSort( data.begin() , data.end() , argc > 1 && strstr( argv[1] , "r" ) ? lessThatA : lessThatB );
for( int i=0 ; i<data.size() ; i++ )
printf("%7d %s" , data[i].cnt , qPrintable(data[i].str) );
// delete[] buf;
// for( int i=0 ; i<data.size() ; i++ )
// free( data[i].str );
if( f != stdin ) fclose(f);
return 0;
}
Pozdrawiam
Pięknie, skompilowałem, a teraz test.
Bez dodatkowych okrążeń na UTF-8 dla sorta i uniq, tylko uczciwie, na tych samych zasadach, ograniczmy się do kodu Ascii. Skoro twoja wersja suniq nie obsługuje.
LC_ALL=C sort |LC_ALL=C uniq -c | LC_ALL=C sort -nr > out1.txt
U mnie nadal sort, uniq jest ponad dwukrotnie szybszy.
Cytat: buninek w 19 Czerwiec 2013, 02:53
Pięknie, skompilowałem, a teraz test.
Bez dodatkowych okrążeń na UTF-8 dla sorta i uniq, tylko uczciwie, na tych samych zasadach, ograniczmy się do kodu Ascii. Skoro twoja wersja suniq nie obsługuje.
LC_ALL=C sort |LC_ALL=C uniq -c | LC_ALL=C sort -nr > out1.txt
U mnie nadal sort, uniq jest ponad dwukrotnie szybszy.
Ja też nic nie optymalizowałem, obliczenia były na utf-16.
Żeby konwertował z utf-8 na utf-16 i potem z powrotem, to
trzeba dodać małą poprawkę:
#include <QHash>
#include <QVector>
#include <QtAlgorithms>
#include <QTextStream>
struct TData {
QString str;
int cnt;
};
bool lessThatA( const TData &a , const TData &b ) {
return a.cnt > b.cnt;
}
bool lessThatB( const TData &a , const TData &b ) {
return b.cnt < a.cnt;
}
int main( int argc, char *argv[] ) {
QHash<QString,int> hash;
QVector<TData> data;
QString s;
QTextStream in(stdin);
in.setCodec("UTF-8");
while( ! (s = in.readLine()).isNull() ) {
if( hash.contains(s) ) {
data[ hash[s] ].cnt ++ ;
} else {
hash.insert( s , data.size() );
TData tmp;
tmp.str = s;
tmp.cnt = 1;
data.append( tmp );
}
}
qSort( data.begin() , data.end() , argc > 1 && strstr( argv[1] , "r" ) ? lessThatA : lessThatB );
QTextStream out(stdout);
out.setCodec("UTF-8");
for( int i=0 ; i<data.size() ; i++ ) {
out<<qSetFieldWidth(7)<<data[i].cnt<<qSetFieldWidth(0)<<" "<<data[i].str<<"\n";
}
return 0;
}
U mnie nadal 7-8 razy szybciej niż:
cat data.txt | sort -S2000000 | uniq -c | sort -S2000000 -nr > out1.txt
Może mam starą wersję sort, uniq i cat...
sort --version
sort (GNU coreutils) 8.5
Copyright (C) 2010 Free Software Foundation, Inc.
Licencja GPLv3+: GNU GPL wersja 3 albo późniejsza http://gnu.org/licenses/gpl.html
To jest wolne oprogramowanie: masz prawo je zmieniać i rozpowszechniać.
Autorzy nie dają ŻADNYCH GWARANCJI w granicach dozwolonych prawem.
Autorzy: Mike Haertel i Paul Eggert.
Pozdrawiam
Cytat: mariotti w 18 Czerwiec 2013, 23:10
...
I teraz moje pytanie: czy powyższy kod jest wydajny? Czy takie ciągłe cofanie o jeden rekord jest szybkie?
Czy może lepiej przeanalizować w porcjach po 10k rekordów, cofnąć wskaźnik pliku o rozmiar całej
porcji i zapisać całą porcję?
Na pewno szybciej będzie wczytać porcję danych do pamięci obrobić i zapisać niż pojedynczo linia po linii.
Odpada ileś-set razy czas dostępu do danych na dysku co w rezultacie może się przełożyć na -naście/-dziesiąt sekund.
Rozwiązanie na bazie skryptu powłoki Linux działa bardzo wydajnie. Dla depth=7
obliczenia trwały zaledwie 412minut. Przy depth=7 trzeba dwa razy posortować
aż 3.2mld wierszy, więc czas rewelacyjny. Niestety ilość unikalnych wierszy zupełnie
nie zgadza się z ilością oczekiwaną. Gdzieś jest błąd, prawdopodobnie w programie perft4.
Program perft4 był dobrze przetestowany, więc błąd jest jakiś dziwny. Niemniej mam
pomysł na napisanie testu, który powinien dokładnie wskazać miejsca, w których
ten dziwny błąd się uaktywnia. Więc pomimo kolejnego potknięcia, jestem nadal
dobrej myśli :)
Pozdrawiam
/usr/bin/file input
input: ASCII text
Doprawdy nie ma sensu zmuszać sorta do pracy na pełnym zakresie UTF-8, aby udowodnić, że wtedy działa 7-8x wolniej.
/usr/bin/file input-utf
input-utf: UTF-8 Unicode English text
W tym przypadku takie działanie jest wręcz konieczne. Wyniki testów są bardzo różne w zależności od danych wejściowych. Bez wątpienia sort nie jest najszybszym programem nie mam do tego żadnych wątpliwości. Jego pole działania i możliwości są zupełnie inne.
Twoja wersja jest bardzo stara, ale wątpię aby nowszy sort (GNU coreutils) 8.20 był odrobinę szybszy.
Cytat: mariotti w 19 Czerwiec 2013, 12:58
Niestety ilość unikalnych wierszy zupełnie
nie zgadza się z ilością oczekiwaną. Gdzieś jest błąd, prawdopodobnie w programie perft4.
Jeśli numeracja wieszy jest niepełna wtedy zmienia się zakres sortowania.
Cytat: buninek w 19 Czerwiec 2013, 13:55
/usr/bin/file input
input: ASCII text
Doprawdy nie ma sensu zmuszać sorta do pracy na pełnym zakresie UTF-8, aby udowodnić, że wtedy działa 7-8x wolniej.
/usr/bin/file input-utf
input-utf: UTF-8 Unicode English text
W tym przypadku takie działanie jest wręcz konieczne. Wyniki testów są bardzo różne w zależności od danych wejściowych. Bez wątpienia sort nie jest najszybszym programem nie mam do tego żadnych wątpliwości. Jego pole działania i możliwości są zupełnie inne.
W ogóle nie chcę udowodnić że sort jest wolnym programem, tylko
chcę pokazać, że specjalistyczny program musi zadziałać szybciej.
Dlatego tak bardzo się zdziwiłem, że tamten program działał 3 razy
wolniej. Chodzi o to, że wyciąganie unikalnych wierszy można
zrealizować zupełnie innym algorytmem niż sortowanie i dlatego ten
inny zadziała szybciej niż sort.
Moja implementacja jest bardzo niechlujna, można w niej jeszcze
wiele poprawić:
a) przejście z utf na ascii
b) usunięcie zdublowanych danych, teraz są dwie kopie wierszy,
c) przydział pamięci dużymi blokami
A pomimo tego, na moim kompie jest 7-8 razy szybsza. Gdy daję
przed shellowym sort i uniq C_ALL=C to na moim kompie działa jakby
jeszcze o kilka sekund wolniej. Nie wiem dlaczego.
Cytat: buninek w 19 Czerwiec 2013, 13:55
Twoja wersja jest bardzo stara, ale wątpię aby nowszy sort (GNU coreutils) 8.20 był odrobinę szybszy.
Cytat: buninek w 19 Czerwiec 2013, 13:55
Jeśli numeracja wieszy jest niepełna wtedy zmienia się zakres sortowania.
Używam takiego skryptu:
depth=$1
(
echo printLeafs $depth
echo quit
) | ./perft4 | nl | LC_ALL=C sort -t$'\t' -k2 -T'./tmp' -S1000000 | uniq -c -f1 | LC_ALL=C sort -n -k2 -T'./tmp' -S1000000 > out.txt
wc -l out.txt
To jest pełna numeracja czy nie?
Pozdrawiam
Twoja wersja suniq jest szybsza od tej STL-owej i na moim kompie wolniejsza od sort-uniq w zakresie ASCII. Różnica między ASCII a UTF-8.
file input
input: ASCII text
env | grep LANG
LANG=pl_PL.UTF-8
time sort input | uniq -c | sort -nr > out
0m53.61s real 0m52.64s user 0m0.76s system
time LC_ALL=C sort input | LC_ALL=C uniq -c | LC_ALL=C sort -nr > out
0m6.21s real 0m5.29s user 0m0.88s system
W zakresie UTF-8 jest szybsza ok 1.7x, ale sposób prezentacji jej wyników jest mało użyteczny, wręcz nieprzydatny . Ostateczny wynik posortowany jest numerycznie tylko po pierwszym polu, drugie pole jest całkowicie nieuporządkowane.
Numeracji linii nie sprawdzałem, pisałem kilka wątków wcześniej jak w miarę szybko sprawdzić. Choć przy systemie x86_64 nie powinno być niespodzianek.
cat -n jest chyba szybszy od nl.
time seq 1 119060324 | nl > /dev/null
time seq 1 119060324 | cat -n > /dev/null
Edit:
Wcześniejsze moje uwagi dotyczyły wersji sort, uniq z coreutils-8.10, okazuje się że jest jednak ogromna różnica z wersją coreutils-8.20.
- w nowszym sortowanie w zakresie UTF-8 jest szybsze ok 3x,
- automatycznie dobierany jest optymalny zakres, nie trzeba zmieniać zmiennych lokalizacyjnych, typu LC_ALL=C
Cytat: buninek w 19 Czerwiec 2013, 22:23
Twoja wersja suniq jest szybsza od tej STL-owej i na moim kompie wolniejsza od sort-uniq w zakresie ASCII. Różnica między ASCII a UTF-8.
Zabrnęliśmy w straszny szczegół :) Szybkość mojego suniq zależy od
wielu czynników:
1) wersja biblioteki qt
2) od tego czy użyto qt w wersji debug czy release
3) od tego jakim kompilatorem była skompilowana biblioteka qt
4) od sposobu kompilacji samego programu
5) od ilości wierszy - mój suniq jest niechlujnie napisany (ma tzw duży
narzut liniowy); ktoś kto pisał sort na pewno włożył wiele dni pracy w
zmniejszenie narzutu liniowego, ja suniq pisałem może 30 minut.
Na moim kompie suniq na ascii działa 13 razy szybciej:
cat go1.sh
cat data.txt | C_ALL=C sort -S2000000 | C_ALL=C uniq -c | C_ALL=C sort -S2000000 -nr > out1.txt
time ./go1.sh
real 1m18.829s user 1m18.565s sys 0m1.392s
cat ./go2.sh
cat data.txt | ./suniq r > out2.txt
./go2.sh
time ./go2.sh
real 0m6.060s user 0m5.696s sys 0m0.792s
ls -l
-rw-rw-r-- 1 x x 289969208 2013-06-19 01:42 data.txt
-rwx------ 1 x x 96 2013-06-19 15:00 go1.sh
-rwx------ 1 x x 36 2013-06-19 01:40 go2.sh
-rw-rw-r-- 1 x x 55292061 2013-06-19 22:53 out1.txt
-rw-rw-r-- 1 x x 55292061 2013-06-19 22:54 out2.txt
Źródło wersji na ascii, można w nim jeszcze dużo ulepszyć, to
jest cały czas taki program na kolanie :)
#include <cstring>
#include <cstdio>
#include <QHash>
#include <QVector>
#include <QtAlgorithms>
#include <QTextStream>
struct TData {
char* str;
int cnt;
};
bool operator==( const TData &a , const TData &b ) {
return strcmp(a.str,b.str)==0;
}
bool lessThatA( const TData *a , const TData *b ) {
return a->cnt > b->cnt;
}
bool lessThatB( const TData *a , const TData *b ) {
return b->cnt < a->cnt;
}
uint qHash( const TData &d ) {
const static uint keys[] = {1144700546,221718428,3154688750,371537357,2204050889,1370979008,3321622132,2725480991,3840323144,3287424469,2776693720,4189889840,2357009355,182334614,1137760547,2900706147,3348220913,3247080425,2942765694,2091459760,3590858303,1290645046,1554428098,463533191,3969044147,1250249148,2989244349,1456428351,3857024942,4147237429,173332611,2149971405,2137831619,3217748225,1903294001,4207362380,4259294664,66392448,3071101674,54014783,3967985131,3366669718,2419662148,663421279,790981550,1731337085,2753511525,1588025203,2471176956,3160209272,1951241493,1184684183,3245719876,1093248988,1541818600,2629471904,825230777,317558013,3112647458,1459626771,3256448485,84165149,711060106,851909497,509867808,2788249988,2690693260,3254214876,4085518806,3740895315,3959970419,2518601845,1270121159,1626531539,2063618718,2285762738,1568456969,3158013257,1185432784,3705456404,489197897,377297527,529628780,2175258231,3655214223,1788156313,1907375709,1313704965,2506847518,4239124880,3743104360,2606809867,2171879399,3068856920,1294506824,1184593192,2094794731,1501071601,3510146245,1080924504,834790104,887598572,1921060681,1907957125,384668965,3832505886,1404479738,429073217,4048180485,1277571586,3351160641,3929569221,721495309,2249158795,1507443992,4017319401,3319905986,839976944,1962528687,1398747462,3799998551,3916009169,1044595540,1932375984,1714949749,3315091734,1614450969,448043715,3439145978,397764290,1532361130,651068336,2827749266,1785537617,2043390134,1033076546,1946784178,2727133176,1778246073,4153396324,631184595,4136570176,4168112821,2352350170,2365669525,3106901503,3559075183,3452679161,267545551,772178552,3072751325,256138618,2644329885,1129762003,4095244794,4240565036,3339433038,334828086,80419977,370347897,699707733,2020346493,2976679044,3064802920,427669986,1428976588,156891279,1545628935,2626081822,1679094495,3742728311,2442576814,1219105916,396285832,3609262031,2201174116,4095719957,609760429,1661234868,2935331633,955752368,1162843510,4061950093,3329577137,3099235594,2128352201,3001147777,744609404,3966064758,2066920942,3597487909,2879251104,1097029495,3971956586,2644484385,4006215800,1205546841,180489701,4242616412,2326232595,1103825622,1798146890,2752105516,647156941,3916328196,3639882107,1960105313,721386580,3530279815,2185140566,858146661,559528220,2718615335,1518010104,684609492,1414712780,3995516568,3161547863,3387987884,2028620113,169538833,3362100723,2985309157,2567324161,1485319169,1041627537,3792110993,1616573006,3681252839,4037267467,94540548,3617564886,1731143893,3013952545,2559946057,2281304224,2145511259,616739264,3889211381,1538154866,1679636709,4094920003,3916479913,1052735971,566141280,1212514386,2586777127,1593236856,1505891350,1146017434,1999486611,2578902328,3787093134,472449269,2411157526,2911776849};
uint x = 123;
for( uint i=0 ; d.str[i] ; i++ )
x ^= keys[ ((uint)d.str[i]+i) % 256 ] ;
return x;
}
int main( int argc, char *argv[] ) {
QHash<TData,TData*> hash;
QVector<TData*> data;
char *buf = new char[1024*1024];
TData tmp;
tmp.str = buf;
tmp.cnt = 0;
while( fgets( buf , 1024*1024 , stdin ) ) {
if( hash.contains( tmp ) ) {
hash[tmp]->cnt ++ ;
} else {
TData *tmp = new TData;
tmp->str = strdup(buf);
tmp->cnt = 1;
hash[*tmp] = tmp;
data.append( tmp );
}
}
qSort( data.begin() , data.end() , argc > 1 && strstr( argv[1] , "r" ) ? lessThatA : lessThatB );
for( int i=0 ; i<data.size() ; i++ ) {
printf("%7d %s" , data[i]->cnt , data[i]->str );
free( data[i]->str );
delete data[i];
}
return 0;
}
Cytat
time sort input | uniq -c | sort -nr > out
0m53.61s real 0m52.64s user 0m0.76s system
Czyli wersja shell-unicode 53s
Cytat
time LC_ALL=C sort input | LC_ALL=C uniq -c | LC_ALL=C sort -nr > out
0m6.21s real 0m5.29s user 0m0.88s system
Wersja shell-ascii ponad 6 sekund. Ciekawe dlaczego na moim
komputerze wersja ascii działa tak samo szybko jak unicode. Na
Twoim różnica jest ogromna.
Cytat
W zakresie UTF-8 jest szybsza ok 1.7x, ale sposób prezentacji jej wyników jest mało użyteczny, wręcz nieprzydatny . Ostateczny wynik posortowany jest numerycznie tylko po pierwszym polu, drugie pole jest całkowicie nieuporządkowane.
Nie było w treści zadania że ma być posortowane po obu polach. Chyba systemowe sort
też ma prawo podać nieuporządkowane po drugim polu. Trzeba
użyć opcji --stable żeby została zachowana kolejność z pierwszego sortowania.
Ale... coś mnie jeszcze tknęło, sprawdziłem i widzę, że systemowe sort pracuje
na wszystkich rdzeniach, jest wielowątkowe! Czyli na moim kompie, na
dużej ilości wierszy, mój niechlujny(!) suniq działa 12-13 razy szybciej na
jednym wątku, niż rozwiązanie shellowe na 2 + 2hyper!
No ale jeszcze wersja z sortowaniem wielokryterialnym:
#include <cstring>
#include <cstdio>
#include <QHash>
#include <QVector>
#include <QtAlgorithms>
struct TData {
char* str;
int cnt;
};
bool operator==( const TData &a , const TData &b ) {
return strcmp(a.str,b.str)==0;
}
bool lessThatA( const TData *a , const TData *b ) {
if( a->cnt != b->cnt )
return a->cnt > b->cnt;
return strcmp( a->str , b->str ) > 0;
}
bool lessThatB( const TData *a , const TData *b ) {
if( a->cnt != b->cnt )
return a->cnt < b->cnt;
return strcmp( a->str , b->str ) < 0;
}
uint qHash( const TData &d ) {
const static uint keys[] = {1144700546,221718428,3154688750,371537357,2204050889,1370979008,3321622132,2725480991,3840323144,3287424469,2776693720,4189889840,2357009355,182334614,1137760547,2900706147,3348220913,3247080425,2942765694,2091459760,3590858303,1290645046,1554428098,463533191,3969044147,1250249148,2989244349,1456428351,3857024942,4147237429,173332611,2149971405,2137831619,3217748225,1903294001,4207362380,4259294664,66392448,3071101674,54014783,3967985131,3366669718,2419662148,663421279,790981550,1731337085,2753511525,1588025203,2471176956,3160209272,1951241493,1184684183,3245719876,1093248988,1541818600,2629471904,825230777,317558013,3112647458,1459626771,3256448485,84165149,711060106,851909497,509867808,2788249988,2690693260,3254214876,4085518806,3740895315,3959970419,2518601845,1270121159,1626531539,2063618718,2285762738,1568456969,3158013257,1185432784,3705456404,489197897,377297527,529628780,2175258231,3655214223,1788156313,1907375709,1313704965,2506847518,4239124880,3743104360,2606809867,2171879399,3068856920,1294506824,1184593192,2094794731,1501071601,3510146245,1080924504,834790104,887598572,1921060681,1907957125,384668965,3832505886,1404479738,429073217,4048180485,1277571586,3351160641,3929569221,721495309,2249158795,1507443992,4017319401,3319905986,839976944,1962528687,1398747462,3799998551,3916009169,1044595540,1932375984,1714949749,3315091734,1614450969,448043715,3439145978,397764290,1532361130,651068336,2827749266,1785537617,2043390134,1033076546,1946784178,2727133176,1778246073,4153396324,631184595,4136570176,4168112821,2352350170,2365669525,3106901503,3559075183,3452679161,267545551,772178552,3072751325,256138618,2644329885,1129762003,4095244794,4240565036,3339433038,334828086,80419977,370347897,699707733,2020346493,2976679044,3064802920,427669986,1428976588,156891279,1545628935,2626081822,1679094495,3742728311,2442576814,1219105916,396285832,3609262031,2201174116,4095719957,609760429,1661234868,2935331633,955752368,1162843510,4061950093,3329577137,3099235594,2128352201,3001147777,744609404,3966064758,2066920942,3597487909,2879251104,1097029495,3971956586,2644484385,4006215800,1205546841,180489701,4242616412,2326232595,1103825622,1798146890,2752105516,647156941,3916328196,3639882107,1960105313,721386580,3530279815,2185140566,858146661,559528220,2718615335,1518010104,684609492,1414712780,3995516568,3161547863,3387987884,2028620113,169538833,3362100723,2985309157,2567324161,1485319169,1041627537,3792110993,1616573006,3681252839,4037267467,94540548,3617564886,1731143893,3013952545,2559946057,2281304224,2145511259,616739264,3889211381,1538154866,1679636709,4094920003,3916479913,1052735971,566141280,1212514386,2586777127,1593236856,1505891350,1146017434,1999486611,2578902328,3787093134,472449269,2411157526,2911776849};
uint x = 123;
for( uint i=0 ; d.str[i] ; i++ )
x ^= keys[ ((uint)d.str[i]+i) % 256 ] ;
return x;
}
int main( int argc, char *argv[] ) {
QHash<TData,TData*> hash;
QVector<TData*> data;
char *buf = new char[1024*1024];
TData tmp;
tmp.str = buf;
tmp.cnt = 0;
while( fgets( buf , 1024*1024 , stdin ) ) {
if( hash.contains( tmp ) ) {
hash[tmp]->cnt ++ ;
} else {
TData *tmp = new TData;
tmp->str = strdup(buf);
tmp->cnt = 1;
hash[*tmp] = tmp;
data.append( tmp );
}
}
qSort( data.begin() , data.end() , argc > 1 && strstr( argv[1] , "r" ) ? lessThatA : lessThatB );
delete[] buf;
for( int i=0 ; i<data.size() ; i++ ) {
printf("%7d %s" , data[i]->cnt , data[i]->str );
free( data[i]->str );
delete data[i];
}
return 0;
}
Spowolnienie w granicach błędu pomiaru.
Cytat
Numeracji linii nie sprawdzałem, pisałem kilka wątków wcześniej jak w miarę szybko sprawdzić. Choć przy systemie x86_64 nie powinno być niespodzianek.
cat -n jest chyba szybszy od nl.
time seq 1 119060324 | nl > /dev/null
time seq 1 119060324 | cat -n > /dev/null
Ja jestem ciekawy jak szybko zadziała pełna wersja programu do
optymalizacji work-units. Przy niej trochę się pomęczę, gdyż będzie
wiele razy potrzebna. Optymalizacja suniq też jest ciekawym zadaniem, ale
chyba taki program nie jest nikomu potrzebny.
Pozdrawiam
Cóż to za zmienna
CytatC_ALL=C
i w jakim celu ją dodajesz przed sortem XD?
Polecam zaktualizować coreutils do wersji 8.20.
Jak widać trudno o miarodajny test. U mnie twoja wersja obecnie przegrywa ponad 2x z sortem z coreutils-8.20 na procesorze jednordzeniowym.
Qt w wersji 4.8.4 kompilowane z pomocą g++-4.7.0, NODEBUG.
Qt w systemie ma tylko w sumie dla Qt-webkita.
Cytat: buninek w 19 Czerwiec 2013, 23:49
Cóż to za zmienna
CytatC_ALL=C
i w jakim celu ją dodajesz przed sortem XD?
Miałem błąd. Po poprawieniu moja wersja jest tylko dwa razy szybsza.
Cytat: buninek w 19 Czerwiec 2013, 23:49
Polecam zaktualizować coreutils do wersji 8.20.
dałem apt-get install coreutils i krzyczy że jest już w najnowszej wersji.
Cytat: buninek w 19 Czerwiec 2013, 23:49
Jak widać trudno o miarodajny test. U mnie twoja wersja obecnie przegrywa ponad 2x z sortem z coreutils-8.20.
Ale można wykonać miarodajną analizę. Wersja shell dwa razy sortuje i raz przegląda całość, aby
odrzucić powtórki. Przed odrzuceniem jest N wierszy, po odrzuceniu jest M. Czyli mamy
N*LogN + N + M*LogM. Moja wersja dodaje do hash-table i raz sortuje unikalne, czyli
M*LogM + N. Widać gołym okiem która wersja jest lepsza, nie trzeba nic testować. Dla
specyficznych danych, np. gdy M=N, albo gdy N jest małe, różnica będzie pomijalnie
mała. Ale podstaw do wzoru gdy N=100kk, a M=1kk.
Poza tym istnieje jeszcze jeden specjalistyczny algorytm dla tego zadania, żeruje on na
wiedzy o tym, że w ilość powtórzeń różnych wierszy jest podobna, np. wiersze powtarzają się
tylko 10, 15 albo 30 razy. Niestety ten algorytm, tak jak każdy specjalistyczny algorytm,
zadziała wolniej w ogólnym przypadku.
To wersja na kolanie tego programu:
#include <cstring>
#include <cstdio>
#include <QHash>
#include <QVector>
#include <QtAlgorithms>
struct TData {
char* str;
int cnt;
};
bool operator==( const TData &a , const TData &b ) {
return strcmp(a.str,b.str)==0;
}
uint qHash( const TData &d ) {
const static uint keys[] = {1144700546,221718428,3154688750,371537357,2204050889,1370979008,3321622132,2725480991,3840323144,3287424469,2776693720,4189889840,2357009355,182334614,1137760547,2900706147,3348220913,3247080425,2942765694,2091459760,3590858303,1290645046,1554428098,463533191,3969044147,1250249148,2989244349,1456428351,3857024942,4147237429,173332611,2149971405,2137831619,3217748225,1903294001,4207362380,4259294664,66392448,3071101674,54014783,3967985131,3366669718,2419662148,663421279,790981550,1731337085,2753511525,1588025203,2471176956,3160209272,1951241493,1184684183,3245719876,1093248988,1541818600,2629471904,825230777,317558013,3112647458,1459626771,3256448485,84165149,711060106,851909497,509867808,2788249988,2690693260,3254214876,4085518806,3740895315,3959970419,2518601845,1270121159,1626531539,2063618718,2285762738,1568456969,3158013257,1185432784,3705456404,489197897,377297527,529628780,2175258231,3655214223,1788156313,1907375709,1313704965,2506847518,4239124880,3743104360,2606809867,2171879399,3068856920,1294506824,1184593192,2094794731,1501071601,3510146245,1080924504,834790104,887598572,1921060681,1907957125,384668965,3832505886,1404479738,429073217,4048180485,1277571586,3351160641,3929569221,721495309,2249158795,1507443992,4017319401,3319905986,839976944,1962528687,1398747462,3799998551,3916009169,1044595540,1932375984,1714949749,3315091734,1614450969,448043715,3439145978,397764290,1532361130,651068336,2827749266,1785537617,2043390134,1033076546,1946784178,2727133176,1778246073,4153396324,631184595,4136570176,4168112821,2352350170,2365669525,3106901503,3559075183,3452679161,267545551,772178552,3072751325,256138618,2644329885,1129762003,4095244794,4240565036,3339433038,334828086,80419977,370347897,699707733,2020346493,2976679044,3064802920,427669986,1428976588,156891279,1545628935,2626081822,1679094495,3742728311,2442576814,1219105916,396285832,3609262031,2201174116,4095719957,609760429,1661234868,2935331633,955752368,1162843510,4061950093,3329577137,3099235594,2128352201,3001147777,744609404,3966064758,2066920942,3597487909,2879251104,1097029495,3971956586,2644484385,4006215800,1205546841,180489701,4242616412,2326232595,1103825622,1798146890,2752105516,647156941,3916328196,3639882107,1960105313,721386580,3530279815,2185140566,858146661,559528220,2718615335,1518010104,684609492,1414712780,3995516568,3161547863,3387987884,2028620113,169538833,3362100723,2985309157,2567324161,1485319169,1041627537,3792110993,1616573006,3681252839,4037267467,94540548,3617564886,1731143893,3013952545,2559946057,2281304224,2145511259,616739264,3889211381,1538154866,1679636709,4094920003,3916479913,1052735971,566141280,1212514386,2586777127,1593236856,1505891350,1146017434,1999486611,2578902328,3787093134,472449269,2411157526,2911776849};
uint x = 123;
for( uint i=0 ; d.str[i] ; i++ )
x ^= keys[ ((uint)d.str[i]+i) % 256 ] ;
return x;
}
int main( int argc, char *argv[] ) {
QHash<TData,TData*> hash;
QHash<int,TData*> hash2;
QVector<TData*> data;
char *buf = new char[1024*1024];
TData tmp;
tmp.str = buf;
tmp.cnt = 0;
while( fgets( buf , 1024*1024 , stdin ) ) {
if( hash.contains( tmp ) ) {
hash[tmp]->cnt ++ ;
} else {
TData *tmp = new TData;
tmp->str = strdup(buf);
tmp->cnt = 1;
hash[*tmp] = tmp;
data.append( tmp );
}
}
for( int i=0 ; i<data.size() ; i++ ) {
hash2.insertMulti(data[i]->cnt , data[i] );
}
QList<int> keys = hash2.uniqueKeys();
if( argc > 1 && strstr( argv[1] , "r" ) )
qSort( keys.begin() , keys.end() , qGreater<int>() );
else
qSort( keys.begin() , keys.end() , qLess<int>() );
for( int i=0 ; i<keys.size() ; i++ ) {
QList<TData*> vals = hash2.values( keys[i] );
for( int j=0 ; j<vals.size() ; j++ )
printf("%7d %s" , vals[j]->cnt , vals[j]->str );
}
return 0;
}
A jeszcze co do testów, to warto zwrócić uwagę, że moja wersja powstała w 30 minut, a
narzędzia coreutils są udoskonalane od nastu lat. Jak sądzisz, który algorytm będzie
szybszy, jeśli w obu przypadkach włoży się tyle samo pracy? Ten który raz sortuje, czy
ten który dwa razy sortuje?
Pozdrawiam
Cytat: buninek w 19 Czerwiec 2013, 23:49
Qt w wersji 4.8.4 kompilowane z pomocą g++-4.7.0, NODEBUG.
Qt w systemie ma tylko w sumie dla Qt-webkita.
A opcje z serii -O3, no_frame_pointers były ustawione?
A narzędzia z serii PGO były użyte?
A march było ustawione?
A wykorzystanie szerokich rejestrów i wstawki asemblerowe moja wersja ma?
W systemowym sort prawdopodobnie ktoś o to wszystko zadbał. Na dłuższą
metę moja wersja wygra zawsze bo sortuje jeden raz a nie dwa razy.
Pozdrawiam
Tobie się nie chce sprofilować sorta w najnowszej wersji tylko używasz jakiegoś zabytku, a mnie się dopytujesz czy ja mam QT odpowiednio zbudowane.
Debian i profilowanie. Pewnie jakiś antyk, typu lenny. Żadna dystrybucja tego nie robi.
Profilować można pod konkretny model procesora na przykład dystrybucję pod Raspberry Pi, wydanie Androida pod konkretny model telefonu.
Wiele programów, bibliotek tego potrzebujących możesz zawsze sobie zbudować na własną modłę z pełnym profilowaniem pod swój procesor.
Trzy minuty
cd /tmp
cd /tmp
wget ftp://ftp.gnu.org/gnu/coreutils/coreutils-8.21.tar.xz
tar xJf coreutils-8.21.tar.xz
cd coreutils-8.21
ustaw swoje CFLAGS
export CFLAGS=""
./configure --prefix=$HOME/test/coreutils --libexecdir=$HOME/test/coreutils/lib
make
make RUN_EXPENSIVE_TESTS=yes check
make DESTDIR=/tmp/coreutils-8.21-install install
Cytat: buninek w 20 Czerwiec 2013, 02:23
Tobie się nie chce sprofilować sorta w najnowszej wersji tylko używasz jakiegoś zabytku, a mnie się dopytujesz czy ja mam QT odpowiednio zbudowane.
Debian i profilowanie. Pewnie jakiś antyk, typu lenny. Żadna dystrybucja tego nie robi.
Nie dopytuję się po to, abyś instalował, czy zadał sobie jeszcze większy trud optymalizacji
programu, ale po to żebyś spróbował przez chwilę
mojego toku rozumowania. Naprawdę
uprawiamy bezsensowną rozmowę od kilku postów, nic z niej nie wyniknie dobrego dla żadnego
z nas. W tej chwili robimy coś takiego: jeden z nas mówi:
- mercedes jest lepszy od syrenki
- syrenka jest lepsza - przeczy drugi
- dlaczego syrenka jest lepsza?
- bo syrenka mniej waży.
Jeśli chcesz powiedzieć że sort jest wydajnym narzędziem, to ja nigdy temu nie przeczyłem,
więc
nie ma sensu abyś mi to udowadniał. Ja tylko twierdzę że sortowanie
jednokrotnejest szybsze niż
dwukrotne. A program który napisałem to potwierdza, bo pomimo tego
iż napisałem go na kolanie, wygrywa, albo prawie wygrywa z potokiem: sort | uniq | sort.
Ta dyskusja nie ma sensu z jeszcze jednego powodu: już wiemy, że dla depth=7 rozwiązanie
na coreutils jest zadowalające. Jeśli jest zadowalające, to szkoda naszego czasu na
ulepszenia. Z kolei dla depth=8 rozwiązanie na coreutils jest niedopuszczalne, bo będzie potrzebowało
8-10TB danych - a mi na początkowym etapie tego projektu szkoda pieniędzy na zakup macierzy.
Więc jeśli będę chciał zrobić work-units dla depth=8, to i tak i tak będę musiał posłużyć
się specjalistycznym programem.
Cytat: buninek w 20 Czerwiec 2013, 02:23
Profilować można pod konkretny model procesora na przykład dystrybucję pod Raspberry Pi,
wydanie Androida pod konkretny model telefonu.
Wiele programów, bibliotek tego potrzebujących możesz zawsze sobie zbudować na własną modłę z pełnym profilowaniem pod swój procesor.
Można. Ale teraz będę potrzebował profilowania operacji dyskowych na dyskach
talerzowych - o tym rozmawiajmy. Wiem na ten temat tylko tyle, że nastawianie
głowicy powinno być wykonywane możliwie rzadko. Nie wiem chociażby czy cofanie
wskaźnika pliku o małą ilość bajtów (np. o 100 bajtów) wymusza fizyczne
naprowadzanie głowicy.
Cytat: buninek w 20 Czerwiec 2013, 02:23
Trzy minuty
cd /tmp
cd /tmp
wget ftp://ftp.gnu.org/gnu/coreutils/coreutils-8.21.tar.xz
tar xJf coreutils-8.21.tar.xz
cd coreutils-8.21
ustaw swoje CFLAGS
export CFLAGS=""
./configure --prefix=$HOME/test/coreutils --libexecdir=$HOME/test/coreutils/lib
make
make RUN_EXPENSIVE_TESTS=yes check
make DESTDIR=/tmp/coreutils-8.21-install install
Dzięki za instrukcję, przyda się, bo jestem noga z administracji systemów :)
Pozdrawiam
Muszé powiedzieć, że obróbka tego tekstu z zapisem do bazy za jednym zamachem mija sié z celem...
kod:
Open "W:\all_rows.txt" For Input As #1
Do While Not EOF(1)
Line Input #1, strTemp
sSQL = "SELECT * FROM dane WHERE Line = '" & strTemp & "'"
rsS.OpenRs sSQL, cnM, adOpenDynamic, adLockPessimistic
If rsS.RecordCount = 0 Then
sSQL = "insert into dane(Line, Rep) Values('" & strTemp & "',0)"
cnM.Execute sSQL
Else
rsS.Fields("Rep") = CInt(rsS.Fields("Rep")) + 1
rsS.Update
End If
rsS.CloseRecordset
DoEvents
rsS.CloseRecordset
Loop
Close #1
Przy odpaleniu w IDE wykonuje na moim sprzécie 30-32 zapytania (średnio) na sekundé. Pomyślałem, że kompilacja powinna przyśpieszyć znacznie... Błád, wynik sié nie zmienił...
Jak widać, w tym przypadku wáskim gardłem jest serwer MySQL, a dokładniej (tak mi sié wydaje) operacja indeksowania tabeli po każdym insercie... (index na Line).
Cytat: krzyszp w 20 Czerwiec 2013, 13:12
Muszé powiedzieć, że obróbka tego tekstu z zapisem do bazy za jednym zamachem mija sié z celem...
kod:
Nom, takie same były rokowania.
Cytat: krzyszp w 20 Czerwiec 2013, 13:12
Przy odpaleniu w IDE wykonuje na moim sprzécie 30-32 zapytania (średnio) na sekundé. Pomyślałem, że kompilacja powinna przyśpieszyć znacznie... Błád, wynik sié nie zmienił...
Wąskim gardłem są operacje na bazie. Optymalizacja innych fragmentów niż wąskie
gardło, przynosi tylko nieznaczną poprawę.
Cytat: krzyszp w 20 Czerwiec 2013, 13:12
Jak widać, w tym przypadku wáskim gardłem jest serwer MySQL, a dokładniej (tak mi sié wydaje) operacja indeksowania tabeli po każdym insercie... (index na Line).
Zarówno indeks jaki i dane nie mieszczą się w buforach ram. Algorytm
nie wykorzystuje zalet sekwencyjnych operacji, głowica dysku jest
naprowadzana zarówno w przypadku dostępu do danych jak i
do indeksu. Więc wąskim gardłem są obie operacje: na danych i na indeksie.
Pozdrawiam
P.S.
Moim zdaniem to by miało sens na dyskach SSD. Na dyskach SSD też
jest jakiś czas dostępu do danych, ale nie ma głowicy mechanicznej, więc
jest, w zależności do jakości dysku, 5-200 razy szybszy.
Jak już korzystasz z MySQL to wykorzystuj go optymalnie ;)
http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
Chociaż jak dla mnie pomysł zaprzęgania do takiego zadania serwera bazodanowego jest lekko poroniony. Jak mamy dość pamięci dyskowej to już lepiej by było zrobić dużego swapa i wszystko wrzucać do jakiegoś drzewka (może być samodzielnie napisane albo set STLowy). W sumie to aż sam jestem ciekawy jak takie rozwiązanie by sobie poradziło :D
Cytat: Karlik w 20 Czerwiec 2013, 14:06
Jak już korzystasz z MySQL to wykorzystuj go optymalnie ;)
http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
Chociaż jak dla mnie pomysł zaprzęgania do takiego zadania serwera bazodanowego jest lekko poroniony. Jak mamy dość pamięci dyskowej to już lepiej by było zrobić dużego swapa i wszystko wrzucać do jakiegoś drzewka (może być samodzielnie napisane albo set STLowy). W sumie to aż sam jestem ciekawy jak takie rozwiązanie by sobie poradziło :D
INSERT ON DUPLICATE spowodował spadek ilości zapytań na sekundé o 1/3 (ale nie sprawdziłem samej ilości insertów w tym czasie). Ciekawe, jak sié zachowa dalej.
Wiem, że z punktu widzenia optymalizacji nie ma sensu zrzucenie tego na db (od poczátku było to wiadomo), ale chciałem sie przekonać, jakie jest praktyczne spowolnienie oraz czy samo skompilowanie kodu przyniesie zysk w operacji.
Cytat: krzyszp w 20 Czerwiec 2013, 14:35INSERT ON DUPLICATE spowodował spadek ilości zapytań na sekundé o 1/3
Czy ogólnie dostałeś przyspieszenie ;)
Za każdym razem w poprzedniej sytuacji miałeś 2 zapytania (select i insert lub update), teraz masz zawsze jedno.
Ze zgrubnych obliczeń:
miałeś x zapytań na sekundę, na każde dodanie wykorzystywałeś 2 zapytania (select i insert lub update): x/2 dodań na sekundę
masz 2/3x zapytań na sekundę, na każde dodanie wykorzystujesz 1 zapytanie (sam insert): 2/3*x dodań na sekundę
Na każdej sekundzie nowym sposobem zyskujesz (2/3 - 1/2)*x dodań
Cytat: Karlik w 20 Czerwiec 2013, 14:06
Jak już korzystasz z MySQL to wykorzystuj go optymalnie ;)
http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
Chociaż jak dla mnie pomysł zaprzęgania do takiego zadania serwera bazodanowego jest lekko poroniony.
A może jednak nie aż taki poroniony? Zależy jaki sprzęt, jak skonfigurowana baza i
jaka baza. Zależy też od tego, jak posłużymy się bazą. A jakby zrobić tabelę w RAM? Dużą tabelę tak
żeby zajęła 50-75% dostępnej pamięci. Następnie dodajemy unikalne lub zliczamy powtórzenia w tej tabeli
w RAM. Gdy osiągniemy ilość wierszy na założone 50-75%, to przerzucamy do tabeli na dysku. Będzie masa
odrzuceń w RAM, a tam to działa szybko. Więc ilość operacji dyskowych będzie zminimalizowana. Oczywiście
bazę danych trzeba tak skonfigurować, żeby pozostałe 25-50% pamięci ram było na bufor tabeli dyskowej.
Oczywiście jeszcze ważne są transakcje, trzeba przynajmniej 10K operacji wstawiania obejmować
begin i commit, a na tabeli RAM może w ogóle wyłączyć transakcje. Trzeba też sprawdzić czy indeks
dla tabeli w RAM się opłaca. Aha, i jeszcze jedno, w obu tabelach indeks typu hash będzie szybszy niż btree.
Pozdrawiam
[edit]
Ponadto kolejna baaardzo ważna technika. Możemy wywalić indeks z tej tabeli dyskowej. Musimy się
upewnić w jakiej kolejności są zapisywane rekordy w tej tabeli dyskowej. Prawdopodobnie są zapisywane
tak jak narasta id=autoinc. Więc mamy pole do popisu dla sekwencyjnego odczytu. Zamiast zrzucać z tabeli w
RAM do tabeli dyskowej, możemy zrobić odwrotnie. Gdy zapełni się tabela w RAM, to odczytujemy z tabeli dyskowej
wszystkie rekordy po kolejnych ID. Jeśli rekord jest w tabeli RAM, to uaktualniamy sumę na dysku:
sum_dysk = sum_dysk + sum_ram
Następnie wyrzucamy go z tabeli w RAM. Gdy dojdziemy do końca tabeli dyskowej, to wszystkie nieusunięte
rekordy z tabeli RAM, przerzucamy na tabelę dyskowa - szybko bo bez sprawdzania czy są powtórzenia i bez
zabawy z indeksami.
Może się okazać, że na id=autoinc w tabeli dyskowej, będzie trzeba założyć clustered-index - ale nie wiem,
trzeba się upewnić.
Pozdrawiam
Cytat: Karlik w 20 Czerwiec 2013, 14:06
Jak mamy dość pamięci dyskowej to już lepiej by było zrobić dużego swapa i wszystko wrzucać do jakiegoś drzewka (może być samodzielnie napisane albo set STLowy). W sumie to aż sam jestem ciekawy jak takie rozwiązanie by sobie poradziło :D
Odpisałem dokładnie na powyższe, ale znowu wcięło tekst. W skrócie: zadziała wolno. Każdy dostęp
do drzewka będzie wymagał nastawienia głowicy i wczytania/zapisania 4kb danych na dysku. Może
być lepiej gdy się swap ustawi na dysku ssd.
Pozdrawiam
Cytat: mariotti w 20 Czerwiec 2013, 16:44W skrócie: zadziała wolno. Każdy dostęp do drzewka będzie wymagał nastawienia głowicy i wczytania/zapisania 4kb danych na dysku.
Właśnie nie jest to takie pewne. Ogólnie dużo zależałoby od samej konstrukcji drzewa (kolejności napływających danych). Węzły drzewa często wykorzystywane (blisko korzenia) byłyby cały czas w pamięci operacyjnej - prawdopodobnie w ogóle nie byłyby zrzucane na swapa. Pytanie tylko jak mocno rozrzucone są dane napływające, jeśli byłyby długie sekwencje podobnych (w sensie wspólnej ścieżki w drzewie) danych to mogłoby być całkiem nieźle.
Dyski SSD raczej nie nadają się do serwerów baz danych. W profesjonalnych sprzętach stosuje się SAS i SCSI.
Dysk SSD przy takiej bazie o której tutaj mówimy najprawdopodobniej za długo by nie przetrwał (przecież tutaj mamy maksymalny io wait). Takich twardzieli właśnie z takich względów nie ustawia się na swap - przy normalnej eksploatacji komputera po pół roku sprzęt idzie na szrot. Pół roku przy normalnej eksploatacji to nie wiem ile by wyszło dla maksymalnego io wait - miesiąc?
Może i SSD są i coraz lepsze ale tutaj potrzeba jakiejś profesjonalnej macierzy. Ktoś oszacował ile ta baza będzie zajmowała? Jeżeli jest to rząd wielkości mierzony w TB to nie wiem czy warto kombinować, bo może okazać się, że zapytania będą szły zbyt wolno aby zgrać to w jakiś realny skrypt. Zależy co tam będzie robione.
Jestem sceptycznie nastawiony ale myślę, że mogę pomóc ale musisz mariotti oszacować jakiego sprzętu potrzebujesz (jaka pojemność, jaka prędkość odczytu/zapisu) i na jak długo.
Cytat: Karlik w 20 Czerwiec 2013, 17:09
Właśnie nie jest to takie pewne. Ogólnie dużo zależałoby od samej konstrukcji drzewa (kolejności napływających danych). Węzły drzewa często wykorzystywane (blisko korzenia) byłyby cały czas w pamięci operacyjnej - prawdopodobnie w ogóle nie byłyby zrzucane na swapa. Pytanie tylko jak mocno rozrzucone są dane napływające, jeśli byłyby długie sekwencje podobnych (w sensie wspólnej ścieżki w drzewie) danych to mogłoby być całkiem nieźle.
W bazach danych są drzewa b-tree i nie zadziałało zbyt dobrze. Drzewa AVL, Red-Black, itd
gorzej sprawują się na dyskach niż b-tree. Ale cóż... skłamałbym, jakbym powiedział, że jestem
pewny na 100% :)
Pozdrawiam
Cytat: Rysiu w 20 Czerwiec 2013, 17:31
Dyski SSD raczej nie nadają się do serwerów baz danych. W profesjonalnych sprzętach stosuje się SAS i SCSI.
Dysk SSD przy takiej bazie o której tutaj mówimy najprawdopodobniej za długo by nie przetrwał (przecież tutaj mamy maksymalny io wait). Takich twardzieli właśnie z takich względów nie ustawia się na swap - przy normalnej eksploatacji komputera po pół roku sprzęt idzie na szrot. Pół roku przy normalnej eksploatacji to nie wiem ile by wyszło dla maksymalnego io wait - miesiąc?
Może i SSD są i coraz lepsze ale tutaj potrzeba jakiejś profesjonalnej macierzy. Ktoś oszacował ile ta baza będzie zajmowała? Jeżeli jest to rząd wielkości mierzony w TB to nie wiem czy warto kombinować, bo może okazać się, że zapytania będą szły zbyt wolno aby
zgrać to w jakiś realny skrypt. Zależy co tam będzie robione.
Nie jestem ekspertem od dysków SSD, zwłaszcza od tych najdroższych. Takie mam
zasłyszane informacje, ze one bardzo dobrze sprawują się w losowym odczycie/zapisie.
Podobno te nowe i drogie są wielokrotnie bardziej żywotne od talerzowych. Ale koszt
jednego dysku to 10tys usd i więcej.
Cytat
Jestem sceptycznie nastawiony ale myślę, że mogę pomóc ale musisz mariotti oszacować jakiego sprzętu potrzebujesz (jaka pojemność, jaka prędkość odczytu/zapisu) i na jak długo.
Jeszcze trochę powalczę na swoim sprzęcie, a nóż się uda. Jak się nie uda, to
wielkiego problemu nie będzie, po prostu work-units będą mniej zoptymalizowane.
Teraz nie potrafię powiedzieć jakie wymagania są potrzebne co do ram i pojemności
dysków - każdy algorytm ma inne. Za jakiś czas dokładnie zastanowimy się czy warto
szukać macierzy dyskowej na to zadanie.
Pozdrawiam
Problem optymalizacji work-units rozwiązany. Opisany kilka postów wyżej
algorytm ( ten z jednym zbiorem w RAM i drugim na dysku) jest bardzo szybki.
Dla depth=7 generuje w niecałe dwie godziny na tanim dysku zewnętrznym
na usb 2. Jeśli ktoś jest zainteresowany kodem źródłowym, to udostępnię.
Szkoda że rozwiązanie tego zadania nie oznacza w ogóle końca kłopotów.
Pojawiły się następne problemy - no ale to zwykła praktyka tworzenia
systemów. Muszę przeznaczyć następne dwa-trzy dni w całości na inny
projekt, a potem wracam do dalszych prac i testów.
Pozdrawiam.
Dotarłem do zdumiewającego etapu :D
Jest sobie ten program perft w kilku wersjach, a wersje czasami są jeszcze w kilku
odmianach. Generalnie wersje dzielą się na dwie grupy. Jedna grupa to
siłowe zliczanie/przeszukiwanie. Do drugiej grupy należą wersje zapamiętujące częściowe
wyniki. Wersje z obu grup były długo testowane. Testy polegały na ustawieniu
tysiąca pozycji początkowych i przeszukaniu tych pozycji na głębokość 4-6 ruchów. Wyniki były
porównywane pomiędzy wersjami, a także były porównywane z innymi,
całkowicie niezależnymi programami. Wszystkie testy zakończyły się pozytywnie.
Jak było testowane przeszukiwanie z pozycji początkowej to najlepiej sami
wiecie, bo sami testowaliście - wyniki na głębokość 9-10 ruchów były zawsze
dokładne.
Na bazie tak przetestowanej wersji napisałem program, który nie tylko
przeszukuje, ale także wyrzuca układy na standardowe wyjście.
Ilość wszystkich wyrzuconych układów jest poprawna. Natomiast ilość
unikalnych jest poprawna tylko do głębokości 5 ruchów. Przy głębokości 6
ruchów, ilość unikalnych układów jest o 2 za duża.
Mało tego, mam napisany drugi program do zliczania unikalnych układów.
Ten drugi też podaje o 2 więcej niż wynika z dostępnych
materiałów. Zasada działania drugiego programu jest zupełnie inna, gdyż zlicza
on tylko wartości funkcji skrótu. Może warto podkreślić, że jakby błąd był w funkcji
skrótu, to z powodu kolizji byłoby za mało układów - a jest o te 2 układy za dużo.
To jeszcze nie koniec. Obecnie program napisany jest tak, że generuje sobie
sam pod-zadania. Gdy ma przeszukać na głębokość np. 10 ruchów, to
najpierw przeszukuje na 3-4 ruchy. Zapamiętuje unikalne układy z tych
3-4 ruchów. Następnie po kolei ustawia kolejne układy i przeszukuje każdy
układ na 7-6 ruchów, tak aby łączna głębokość wynosiła założone 10 ruchów.
Przez chwilę pomyślałem, że błąd jest właśnie w generowaniu/formatowaniu
układów. No ale nie może tam być błędu, bo generowanie jest wykorzystywane
także w zwykłym przeszukiwaniu, a więc było też przetestowane.
Patrzyłem dziś w różne miejsca kodu i nie wiem co się dzieje. Wygląda to tak,
jakby jeden i ten sam element raz działał, a drugi raz nie. W dodatku
dwa różne algorytmy dają taki sam błąd. Wszelka logika zawodzi.
Może jakiś element programu nie był tak dokładnie przetestowany jak mi się
wydaje, ale to raczej bym wiedział.
Zastanawiam się czy może być błąd w materiałach jakie znalazłem, ale taką
możliwość chyba też trzeba odrzucić. Zakładam że jak ktoś przygotowywał
takie czy inne materiały, to jakoś zweryfikował wyniki.
W trakcie pisania tego posta, naszło mnie pewne spostrzeżenie. Program perft4
ma problem z wygenerowaniem unikalnych układów na głębokości równej sześć.
Nie jestem dobrym szachistą, interesuję się tylko szachami komputerowymi, a
samemu nie gram, ale jeśli się nie mylę, to na tej samej głębokości zaczynają
mieć znaczenie "przyzwolenia" do roszad. Przykład widać na pozycji 1 poniżej:
białe i czarne wyjeżdżają skoczkiem i laufrem i mogą wykonać małe roszady:
pozycja 1 (http://www.ideachess.com/chess_fen_viewer/fen/cm5icWsyci9wcHBwMXBwcC8zYnBuMi84LzgvM0JQTjIvUFBQUDFQUFAvUk5CUUsyUiB3IEtRa3EgLSA0IDQ-)
Pojawia się w tym kontekście pewna ciekawostka. W sześciu ruchach można także
dojść do takiego układu:
pozycja 2 (http://www.ideachess.com/chess_fen_viewer/fen/cm4xcWtibnIvcDFwcHBwcHAvMXA2LzgvOC8zYlBOMi9QUFBQMVBQUC9STkJRSzJSIHcgS1FrcSAtIDAgNA--)
Białe nie wykonały żadnego ruchu ani królem, ani wieżą, jest wolna przestrzeń
pomiędzy królem i wieżą, więc mają "przyzwolenie" do roszady. Jednak roszady
wykonać w siódmy ruchu nie mogą, bo jest atakowane pole na drodze króla.
Z punktu widzenia programu do zliczania wszystkich pozycji powyższy niuans
nie ma znaczenia, gdyż program i tak i tak nie wykona roszady wbrew zasadom gry, a
więc pozycji po jej wykonaniu nie uwzględni w zliczaniu. Natomiast w przypadku
zliczania unikalnych pozycji mamy dwuznaczność. Gdy zignorujemy "przyzwolenia", to
jest wszystko w porządku, bo i tak i tak nie możemy roszady wykonać. Gdy nie zignorujemy,
to też jest wszystko w porządku - po prostu mamy dodatkową informację o tym, że król i
wieża nie była do tej pory ruszana. Przyzwolenia będą ważne w ruchach następnych, ale w tej
pozycji równie dobrze możemy o nich pamiętać jak i nie.
Czyżby powyższe spostrzeżenie prowadziło do wniosku, że w materiałach jakie mam, ktoś
robiący badania uznał, że w takich pozycjach należy usunąć informację o przyzwoleniach, bowiem
i tak i tak nie można wykonać roszady, a ponadto takie pozycje pojawiają się raptem dwie wśród 12milionów
pozycji, a więc w wynikach ma o te dwie pozycje mniej niż ja? :boing: Brzmi nieprawdopodobnie, dosłownie
nie mogę uwierzyć, ale na tę chwilę nie mam lepszego wyjaśnienia.
Pewne natomiast jest to, że ja nie mogę z work-units usunąć informacji o przyzwoleniach, bo będzie ona
potrzebna w dalszym przeszukiwaniu drzewa gry, konkretnie w tym przeszukiwaniu jakie będą wykonywały aplikacje
klienckie.
Jakby ktoś coś dorzucił do moich rozważań, to za wszelkie inspirację będę wdzięczny.
Pozdrawiam
CytatCzyżby powyższe spostrzeżenie prowadziło do wniosku, że w materiałach jakie mam, ktoś
robiący badania uznał, że w takich pozycjach należy usunąć informację o przyzwoleniach, bowiem
i tak i tak nie można wykonać roszady, a ponadto takie pozycje pojawiają się raptem dwie wśród 12milionów
Ciężko ocenić, nie znając materiałów na których się opierasz (być może informacja o tym jest w tekście)...
Cytat: krzyszp w 24 Czerwiec 2013, 23:52
CytatCzyżby powyższe spostrzeżenie prowadziło do wniosku, że w materiałach jakie mam, ktoś
robiący badania uznał, że w takich pozycjach należy usunąć informację o przyzwoleniach, bowiem
i tak i tak nie można wykonać roszady, a ponadto takie pozycje pojawiają się raptem dwie wśród 12milionów
Ciężko ocenić, nie znając materiałów na których się opierasz (być może informacja o tym jest w tekście)...
Pogrzebałem jeszcze trochę w sieci.
Tutaj jest z trójką na końcu (9417683) (http://oeis.org/A057745/b057745.txt).
A tutaj z jedynką (9417681) (http://oeis.org/search?q=id:A083276&fmt=text)
Piszą, że różnica wynika z tego, iż bicie w przelocie jest (czasami) nielegalne. Przyczyna
różnicy jest podobna jak opisałem powyżej, jednak myliłem się że względem roszady. Nielegalność
oznacza, że po wykonaniu bicia w przelocie król (król strony wykonującej to bicie) będzie
szachowany. Skoro to nielegalny ruch, to można informację o nim usunąć. Jeśli się usunie, to
układów będzie mniej. Trochę dziwne, że przy przeszukiwaniu na głębokość sześciu
ruchów, są tylko dwie takie sytuacje, ale widocznie tak jest.
Program z tą "usterką" zadziałałby poprawnie, po prostu dwa układy brałby za różne, gdy
można je wziąć za takie same. Jednak widzę sens wprowadzenia zmiany do programu.
Po zmianie będzie można sprawdzić, czy ilość unikalnych układów zgadza się z podaną
ilością w tamtych wynikach. Program szybciej będzie przetestowany, odpadnie wiele testów z
poziomu serwera boinc.
Pozdrawiam
P.S.
Tam chyba pełny test perft do depth <= 13
perft <= 13 (http://oeis.org/A048987/b048987.txt)
Mam wielką prośbę do Was o przeprowadzenie pewnego testu. Na stacjonarnym komputerze
mam losowe wyniki, nie wiem czy ja narobiłem błędów, czy coś źle ze sprzętem lub systemem.
Cały program perft jest wielki, więc napisałem mały substytut o nazwie test_csuniq.
Substytut generuje wiersze, w tym pewną ilość unikalnych wierszy. Jeśli test się nie powiedzie,
to będziemy mieli 100% pewności, że jest błąd w jednym z członów:
1) błąd w programie test_csuniq
2) błąd sprzętu
3) błąd systemu operacyjnego w szczególności narzędzi systemowych
4) błąd kompilatora, bibliotek dostarczonych z kompilatorem
Zrobiłem na laptopie około 10 testów i zakończyły się powodzeniem. Na stacjonarnym 50% kończy
się błędem.
Jak uruchomić program? Można przykładową komendą:
./test_csuniq len_min=5 len_max=20 rows=30 uniq=5 seed=0
Tak uruchomiony program wygeneruje 30 wierszy (rows=30), w
tym 5 unikalnych (unq=5), o długości z przedziału od 5 do 20 znaków.
Wiersze będą zawierały (prawie) losowe znaki ascii. Sposób losowania
można kontrolować nadając parametrowi seed wartości powyżej zero.
Test polega na przekierowaniu programu do sort, uniq i wc, aby sprawdzić czy
ilość unikalnych wierszy jest taka jak wartość parametru uniq. Poniższe
uruchomienie powinno dać w wyniku wartość 50tys.
./test_csuniq len_min=7 len_max=70 rows=200000 uniq=50000 seed=0 | sort | uniq | wc -l
Jak ktoś nie chce wnikać w szczegóły, to najlepiej pobrać źródło programu i
zapisać je jako plik 'main.cpp' w jakimś katalogu:
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <ctime>
typedef int ityp;
typedef const int cityp;
typedef unsigned int utyp;
typedef const utyp cutyp;
static void help() {
printf("using:test_csuniq len_min=uint len_max=uint rows=uint uniq=uint seed=uint\n");
abort();
}
struct Args {
utyp len_min;
utyp len_max;
utyp rows;
utyp uniq;
utyp seed;
};
static void parseArgs(int argc, char *argv[], Args &args) {
memset( &args , 0 , sizeof(args) );
args.seed = 0;
for( int i=1 ; i<argc ; i++ ) {
if( strncmp( "len_min=" , argv[i] , 8 ) == 0 ) {args.len_min = (utyp)atol( argv[i]+8 ); }
if( strncmp( "len_max=" , argv[i] , 8 ) == 0 ) {args.len_max = (utyp)atol( argv[i]+8 ); }
if( strncmp( "rows=" , argv[i] , 5 ) == 0 ) {args.rows = (utyp)atol( argv[i]+5 ); }
if( strncmp( "uniq=" , argv[i] , 5 ) == 0 ) {args.uniq = (utyp)atol( argv[i]+5 ); }
if( strncmp( "seed=" , argv[i] , 5 ) == 0 ) {args.seed = (utyp)atol( argv[i]+5 ); }
}
if( args.len_max < args.len_min ) help();
if( args.rows < args.uniq ) help();
if( args.len_min == 0 ) help();
if( args.len_max == 0 ) help();
if( args.rows == 0 ) help();
if( args.uniq == 0 ) help();
if( args.seed == 0 ) args.seed = time(NULL);
}
char rndChar() {
const static char rndc[] = "-=!@#$%^&*()_+qqweertyuiop[[]]]\\QWERTYUIOP{}|asdfghjkl;'ASDFGHJKL:\"zxcvbnm,./ZXCVBNM<>?`~";
return rndc[ rand() % (sizeof(rndc)-1) ];
}
void rndString( cutyp len_min, cutyp len_max , char string[] , utyp nr ) {
utyp len = rand() % ( len_max - len_min + 1 ) + len_min;
string[len] = 0;
while( len && nr ) {
string[--len] = '0' + (nr%10);
nr /= 10;
}
while( len )
string[--len] = rndChar();
}
int main(int argc, char *argv[]) {
Args args;
parseArgs( argc , argv , args );
srand(args.seed);
char **strings = new char*[args.uniq];
utyp *counts = new utyp[args.uniq];
char *string = new char[args.len_max+1];
for( utyp i=0 ; i<args.uniq ; i++ ) {
rndString( args.len_min , args.len_max , string , i+1 );
strings[i] = strdup( string );
counts[i] = 1;
}
utyp r = rand();
for( utyp i=0 ; i<args.rows-args.uniq ; i++ ) {
r = (r + rand())%args.uniq;
counts[r] ++ ;
}
{
utyp uniq = args.uniq;
while( uniq ) {
r = (r + rand()) % uniq;
printf("%s\n",strings[r]);
if( --counts[r] == 0 ) {
free( strings[r] );
strings[r] = strings[uniq-1];
counts[r] = counts[uniq-1];
uniq--;
}
}
}
delete[] string;
delete[] counts;
delete[] strings;
return 0;
}
Następnie w tym samym katalogu trzeba zapisać skrypt powłoki:
g++ -O3 -omit-frame-pointers -march=native -o test_csuniq main.cpp
mkdir -p tmp
RAM=$1
./test_csuniq len_min=10 len_max=20 rows=20000 uniq=5000 seed=0 | sort -T'./tmp' -S$RAM | uniq | wc -l
./test_csuniq len_min=50 len_max=100 rows=20000 uniq=5000 seed=0 | sort -T'./tmp' -S$RAM | uniq | wc -l
./test_csuniq len_min=500 len_max=1000 rows=20000 uniq=5000 seed=0 | sort -T'./tmp' -S$RAM | uniq | wc -l
./test_csuniq len_min=10 len_max=20 rows=20000 uniq=5000 seed=0 | sort -T'./tmp' -S$RAM --compress-program=gzip | uniq | wc -l
./test_csuniq len_min=50 len_max=100 rows=20000 uniq=5000 seed=0 | sort -T'./tmp' -S$RAM --compress-program=gzip | uniq | wc -l
./test_csuniq len_min=500 len_max=1000 rows=20000 uniq=5000 seed=0 | sort -T'./tmp' -S$RAM --compress-program=gzip | uniq | wc -l
./test_csuniq len_min=10 len_max=20 rows=200000 uniq=50000 seed=0 | sort -T'./tmp' -S$RAM | uniq | wc -l
./test_csuniq len_min=50 len_max=100 rows=200000 uniq=50000 seed=0 | sort -T'./tmp' -S$RAM | uniq | wc -l
./test_csuniq len_min=500 len_max=1000 rows=200000 uniq=50000 seed=0 | sort -T'./tmp' -S$RAM | uniq | wc -l
./test_csuniq len_min=10 len_max=20 rows=200000 uniq=50000 seed=0 | sort -T'./tmp' -S$RAM --compress-program=gzip | uniq | wc -l
./test_csuniq len_min=50 len_max=100 rows=200000 uniq=50000 seed=0 | sort -T'./tmp' -S$RAM --compress-program=gzip | uniq | wc -l
./test_csuniq len_min=500 len_max=1000 rows=200000 uniq=50000 seed=0 | sort -T'./tmp' -S$RAM --compress-program=gzip | uniq | wc -l
./test_csuniq len_min=10 len_max=20 rows=2000000 uniq=500000 seed=0 | sort -T'./tmp' -S$RAM | uniq | wc -l
./test_csuniq len_min=50 len_max=100 rows=2000000 uniq=500000 seed=0 | sort -T'./tmp' -S$RAM | uniq | wc -l
./test_csuniq len_min=500 len_max=1000 rows=2000000 uniq=500000 seed=0 | sort -T'./tmp' -S$RAM | uniq | wc -l
./test_csuniq len_min=10 len_max=20 rows=2000000 uniq=500000 seed=0 | sort -T'./tmp' -S$RAM --compress-program=gzip | uniq | wc -l
./test_csuniq len_min=50 len_max=100 rows=2000000 uniq=500000 seed=0 | sort -T'./tmp' -S$RAM --compress-program=gzip | uniq | wc -l
./test_csuniq len_min=500 len_max=1000 rows=2000000 uniq=500000 seed=0 | sort -T'./tmp' -S$RAM --compress-program=gzip | uniq | wc -l
./test_csuniq len_min=10 len_max=20 rows=20000000 uniq=5000000 seed=0 | sort -T'./tmp' -S$RAM | uniq | wc -l
./test_csuniq len_min=50 len_max=100 rows=20000000 uniq=5000000 seed=0 | sort -T'./tmp' -S$RAM | uniq | wc -l
./test_csuniq len_min=500 len_max=1000 rows=20000000 uniq=5000000 seed=0 | sort -T'./tmp' -S$RAM | uniq | wc -l
./test_csuniq len_min=10 len_max=20 rows=20000000 uniq=5000000 seed=0 | sort -T'./tmp' -S$RAM --compress-program=gzip | uniq | wc -l
./test_csuniq len_min=50 len_max=100 rows=20000000 uniq=5000000 seed=0 | sort -T'./tmp' -S$RAM --compress-program=gzip | uniq | wc -l
./test_csuniq len_min=500 len_max=1000 rows=20000000 uniq=5000000 seed=0 | sort -T'./tmp' -S$RAM --compress-program=gzip | uniq | wc -l
Skrypt sam:
- skompiluje program
- założy katalog tymczasowy dla polecenia sort
- no i przeprowadzi testy.
Jako parametr skryptu podajemy ilość pamięci w kilobajtach. Gdy skrypt zapisaliśmy
jako plik 'go.sh', to uruchomienie dla 3GB RAM wygląda tak:
./go.sh 3000000
Jeśli test przebiegnie pomyślnie, to program wyświetli 6 razy: 5tys, 50tys, 500tys i 5mln, czyli
razem 24 liczby. Ostatnie testy zajmują dużo czasu i wymagają dużo miejsca na dysku, więc
jak ktoś straci cierpliwość, to po wyświetleniu 20 początkowych liczb można program ubić.
Program losuje sobie zarodek liczb losowych z czasu systemowego, więc każde uruchomienie to
trochę inny test, można program uruchomić kilka razy.
Pozdrawiam
(https://dl.dropboxusercontent.com/u/31067433/Test.jpg)
Robi się, aktualnie mam drugi raz 500k na ekranie.
Cytat: krzyszp w 26 Czerwiec 2013, 22:52
Robi się, aktualnie mam drugi raz 500k na ekranie.
Dziękuję wszystkim. To jest prosty program, ale wpadam w paranoję, że narobiłem
jakiś błędów, bo sytuacja jest dziwna. Dziwność jej polega na tym, że
jakbym miał błędy na dysku przenośnym, to by też na laptopie nie działało.
Jakbym miał uszkodzoną pamięć RAM, to by nie działał Linux, a już
na pewno by nie działał tam program perft, który korzysta z hash-table o
rozmiarze 6GB RAM. Jednak to wszystko działa i wiele innych programów
też działa. Błąd kompilatora też nie wchodzi w grę, bo jak przenoszę
program skompilowany na laptopie, to na PC nadal nie działa. Jak
długo chodzę po tej planecie, czegoś takiego nie widziałem. No chyba
że jednak znajdziecie błąd w tym prostym programie :)
Pozdrawiam
Spokojnie, nie takie rzeczy widzialem...
Wierz mi, że kompilatory potrafią cuda narobić, a zwłaszcza w sytuacji, gdy nieświadomie, podczas ich instalacji np. włączysz optymalizację dla którejś wersji sse...
Osobny temat (rzeka) to .net w tym względzie...
Koniec off-topa... Jak długo program powinien się wykonywać?
Cytat: krzyszp w 26 Czerwiec 2013, 23:12
Spokojnie, nie takie rzeczy widzialem...
Wierz mi, że kompilatory potrafią cuda narobić, a zwłaszcza w sytuacji, gdy nieświadomie, podczas ich instalacji np. włączysz optymalizację dla którejś wersji sse...
Wierzę, ale dlaczego reszta programów działa?
Cytat: krzyszp w 26 Czerwiec 2013, 23:12
Osobny temat (rzeka) to .net w tym względzie...
Koniec off-topa... Jak długo program powinien się wykonywać?
Dwadzieścia pierwszych testów powinno w kilka minut wyskoczyć. Pozostałe mogą trwać bardzo
długo. Jak wyświetlił wyniki z 20 testów, to już jest miarodajne i można ubić przez ctrl+c.
Pozdrawiam
Cytat: krzyszp w 26 Czerwiec 2013, 23:12
Koniec off-topa... Jak długo program powinien się wykonywać?
o właśnie, też mnie interesuje odpowiedź, bo nie wiem czy jest sens to dzisiaj zapuszczać
Cytat: sknd w 26 Czerwiec 2013, 23:30
Cytat: krzyszp w 26 Czerwiec 2013, 23:12
Koniec off-topa... Jak długo program powinien się wykonywać?
o właśnie, też mnie interesuje odpowiedź, bo nie wiem czy jest sens to dzisiaj zapuszczać
Program można zabić po wyczerpaniu cierpliwości, np. po 5-15 minutach :)
Pozdrawiam
po dwudziestu kilku minutach zrobiło mi się szkoda dysku;)
[ja@komp tlo]$ chmod +x go.sh
[ja@komp tlo]$ ./go.sh 8000000
5000
5000
5000
5000
5000
5000
50000
50000
50000
50000
50000
50000
500000
500000
500000
500000
500000
500000
5000000
5000000
U mnie na razie wynik identyczny, ale niech mieli (jeśli ma to sens).
Cytat: sknd w 27 Czerwiec 2013, 00:19
po dwudziestu kilku minutach zrobiło mi się szkoda dysku;)
Dzięki serdeczne :)
Wygląda na to, że w programie nie ma błędów, a z jakiś niejasnych
powodów program nie chce działać na moim stacjonarnym kompie.
Jakby stacjonarny się zepsuł, to bym kupił po prostu nowy, ale ja z
niego od czasu do czasu korzystam i wszystko działa bardzo dobrze.
Co jest grane to nie wiem. Najgorsze jest to, że przez takie problemy
traci się wiele dni czasu.
Trzeba przyjąć jakiś plan działania... Na razie chyba zadowolę się
generowaniem/optymalizowaniem WU na laptopie. Powiedzmy że
generowanie i optymalizowanie jest średnio przetestowane. Więc
mogę na wirtualu postawić BOINC i dalej się uczyć konfiguracji i
dodania work-units.
Pozdrawiam
Cytat: krzyszp w 27 Czerwiec 2013, 01:00
U mnie na razie wynik identyczny, ale niech mieli (jeśli ma to sens).
Sam nie jestem pewny czy jest sens. Programik jest prosty. Na kilku
systemach/kompilatorach/komputerach/RNG zadziałał poprawnie. Na jednym
kompie nie działa. Chyba mamy już prawie pewność, że jakieś cuda
z moim stacjonarnym kompem się dzieją. Raczej wystarczy, dziękuję :)
Pozdrawiam
podaj dokładną specyfikację swego kompa oraz laptopa. Może coś nie kuku ze sprzętem?
Cytat: Troll81 w 27 Czerwiec 2013, 08:16
podaj dokładną specyfikację swego kompa oraz laptopa. Może coś nie kuku ze sprzętem?
Ale jak wytłumaczyć fakt, że inne programy działają, a zliczanie wierszy żadną z
trzech (różnych) metod nie działa? Ku ścisłości: działa z prawdopodobieństwem
równym około 50%. To jest dość typowe zachowanie dla programów z UB, ale
ten który testowaliśmy UB nie ma, bo na wszystkich innych kompach działa poprawnie.
Pozdrawiam
podaj to pogłówkujemy..... może jakiś bibliotek brak? może któraś konkretna apka wykrzacza wyniki.... z kryształowej kuli nie umiem wróżyć....
Cytat: Troll81 w 27 Czerwiec 2013, 11:35
podaj to pogłówkujemy..... może jakiś bibliotek brak? może któraś konkretna apka wykrzacza wyniki.... z kryształowej kuli nie umiem wróżyć....
Niezręcznie się czuję. Z jednej strony głupio mi odrzucić pomoc, a z drugiej podejrzewam, że
wnioski do jakich dojdziemy, nie będą warte tej całej pisaniny. Na razie dążę do postawienia
wersji testowej, więc generowanie na laptopie wystarczy. Potem... nie wiem... może kupię
płytę główną, procesor i pamięć, zainstaluję linuxa, włączę test, jak nie zadziała, to zaniosę
kompa na gwarancję i powiem że źle działa :D
Właściwe to można pogłówkować apropo sprzętu z pożytkiem dla wszystkich. Jaki warto
kupić zestaw "płyta, procesor, pamięć" żeby miał maksymalny współczynnik:
wydajność / (cena zakupu + cena energii * 2 lata ciągłych obliczeń ) ?
Pozdrawiam
1. U mnie program się nie wysypał do dzisiaj rana, kiedy go wyłączyłem, nadal był na etapie "2x500k@.
2. Obadaj jednak RAM'y, często są przyczyną "dziwnych" problemów.
3. Co do kompa, polecam składniki jakie sam zamontowałem:
Mobo - Gigabyte Z77-D3H
CPU Xeon 1230v2
Zestaw powyżej dopalony 2 x 7770, 5 x HDD,1 x SDD, 2 x 4GB RAM "pożera" 105W w stresie (stres = 8WU POEM na raz). Do zestawy chcę dołożyć jeszcze 8GB RAM, bo mi niestety lubi zabraknąć :)
Cytat: krzyszp w 27 Czerwiec 2013, 15:58
1. U mnie program się nie wysypał do dzisiaj rana, kiedy go wyłączyłem, nadal był na etapie "2x500k@.
Zadanie jest ciężkie, ale powinien wykonać. Jeśli masz ochotę, to zobacz jeszcze taki skrypt:
g++ -O3 -omit-frame-pointers -march=native -o test_csuniq main.cpp
mkdir -p tmp
RAM=1000000
rows=(100000, 200000, 500000, 1000000, 2000000, 5000000, 10000000, 20000000, 50000000, 100000000, 200000000)
for i in "${rows[@]}"
do
echo "rows $i"
time ./test_csuniq len_min=500 len_max=1000 rows=$i uniq=5000 seed=0 | sort -T'./tmp' -S$RAM | uniq | wc -l
done
Na moim lapku i3 takie czasy są:
rows 100000,
5000
real 0m1.496s
user 0m1.472s
sys 0m0.236s
rows 200000,
5000
real 0m3.130s
user 0m3.072s
sys 0m0.472s
rows 500000,
5000
real 0m8.593s
user 0m8.457s
sys 0m1.168s
rows 1000000,
5000
real 0m18.846s
user 0m18.029s
sys 0m2.904s
rows 2000000,
5000
real 1m3.013s
user 0m38.874s
sys 0m7.000s
rows 5000000,
5000
real 4m27.217s
user 1m40.978s
sys 0m17.437s
rows 10000000,
5000
real 9m25.056s
user 3m25.029s
sys 0m35.310s
rows 20000000,
5000
real 19m2.746s
user 6m50.070s
sys 1m6.800s
Cytat: krzyszp w 27 Czerwiec 2013, 15:58
2. Obadaj jednak RAM'y, często są przyczyną "dziwnych" problemów.
To test perft by też nie działał. On bardzo intensywnie korzysta z RAM.
Cytat: krzyszp w 27 Czerwiec 2013, 15:58
3. Co do kompa, polecam składniki jakie sam zamontowałem:
Mobo - Gigabyte Z77-D3H
CPU Xeon 1230v2
Zestaw powyżej dopalony 2 x 7770, 5 x HDD,1 x SDD, 2 x 4GB RAM "pożera" 105W w stresie (stres = 8WU POEM na raz). Do zestawy chcę dołożyć jeszcze 8GB RAM, bo mi niestety lubi zabraknąć :)
O jaki fajny zestaw! Tyle przeglądałem procesory, a jakoś nie zauważyłem, że ten procesor
ma tylko 69TDP
http://www.cpubenchmark.net/cpu.php?cpu=Intel+Xeon+E3-1230+V2+%40+3.30GHz&id=1189
W tym rankingu ma aż 8884 punktów.
http://www.cpubenchmark.net/cpu_list.php
Dziwi mnie że zestaw z dwoma kartami grafiki bierze zaledwie 105wat - ale to dobrze :)
Pozdrawiam
Później odpalę skrypt, teraz muszę lecieć do pracy.
Natomiast co do zestawu, to też mnie dziwi, ale mam cały czas podczepiony miernik i ni cholery nie chce pokazać pow. 105W :)
Faktem jest, że POEM nie obciąża sprzętu na 100%, a Ati 7770 nie należą do zbyt prądożernych.
Wg Core Temp proc podczas pracy bierze ok. 35W.
Cytat: krzyszp w 28 Czerwiec 2013, 09:23
Później odpalę skrypt, teraz muszę lecieć do pracy.
Wieczorem dam lepsze i ważniejsze testy niż tamten skrypt, ino niech się zakończą
na moim kompie :)
Cytat: krzyszp w 28 Czerwiec 2013, 09:23
Natomiast co do zestawu, to też mnie dziwi, ale mam cały czas podczepiony miernik i ni cholery nie chce pokazać pow. 105W :)
Faktem jest, że POEM nie obciąża sprzętu na 100%, a Ati 7770 nie należą do zbyt prądożernych.
Wg Core Temp proc podczas pracy bierze ok. 35W.
Ciekawe jakie są możliwości zmniejszania częstotliwości zegara w i7. Mój phenom na
płycie z jakąś zintegrowaną grafiką, pobiera w stresie do 300W. Co ciekawe, w aplikacjach
jednowątkowych pobiera więcej, bo się włącza opcja turbo. Jednak gdy zmniejszyłem
częstotliwość i voltage, to pobór mocy spadł do takiej wartości jak u Ciebie, czyli do 105W.
Wydajność z tego tytułu spadła o jakieś 10-15%, więc na ówczesne czasy ten procesor
okazał się optymalnym wyborem. Nowe i7 zwykle mają TDP=130. Może po zmniejszeniu
częstotliwości o 15% pobór mocy też by spadł o 60%.
Pozdrawiam
Cytat: mariotti w 28 Czerwiec 2013, 11:08
Wieczorem dam lepsze i ważniejsze testy niż tamten skrypt, ino niech się zakończą
na moim kompie :)
Test jest w pełni automatyczny. Rozpakowujemy do jakiegoś katalogu i uruchamiamy
skrypt ./go.sh. W plikach test1.txt i test2.txt powinna być identyczna zawartość. Przed
zakończeniem testu, te pliki mogą mieć różną długość, ale poza tym powinny być
identyczne. Można je porównać poleceniem
diff test1.txt test2.txt
Test trwa dość długo, u mnie trwał kilka godzin. Nie trzeba koniecznie czekać do końca :)
Pozdrawiam
Robi się...
Edit:
Końcówka:
...
exhausted rows 296120022 3000000
exhausted rows 296649733 3000000
exhausted rows 297245903 3000000
exhausted rows 298045773 3000000
flush 300000000 3000000
sync...
real 99m53.957s
user 34m31.416s
sys 8m49.104s
3000000 uniq2.txt
O]k\M$v?eKtqu`h!V]pz/ES[yQ!OmY2241453; 105
.dwtEGu"svmEXRdFbmSXm>Kr\uG,Ohl'2676572; 103
u]S=kxhdW[/EmRL+z[pH#_R$NO!Bk}.~zZ2045601; 113
[|o-r[HU\+~>MDD@iVlWtaGCtflE(Ab@p?%d<fe+?&$CRzISG&J^pX[,UL]m*,L|!d]gj/&%H[ez,]<]hhfIO]uQ'a/\hwq{Kyeuqv'MtZn}d)g)(t<.J"|!JGe&tB=P,qAthaZ}]IHqx]wope1748118; 90
AJ(lxL#e_N}hbu]k-u#->)[H[;D$V;,@HRfj])KhZ`y?umfz#GO!mJ@yJbtZGe}*nqZx={]V:qUyd1627781; 108
cNYocXQBAF;cVuNL,BHYF$n.(;_%:$La+fFZ-I$/sQ.qqxvYyE;jM<PbX%\tBMl@f?h+GHz\>,E"p+hFOT*CmROSqYEA+Wt+#Z_]}NKr2913477; 105
sum rows=300000000
Podać zawartość test1.txt i test2.txt?
Cytat: mariotti w 28 Czerwiec 2013, 11:08
Ciekawe jakie są możliwości zmniejszania częstotliwości zegara w i7. Mój phenom na
płycie z jakąś zintegrowaną grafiką, pobiera w stresie do 300W. Co ciekawe, w aplikacjach
jednowątkowych pobiera więcej, bo się włącza opcja turbo. Jednak gdy zmniejszyłem
częstotliwość i voltage, to pobór mocy spadł do takiej wartości jak u Ciebie, czyli do 105W.
Wydajność z tego tytułu spadła o jakieś 10-15%, więc na ówczesne czasy ten procesor
okazał się optymalnym wyborem. Nowe i7 zwykle mają TDP=130. Może po zmniejszeniu
częstotliwości o 15% pobór mocy też by spadł o 60%.
Kiedyś jak testowałem OC na Phenom II x4 i wyciągnąłem z niego 4,6 GHz to miernik energii pokazywał 310 W. Grzała była niesamowita. Na std. zegarze i obniżonym napięciu max. pobór całego komputera (z integrą) wynosił 95 W. Z tego co piszesz to masz PhII x6 i jakoś nie chce mi się wierzyć, że wydajność spadła ci tylko o 10-15%. U mnie spadła o 25-30%
Cytat: krzyszp w 29 Czerwiec 2013, 14:40
Robi się...
Podać zawartość test1.txt i test2.txt?
Super, dzięki. Widzę już, że jest dobrze :)
Pozdrawiam
Cytat: Dario666 w 29 Czerwiec 2013, 19:58
Kiedyś jak testowałem OC na Phenom II x4 i wyciągnąłem z niego 4,6 GHz to miernik energii pokazywał 310 W. Grzała była niesamowita. Na std. zegarze i obniżonym napięciu max. pobór całego komputera (z integrą) wynosił 95 W. Z tego co piszesz to masz PhII x6 i jakoś nie chce mi się wierzyć, że wydajność spadła ci tylko o 10-15%. U mnie spadła o 25-30%
Wszystko zależy od tego, jak się ustawi taktowanie zegara. Jeśli się zmniejszy dwa razy, to
wydajność też spada około 2 razy. Nie znam się na takich szczegółach, ale możliwe że
mniej niż 2 razy, bo jest mniej oczekiwań na dane z RAM. PhenomII X6 ma 6 fizycznych rdzeni.
W moim przypadku wydajność w aplikacjach wielowątkowych spadła o niecały jeden rdzeń. W
jednowątkowych spadła bardziej, bo nie dość że zmniejszyłem zegar, to jeszcze wyłączyłem turbo.
Pozdrawiam
BTW
Zobaczcie na ten procesor:
http://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i7-3770T+%40+2.50GHz&id=898
TDP 45watt, w rankingu 8452 punktów, cena 300USD. Może to najlepszy wybór na domowy klaster?
Możliwe, że ma 45W TDP, ale na pewno nie w trybie turbo 3,7 GHz. Gdyby tak było, wystarczyłby mu cooler ze starego Durona.
Po drugie ten test nie jest miarodajny do wydajności w BOINC. Wiadomo jaki nowe AMD są cienkie, a tu na wykresie wyglądają na mega mocne.
Wracając stricte do tematu BOINC.
Skonfigurowałem VPS, założyłem sub-domeny, wygląda na to że
ta część działa poprawnie:
http://test.computers-chess.com/ (http://test.computers-chess.com/).
Pobrałem z repozytorium źródła serwera BOINC:
git clone git://boinc.berkeley.edu/boinc-v2.git boinc
Zainstalowałem mysqla i wszystkie biblioteki o jakie krzyczał.
Następnie dałem polecenie make_project i jest błąd:
FATAL ERROR: Command failed: /home/test/boinc/lib/crypt_prog -genkey 1024 /home/test/www/keys/upload_private /home/test/www/keys/upload_public >/dev/null
Szukam w googlach rozwiązania, ale nadal nie wiem dlaczego nie mam programu crypt_prog.
Błąd jest w pliku Makefile i go nie kompiluje w ogóle?
Pozdrawiam