Statystyki BOINC z RRDTool

by mindc

Wstęp

Ten tutorial ma pokazać, w jak prosty sposób można stworzyć własne statystyki BOINC. Przy odrobinie wysiłku, można osiągnąć bardzo interesujące efekty. Dzięki temu, można wzbogacić swoja stronę www lub sygnaturkę. Wszelkie polecenia dotyczą systemu Linux, jednak nie powinno stanowić problemu, stworzeniu takich statystyk pod systemem Windows :)

Kolory: Wskazówki Uwagi Linia poleceń Kod

Wymagania

Przygotowania

Zaczniemy od przygotowania oprogramowania.

Perl i rrdtool

W Debianie i pochodnych, sprawa wygląda prosto (w Ubuntu trzeba pamiętać o sudo przed apt-get):

# apt-get install perl rrdtool librrds-perl

Zainstalujemy w ten sposób Perl w wersji 5.10.0 i rrdtool w wersji 1.3.1.

Jeśli chcemy jedynie pobierać dane z schedulerów i dane obrabiać w inny sposób niż z pomocą rrdtool, można pominąć instalację tego pakietu.

Do generowania samych wykresów, używam rrdtool w wersji 1.2.26, ponieważ umożliwia on wykorzystywanie własnych czcionek. Wersja 1.2.27 już ignoruje ten parametr. Na dzień dzisiejszy wersje 1.3.x i 1.4.x także ignorują zewnętrzne czcionki użytkownika.

build-rrdtool-1.2.26.sh (wersja wspierająca czcionki użytkownika)
skrypt ściąga niezbędne pakiety, kompiluje i instaluje rrdtool w wersji 1.2.26 w katalogu /usr/local/rrdtool-1.2.26

build-rrdtool-1.4.4.sh (najnowsza wersja na dzień 2010-07-28)
skrypt ściąga niezbędne pakiety, kompiluje i instaluje rrdtool w wersji 1.4.4 w katalogu /usr/local/rrdtool-1.4.4

Nic nie stoi na przeszkodzie aby jednocześnie było zainstalowanych kilka wersji rrdtool. Obecnie do generowania wykresów używam wersji 1.2.26, a do generowania i aktualizacji samych plików rrd, wersji 1.3.1

Aby korzystać z biblioteki innej niż domyślna, należy w skryptach dopisać linijkę przed use RRDs;
Na przykład dla wersji 1.2.26

use RRDs;

zmieniamy na

use lib qw(/usr/local/rrdtool-1.2.26/lib/perl);
use RRDs;

i analogicznie dla wersji 1.4.4

use lib qw(/usr/local/rrdtool-1.4.4/lib/perl);
use RRDs;

Scieżki do bibliotek są prawidłowe, w przypadku wykorzystania skryptów instalacyjnych z tej strony.

Moduły

Do uruchomienia skryptów wymagane jest zainstalowanie kilku modułów. Najprościej zainstalować je w następujący sposób:

# perl -MCPAN -e 'install qw(Digest::MD5 XML::Simple LWP::UserAgent Getopt::Long Time::HiRes)'

Aby instalacja modułów przebiegła bezproblemowo, musimy mieć działające środowisko do kompilacji oprogramowania (Linux). Nie wolno także zapomnieć o instalcji odpowiednich bibliotek, libxml2 i libxml2-dev.

config.xml

W pliku tym przechowywana jest informacja, z których projektów mają być pobierane dane. Autoryzacja odbywa się poprzez podanie adresu email i hasła do projektu lub podania klucza. Można użyć również "słabego" klucza. Przykładowy plik config.xml:

<config>
  <account_email>TWÓJ_ADRES_EMAIL_DLA_BOINC</account_email>
  <account_passwd>TWOJE_HASŁO</account_passwd>
  <projects>
    <!-- DistributedDataMining Project -->
    <project>
      <project_url>http://www.distributeddatamining.org/DistributedDataMining/</project_url>
      <scheduler_url>http://www.distributeddatamining.org/DistributedDataMining_cgi/cgi</scheduler_url>
    </project>
    <!-- World Community Grid -->
    <project>
      <account_email>LOGIN_DO_WCG</account_email>
      <project_url>http://www.worldcommunitygrid.org/</project_url>
    </project>
    <!-- Collatz Conjecture -->
    <project>
      <project_url>http://boinc.thesonntags.com/collatz/</project_url>
      <!-- Alternatywne dane logowania
      <account_email>TWÓJ_ADRES_EMAIL_DLA_BOINC</account_email>
      <account_passwd>TWOJE_HASŁO</account_passwd>
      -->
    </project>
    <!-- POEM@home -->
    <project>
      <project_url>http://boinc.fzk.de/poem/</project_url>
      <!-- Można podać swój klucz dostępu do projektu/konta bezpośrednio, może to być także "słaby" klucz
      <account_key>????????????????????????????????</account_key>
      -->
    </project>
    <!-- PS3GRID -->
    <project>
      <project_url>http://www.ps3grid.net/</project_url>
    </project>
    <!-- MilkyWay@home -->
    <project>
      <project_url>http://milkyway.cs.rpi.edu/milkyway/</project_url>
    </project>
    <!-- SETI@Home -->
    <project>
      <project_url>http://setiathome.berkeley.edu/</project_url>
    </project>
  </projects>
</config>

Plik konfiguracyjny należy dostosować do własnych potrzeb, analogicznie jak podano wyżej.

DistributedDataMining Project - należy koniecznie podać adres schedulera. Nie można go, jakimś dziwnym trafem, wyciągnąć ze strony głównej projektu. Pomimo tego, że standardowy klient BOINC robi to bez problemu :)

World Community Grid - należy podać swój login a nie adres email.

Pobieranie danych z schedulera

get-stats.pl

Skrypt pobierający dane bezpośrednio z schedulera wybranego projektu. Odczytuje on konfigurację z pliku config.xml. Generuje plik stats.xml z zebranymi danymi.

Skrypt, bez przeróbek, działa także pod systemami Windows. Należy jedynie zainstalować ActivePerl.

Wywołanie:

# ./get-stats.pl -c ŚCIEŻKA_DO_PLIKU_KONFIGURACYJNEGO/config.xml -o ŚCIEŻKA_DO_PLIKU_STATYSTYK/stats.xml

W przypadku wywołania bez podawania parametrów, skrypt domyślnie spróbuje otworzyć plik config.xml w bierzącym katalogu, podobnie z plikiem stats.xml, który zostanie utworzony w bierzącym katalogu

Aby zapewnić stały dopływ danych z schedulerów, należy co jakiś czas uruchamiać plik get-stats.pl z odpowiednimi parametrami. W tym celu należy dopisać linijkę do pliku konfiguracyjnego crond

Uruchamiamy w linii poleceń:

# crontab -e

Teraz po otwarciu domyślnego edytora, dodajemy linijkę:

*/15 * * * * PEŁNA_ŚCIEŻKA/get-stats.pl -c PEŁNA_ŚCIEŻKA/config.xml -o PEŁNA_ŚCIEŻKA/stats.xml

Wpis ten uruchamia skrytp pobierający dane co 15 minut. Zamiast PEŁNA_ŚCIEŻKA, należy podać wpisy odpowiednie dla swojej konfiguracji.

Przykładowy plik stats.xml

<stats>
  <host_cpid>?????????????????????????????????</host_cpid>
  <projects>
    <project>
      <project_name>Collatz Conjecture</project_name>
      <project_url>http://boinc.thesonntags.com/collatz/</project_url>
      <user_total_credit>1168738.915939</user_total_credit>
      <user_expavg_credit>388.189664</user_expavg_credit>
      <user_diff_credit>0</user_diff_credit>
      <last_update>1280161212</last_update>
      <hostid>??????</hostid>
      <request_delay>303</request_delay>
    </project>
    <project>
      <project_name>Cosmology@Home</project_name>
      <project_url>http://www.cosmologyathome.org/</project_url>
      <user_total_credit>118790</user_total_credit>
      <user_expavg_credit>348.566062</user_expavg_credit>
      <user_diff_credit>0</user_diff_credit>
      <last_update>1280161217</last_update>
      <hostid>??????</hostid>
      <request_delay>31</request_delay>
    </project>
  </projects>
</stats>
 

Nie ma potrzeby własnoręcznego edytowania pliku stats.xml, chyba że się wie, co się robi.

W systemach Windows, możemy użyć odpowiednika Cron. Zaletą tego programiku, jest możliwość uruchomienia go jako usługi.

W tym momencie, można zakończyć czytanie, jeśli ktoś potrzebuje jedynie wyciągania danych z schedulera. Dane są łatwo dostępne w postaci pliku XML, który można parsować dowolnym oprogramowaniem.

Aktualizacja plików RRD

update-rrd.pl

Skrypt aktualizuje pliki rrd w podanym katalogu, na podstawie danych zgromadzonych w pliku stats.xml. Automatycznie tworzy brakujące pliki rrd, dla nowo dodanych projektów.

Każdy z plików rrd ma bardzo prostą strukturę:

--step=3600
DS:total:GAUGE:86400:0:U
DS:expavg:GAUGE:86400:0:U
DS:avgrac:COUNTER:86400:0:U
RRA:LAST:0.5:1:20000
 

W przypadku opracowania własnej metody aktualizacji plików rrd, należy pamiętać, że dane dla typu COUNTER, muszą być liczbami całkowitymi.

Wywołanie:

# ./update-rrd.pl -i ŚCIEŻKA_DO_PLIKU_STATYSTYK/stats.xml -o ŚCIEŻKA_DO_KATALOGU_Z_PLIKAMI_RRD

Aby na bieżąco aktualizować pliki rrd, należy regularnie uruchamiać plik update-rrd.pl. W tym celu dopiszemy kolejną linijkę do pliku konfiguracyjnego dla crond

Uruchamiamy w linii poleceń:

# crontab -e

Teraz po otwarciu domyślnego edytora, dodajemy linijkę:

1 */1 * * * PEŁNA_ŚCIEŻKA/update-rrd.pl -i PEŁNA_ŚCIEŻKA/stats.xml -o PEŁNA_ŚCIEŻKA/

Wpis ten uruchamia skrypt aktualizujący pliki rrd, minutę po każdej pełnej godzinie. Zamiast PEŁNA_ŚCIEŻKA, należy podać wpisy odpowiednie dla swojej konfiguracji.

Generowane pliki rrd, przechowują dane z ostatnich 833 dni, z rozdzielczością 1h.

Bez problemu mozna zwiekszyć tą rozdzielczość, jednakże schedulery niektórych projektów mają ustawione ograniczecie na częstość zapytań. Objawia się to komunikatem last request too recent.

Generowanie wykresów

Przedstawione poniżej przykłady dotyczą wersji 1.2.26. Nowsze wersje, oferują większe możliwości konfigurowania elementów wykresu.

avgrac_1d.png

Wykresy podstawowe

user_total_credit

Wykres przedstawia nam zmiany całkowitej ilości kredytów w danym projekcie.

example1.png

#!/usr/bin/perl -w
 
use strict;
use lib qw( /usr/local/rrdtool-1.2.26/lib/perl );
use RRDs;
 
RRDs::graph "./example1.png",
    "--title=user_total_credit",
    "--start=-180d",
    "--lower-limit=0",
    "DEF:user_total_credit=www.primegrid.com.rrd:total:LAST",
    "AREA:user_total_credit#0066FF:Total",
    "GPRINT:user_total_credit:LAST:%lf%s\\n";
if ( my $err = RRDs::error ) { print $err }
exit;
 

example1.pl

Wywołanie:

# ./example1.pl

W tym samym katalogu co plik example1.pl, musi znajdować się plik www.primegrid.com.rrd.

user_expavg_credit

Wykres przedstawia nam zmiany RAC dla danego projektu.

example2.png

#!/usr/bin/perl -w
 
use strict;
use lib qw( /usr/local/rrdtool-1.2.26/lib/perl );
use RRDs;
 
RRDs::graph "./example2.png",
    "--title=user_expavg_credit",
    "--start=-90d",
    "--lower-limit=0",
    "DEF:user_expavg_credit=www.primegrid.com.rrd:expavg:LAST",
    "LINE1:user_expavg_credit#0000FF:Current",
    "GPRINT:user_expavg_credit:LAST:%lf%s\\n";
if ( my $err = RRDs::error ) { print $err }
exit;
 

example2.pl

Wywołanie:

# ./example2.pl

W tym samym katalogu co plik example2.pl, musi znajdować się plik www.primegrid.com.rrd.

user_avgrac_credit

Wykres przedstawia nam przyrosty w ilości kredytów z rozdzielczością 1h dla danego projektu.

example3.png

#!/usr/bin/perl -w
 
use strict;
use lib qw( /usr/local/rrdtool-1.2.26/lib/perl );
use RRDs;
 
RRDs::graph "./example3.png",
    "--title=user_avgrac_credit",
    "--start=-5d",
    "DEF:user_avgrac_credit=www.primegrid.com.rrd:avgrac:LAST",
    #mnożymy wartości przez 3600 aby uzyskać przyrosty "na godzinę" a nie domyślne "na sekundę"
    "CDEF:user_avgrac_credit2=user_avgrac_credit,3600,*",
    "AREA:user_avgrac_credit2#0066FF:Last",
    "GPRINT:user_avgrac_credit2:LAST:%lf%s\\n";
if ( my $err = RRDs::error ) { print $err }
exit;
 

example3.pl

Wywołanie:

# ./example3.pl

W tym samym katalogu co plik example3.pl, musi znajdować się plik www.primegrid.com.rrd.

Składanie wykresów

user_total_credit

Analogicznie do przykładu 1. ale tym razem na wykresie umieszczamy dane z dwóch projektów.

example4.png

#!/usr/bin/perl -w
 
use strict;
use lib qw( /usr/local/rrdtool-1.2.26/lib/perl );
use RRDs;
 
RRDs::graph "./example4.png",
    "--title=user_total_credit",
    "--start=-720d",
    "--lower-limit=0",
    "DEF:user_total0=www.primegrid.com.rrd:total:LAST",
    "DEF:user_total1=milkyway.cs.rpi.edu_milkyway.rrd:total:LAST",
    "AREA:user_total0#0066FF:PrimeGrid:STACK",
    "GPRINT:user_total0:LAST:%.2lf%s\\n",
    "AREA:user_total1#FF0000:MilkyWay\@home:STACK",
    "GPRINT:user_total1:LAST:%.2lf%s\\n";
if ( my $err = RRDs::error ) { print $err }
exit;
 

example4.pl

# ./example4.pl

W tym samym katalogu co plik example4.pl, muszą znajdować się pliki www.primegrid.com.rrd oraz milkyway.cs.rpi.edu_milkyway.rrd.

user_expavg_credit

Analogicznie do przykładu 2. ale tym razem na wykresie umieszczamy dane z dwóch projektów.

example5.png

#!/usr/bin/perl -w
 
use strict;
use lib qw( /usr/local/rrdtool-1.2.26/lib/perl );
use RRDs;
 
RRDs::graph "./example5.png",
    "--title=user_expavg_credit",
    "--start=-30d",
    "--lower-limit=0",
    "DEF:user_expavg0=szdg.lpds.sztaki.hu_szdg.rrd:expavg:LAST",
    "DEF:user_expavg1=www.primegrid.com.rrd:expavg:LAST",
    "LINE1:user_expavg0#FF0000:SZTAKI",
    "GPRINT:user_expavg0:LAST:%lf\\n",
    "LINE1:user_expavg1#FF00FF:PrimeGrid",
    "GPRINT:user_expavg1:LAST:%lf\\n";
if ( my $err = RRDs::error ) { print $err }
exit;
 

example5.pl

Wywołanie:

# ./example5.pl

W tym samym katalogu co plik example5.pl, muszą znajdować się pliki www.primegrid.com.rrd oraz szdg.lpds.sztaki.hu_szdg.rrd.

user_total_credit + total

Na tym przykładzie pokażę, jak przedstawić w legendzie wykresu, sumę ilości kredytów z dwóch projektów.

example6.png

#!/usr/bin/perl -w
 
use strict;
use lib qw( /usr/local/rrdtool-1.2.26/lib/perl );
use RRDs;
 
RRDs::graph "./example6.png",
    "--title=user_total_credit",
    "--start=-720d",
    "--width=720",
    "--lower-limit=0",
    "DEF:user_total0=www.primegrid.com.rrd:total:LAST",
    "DEF:user_total1=milkyway.cs.rpi.edu_milkyway.rrd:total:LAST",
    "AREA:user_total0#0066FF:PrimeGrid:STACK",
    "AREA:user_total1#FF0000:MilkyWay\@home:STACK",
    "CDEF:total=user_total0,user_total1,+",# tutaj liczymy sumę dwóch parametrów
    "GPRINT:total:LAST:TOTAL %.2lf";# a tutaj umieszczamy na wykresie
if ( my $err = RRDs::error ) { print $err }
exit;
 

example6.pl

Wywołanie:

# ./example6.pl

W tym samym katalogu co plik example6.pl, muszą znajdować się pliki www.primegrid.com.rrd oraz milkyway.cs.rpi.edu_milkyway.rrd.

Wszelkie operacje matematyczne w RRDTool, wykonywane są w polskiej notacji odwrotnej.

Kolorowanie wykresu

example7.png

#!/usr/bin/perl -w
 
use strict;
use lib qw( /usr/local/rrdtool-1.2.26/lib/perl );
use RRDs;
 
RRDs::graph "./example7.png",
    "--title=user_total_credit",
    "--start=-180d",
    "--lower-limit=0",
    "--color=BACK#7fff00",
    "--color=CANVAS#7f00ff",
    "--color=AXIS#ff007f",
    "--color=FONT#ff7f00",
    "--color=MGRID#ffff00",
    "--color=GRID#ff007f",
    "--color=SHADEA#007fff",
    "--color=SHADEB#00ffff",
    "--color=ARROW#ff0000",
 
    "DEF:user_total_credit=www.primegrid.com.rrd:total:LAST",
    "AREA:user_total_credit#000000:Total",
    "GPRINT:user_total_credit:LAST:%lf%s\\n";
if ( my $err = RRDs::error ) { print $err }
exit;
 
 

example7.pl

Wywołanie:

# ./example7.pl

W tym samym katalogu co plik example7.pl, musi znajdować się plik www.primegrid.com.rrd.

Kolory samych danych, można łatwo zidentyfkować, analizując powyższe przykłady. Poniżej, definiowanie koloru dla tła, czcionek, siatki itd.

"--color=BACK#7fff00"
    #kolor tła całego wykresu
"--color=CANVAS#7f00ff"
    #kolor tła wykresu danych
"--color=AXIS#ff007f"
    #kolor osi x i y
"--color=FONT#ff7f00"
    #kolor czcionek
"--color=MGRID#ffff00"
    #kolor głównych podziałek na wykresie
"--color=GRID#ff007f"
    #kolor pomocniczych podziałek na wykresie
"--color=SHADEA#007fff"
    #kolor dla ramki lewej i górnej
"--color=SHADEB#00ffff"
    #kolor dla ramki prawej i dolnej
"--color=ARROW#ff0000"
    #kolor strzałki na wykresie
 

Każdemu kolorowi można przypisać także przeźroczystość. Na przykład: --color=FONT#FF0000 jest równoważny zapisowi --color=FONT#FF0000FF. Należy zwrócić uwagę na wartość na samym końcu definiowania koloru. Przeźroczystość ustawiona na 50%: --color=FONT#FF000080

Przydatne funkcje

fisher_yates_shuffle() przestawia w sposób losowy elementy tablicy podanej jako parametr.

sub fisher_yates_shuffle {
    my $array = shift;
    my $i;
    for ($i = @$array; --$i; ) {
        my $j = int rand ($i+1);
        next if $i == $j;
        @$array[$i,$j] = @$array[$j,$i];
    }
}
 
# przykład
 
my @array = (1,4,7,34,2);
 
fisher_yates_shuffle(\@array);
 
# przykładowa zawartość tablicy po wywołaniu funkcji
#
# (4,34,7,2,1)
#

hsv2rgb() zmienia nam reprezentację barw w HSV na RGB. Bardzo ułatwia to uzyskanie efektu "spectrum".

# parametry wywołania funkcji
# $h - barwa, zakres 0..359
# $s - nasycenie, zakres 0..1
# $v - natężenie, zakres 0..1
 
sub hsv2rgb {
    my ($h,$s,$v) = @_;
    my $hi = int($h/60) % 6;
    my $f = $h/60 - int($h/60);
    my $p = $v * (1 - $s);
    my $q = $v * (1 - $f * $s);
    my $t = $v * (1 - (1 - $f) * $s);
 
    for ($v,$t,$p,$q) {
        $_ *= 255;
        $_ = $_ > 255 ? 255 : $_;
        $_ = sprintf "%02x",int $_;
    }
 
    return "$v$t$p" if $hi == 0;
    return "$q$v$p" if $hi == 1;
    return "$p$v$t" if $hi == 2;
    return "$p$q$v" if $hi == 3;
    return "$t$p$v" if $hi == 4;
    return "$v$p$q" if $hi == 5;
}
 
# przykłady
 
print hsv2rgb(0,1,1);
 
# wynik ff0000
# czyli kolor czerwony
 
print hsv2rgb(120,0.5,1);
 
# wynik 8cff8c
# czyli wypłowiały zielony :)
 
print hsv2rgb(240,1,0.5);
 
# wynik 00008c
# czyli ciemno-niebieski

Koniec

total_30d.png

@2019-03-29T13:06:52+00:00