Tips en Trucs 2012

Geheugen snelheidstest met bash en memxfer

Een desktop computer werkt vandaag de dag vlot met een werkgeheugen van 4 GB, met 8 GB werkgeheugen zit je nog een paar jaar veilig.

Naast de hoeveelheid aan geheugen is ook de toegangssnelheid van het geheugen van belang. Dit kunnen we testen met memxfer, een hulpmiddel van IBM en later bewerkt door Jörg Arndt (http://www.jjj.de/memxfer/)

memxfer compileren of niet?

Op de site van Jörg Arndt staat zowel de broncode (memxferjj.cc) als een executable (memxferjj).

Laten we beginnen met de executable memxferjj: Het grote voordeel van een vooraf door de ontwerper gecompileerd programma is dat het op alle computers werkt, sommigen noemen dit portable. Het nadeel is dat het geen gebruik maakt van moderne verbeteringen van uw processor en nieuwe technieken van compilers. M.a.w. het programma minder efficiënt werkt. Vooral bij snelheidstests kan dit een rol spelen. We willen namelijk vooral weten hoe snel het werkgeheugen in onze computer werkt, m.a.w. hoe snel de processor met moderne compilertechnieken het werkgeheugen kan benaderen. Dan kun je beter de broncode zelf compileren. In het geval van memxfer is dit zelfs zeer eenvoudig (eenvoudig programma, de procedure wordt beschreven in de broncode zelf):

memxfer gebruiken

Door de opdracht ./memxfer zonder argumenten uit te voeren, wordt een korte handleiding weergegeven.
dany@linux-ezca:~/Downloads> ./memxfer 
Usage: ./memxfer [-f] [-s] [+p] size cnt [method [method2...]]
        -f flag says to malloc and free of the "cnt" times.
        -s = silent; only print averages
        +p = no prep
        methods:                                                                                                                                 
         0:     "memcpy"
         1:     "char *"
         2:     "short *"
         3:     "int *"
         4:     "long *"
         5:     "long * (4x unrolled)"
         6:     "int64 *"
         7:     "double *"
         8:     "double * (4x unrolled)"

Merk op dat memxfer op acht verschillende manieren de snelheid van het werkgeheugen kan testen.

Met de hulp van bash

Om de acht verschillende testmethoden na elkaar uit te voeren, gebruik je de volgende opdrachtregel:
dany@linux-ezca:~/Downloads> for r in 1 2 3 4 5 6 7 8; do ./memxfer -s 32M 100 $r; done
avg:   33554432  [ 1]"char *"                   2163.280 MB/s
avg:   33554432  [ 2]"short *"                  2809.504 MB/s
avg:   33554432  [ 3]"int *"                    2956.593 MB/s
avg:   33554432  [ 4]"long *"                   3083.565 MB/s
avg:   33554432  [ 5]"long * (4x unrolled)"     3086.381 MB/s
avg:   33554432  [ 6]"int64 *"                  3083.698 MB/s
avg:   33554432  [ 7]"double *"                 3082.047 MB/s
avg:   33554432  [ 8]"double * (4x unrolled)"   3081.545 MB/s
Dit kan je korter met:
dany@linux-ezca:~/Downloads> for r in $(seq 1 8); do ./memxfer -s 32M 100 $r; done
avg:   33554432  [ 1]"char *"                   2161.334 MB/s
avg:   33554432  [ 2]"short *"                  2768.463 MB/s
avg:   33554432  [ 3]"int *"                    2950.818 MB/s
avg:   33554432  [ 4]"long *"                   3058.530 MB/s
avg:   33554432  [ 5]"long * (4x unrolled)"     3082.649 MB/s
avg:   33554432  [ 6]"int64 *"                  3042.939 MB/s
avg:   33554432  [ 7]"double *"                 3085.137 MB/s
avg:   33554432  [ 8]"double * (4x unrolled)"   3068.688 MB/s
Of met een iets minder bekende methode:
dany@linux-ezca:~/Downloads> for r in {1..8}; do ./memxfer -s 32M 100 $r; done
avg:   33554432  [ 1]"char *"                   2164.142 MB/s
avg:   33554432  [ 2]"short *"                  2772.308 MB/s
avg:   33554432  [ 3]"int *"                    2952.784 MB/s
avg:   33554432  [ 4]"long *"                   3058.896 MB/s
avg:   33554432  [ 5]"long * (4x unrolled)"     3081.062 MB/s
avg:   33554432  [ 6]"int64 *"                  3041.545 MB/s
avg:   33554432  [ 7]"double *"                 3084.304 MB/s
avg:   33554432  [ 8]"double * (4x unrolled)"   3066.994 MB/s
Om de invloed van de grootte van het geteste geheugenblok na te gaan testen we geheugenblokken die telkens verdubbelen (machten van 2). We gaan deze machten vanzelfsprekend niet één voor één opsommen, maar in de lus berekenen:
dany@linux-ezca:~/Downloads> for s in {0..16}; do ./memxfer -s $((1<<$s))k 100 1; done
avg:       1024  [ 1]"char *"                   1207.176 MB/s
avg:       2048  [ 1]"char *"                   1002.119 MB/s
avg:       4096  [ 1]"char *"                   1006.509 MB/s
avg:       8192  [ 1]"char *"                   1010.650 MB/s
avg:      16384  [ 1]"char *"                   1006.117 MB/s
avg:      32768  [ 1]"char *"                    992.347 MB/s
avg:      65536  [ 1]"char *"                   2764.228 MB/s
avg:     131072  [ 1]"char *"                   2734.630 MB/s
avg:     262144  [ 1]"char *"                   2734.333 MB/s
avg:     524288  [ 1]"char *"                   2713.695 MB/s
avg:    1048576  [ 1]"char *"                   2778.773 MB/s
avg:    2097152  [ 1]"char *"                   2769.165 MB/s
avg:    4194304  [ 1]"char *"                   2364.360 MB/s
avg:    8388608  [ 1]"char *"                   2204.403 MB/s
avg:   16777216  [ 1]"char *"                   2190.226 MB/s
avg:   33554432  [ 1]"char *"                   2156.628 MB/s
avg:   67108864  [ 1]"char *"                   2145.675 MB/s
Als we alles samenvoegen, krijgen we:
dany@linux-ezca:~/Downloads> for r in {0..8}; do
>    for s in {0..16}; do
>      ./memxfer -s $((1<<$s))k 100 $r
>    done
> done
avg:       1024  [ 0]"memcpy"                   16213.614 MB/s
avg:       2048  [ 0]"memcpy"                   39811.394 MB/s
avg:       4096  [ 0]"memcpy"                   49445.190 MB/s
avg:       8192  [ 0]"memcpy"                   48926.391 MB/s
avg:      16384  [ 0]"memcpy"                   32541.780 MB/s
avg:      32768  [ 0]"memcpy"                   26021.956 MB/s
avg:      65536  [ 0]"memcpy"                   24515.824 MB/s
avg:     131072  [ 0]"memcpy"                   21592.253 MB/s
avg:     262144  [ 0]"memcpy"                   21293.841 MB/s
avg:     524288  [ 0]"memcpy"                   20815.246 MB/s
avg:    1048576  [ 0]"memcpy"                   8887.402 MB/s
avg:    2097152  [ 0]"memcpy"                   6950.255 MB/s
avg:    4194304  [ 0]"memcpy"                   5424.462 MB/s
avg:    8388608  [ 0]"memcpy"                   3783.830 MB/s
avg:   16777216  [ 0]"memcpy"                   3738.056 MB/s
avg:   33554432  [ 0]"memcpy"                   3618.940 MB/s
avg:   67108864  [ 0]"memcpy"                   3612.698 MB/s
...
avg:       1024  [ 8]"double * (4x unrolled)"   23819.537 MB/s
avg:       2048  [ 8]"double * (4x unrolled)"   24113.726 MB/s
avg:       4096  [ 8]"double * (4x unrolled)"   26067.362 MB/s
avg:       8192  [ 8]"double * (4x unrolled)"   24474.690 MB/s
avg:      16384  [ 8]"double * (4x unrolled)"   24815.116 MB/s
avg:      32768  [ 8]"double * (4x unrolled)"   21399.927 MB/s
avg:      65536  [ 8]"double * (4x unrolled)"   22076.111 MB/s
avg:     131072  [ 8]"double * (4x unrolled)"   21364.054 MB/s
avg:     262144  [ 8]"double * (4x unrolled)"   21044.705 MB/s
avg:     524288  [ 8]"double * (4x unrolled)"   17799.512 MB/s
avg:    1048576  [ 8]"double * (4x unrolled)"   17196.644 MB/s
avg:    2097152  [ 8]"double * (4x unrolled)"   15538.839 MB/s
avg:    4194304  [ 8]"double * (4x unrolled)"   3705.349 MB/s
avg:    8388608  [ 8]"double * (4x unrolled)"   3145.186 MB/s
avg:   16777216  [ 8]"double * (4x unrolled)"   3165.120 MB/s
avg:   33554432  [ 8]"double * (4x unrolled)"   3067.414 MB/s
avg:   67108864  [ 8]"double * (4x unrolled)"   3051.317 MB/s

Bash en accolades

Met accolades kun je in bash zeer eenvoudig een reeks getallen aanmaken. Maar er is meer mogelijk:
dany@linux-ezca:~/Downloads> echo woord{1..4}
woord1 woord2 woord3 woord4
Dit werkt ook met letters:
dany@linux-ezca:~/Downloads> echo letter:{a..f}
letter:a letter:b letter:c letter:d letter:e letter:f
Je kunt zelfs combineren tot permutaties en terugtellen:
dany@linux-ezca:~/Downloads> echo {a..c}{11..13}{z..w}
a11z a11y a11x a11w a12z a12y a12x a12w a13z a13y a13x a13w b11z b11y b11x b11w b12z b12y b12x b12w b13z b13y b13x b13w c11z c11y c11x c11w c12z c12y c12x c12w c13z c13y c13x c13w
Om te eindigen deze opmerking: als je een teller wilt met een verschillend aantal cijfers, kan je gebruik maken van voorloopnullen:
dany@linux-ezca:~/Downloads> echo {001..100}
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100