page header

november 2008 Archieven

Waarom atop niet op 1?


Geplaatst door gerlof op woensdag 19 november 2008 | Permanente link | Categorie: ATComputing | Reacties: 0

atop, de bijdrage van AT Computing aan de open source community heeft een zeer respectabele tweede plaats behaald in de Amerikaanse uitgave van het onafhankelijke Linux Magazine. Uiteraard vinden onze experts dat het eigenlijk een eerste plaats had moeten zijn, waarom? Dat kunt u hieronder lezen.

Met de ontwikkeling van atop is begonnen toen bleek dat we bij performance-gerelateerde consultancy-opdrachten met de oude trouwe top niet konden zien waar de werkelijke ''resource lekken'' zaten.

Net als atop, deelt top het scherm in tweeën: de bovenste helft voor systeemgegevens, de onderste helft voor individuele processen. Zoals een boekhouder graag ziet waar de post "uitgaven secretariaat" uit bestaat, zo ziet de performance analist graag waar de "kostenpost" 85% CPU-belasting uit bestaat. Boven de streep zien we dat die 85% bezetting bestaat uit bijv. 45% user-mode CPU-belasting en 40% kernel-mode CPU-belasting.

Top splitst op systeemniveau het CPU-verbruik wel op in user mode en kernel mode, maar niet voor individuele processen; top drukt slechts het totaal van die twee af.

Ten tweede kan "top" de totaaltelling niet rond krijgen: de totaaltelling van CPU-tijden onder de streep klopt bijna nooit met de gegevens op systeem-niveau boven de streep. De reden daarvoor is dat top alleen informatie geeft (en kan geven) over processen die lopen op het moment dat top weer een snapshot neemt; processen die tijdens het interval gestopt zijn worden dus niet getoond. Atop krijgt via de standaard Linux-faciliteit "process accounting" ook informatie over processen die sinds de vorige snapshot geëindigd zijn, en neemt het CPU-verbruik van deze processen (voordat ze eindigden) mee in de telling. Bij atop klopt de totaaltelling van CPU-verbruik "onder de streep" dus met de systeemgegevens.

Niet alleen CPU-tijd is van belang: ook over de gebruikte disk- en netwerk-I/O wil je graag weten wat het totaalverbruik is op systeemniveau en per proces. Dat is iets dat top in het geheel niet kan. Daarnaast is atop nauwkeuriger als het gaat om het geheugengebruik. Snelle en voortdurende groeiers in geheugengebruik zijn belangrijker om ``bovenaan'' te zetten dan processen die al geruime tijd draaien en een constant (groot) geheugengebruik laten zien.

Op deze manier kan atop van de vier belangrijkste resources CPU, geheugen, disk-I/O en netwerk-I/O een actuele, kloppende boekhouding laten zien, waar top dat niet of slechts gedeeltelijk kan.

Daarnaast biedt atop nog een bijzondere faciliteit: je kunt atop iedere N minuten een snapshot laten nemen en op laten slaan in een logfile. Vervolgens kun je interactief door deze file heenwandelen, net zoals je dat op de normale manier met atop kunt. Een klacht als "om kwart voor vier was het systeem zó traag..." kun je op deze manier ook de volgende dag nog herleiden tot een op hol geslagen geheugenvretend proces dat het systeem ernstig deed swappen. Uiteraard kan atop ook een tekst-gebaseerde datastroom opleveren zodat je makkelijk met grep, awk en dergelijke aan de slag kunt.

Omdat atop toch al iedere N minuten een snapshot neemt, kan atop -- op dezelfde manier als het commando sar dat doet -- voor systeem-resources een overzicht geven van de belasting door de tijd.

Al met al geeft atop meer en nuttiger informatie dan top. Enthousiast geworden? Kijk op http://www.atcomputing.nl/Tools/atop/ voor meer informatie, screenshots en downloads!

Zie http://www.linux-magazine.com/w3/issue/97/TheBestTopToolsReview.pdf voor het artikel van Linux Magazine.

Shell scripting


Geplaatst door miekg op woensdag 12 november 2008 | Permanente link | Categorie: Tips and Tricks | Reacties: 0

Als je in de UNIX shell programmeert dan gebruik je veel externe utilities om files te manipuleren. Standaard utilities zoals head en tail bijvoorbeeld. Het telkens opstarten van zo'n tooltje levert een (kleine) performance hit op. Zou het daarom niet beter zijn om deze te vervangen door pure shell varianten?

Voor head en tail hebben we dit gedaan in de zsh shell (homepage). Er was wel een paar problemen die opgelost moesten worden:

  1. interpretatie van escape sequences (bv \n) in de files.
  2. lege regels die hier en daar op de proppen kwamen.

Samen met Ton Kersten kwamen we tot de volgende implementaties.

head

Het volgende zsh script implementeert head, er worden twee opties ondersteund: -n N om het aantal regels te selecteren en een -h voor een kleine help.

 1  #!/bin/zsh
 2  IAM="${0##*/}"
 3  typeset -i n=0
 4  
 5  o_line=(-n 10)
 6  zparseopts -D -K -- n:=o_line h=o_help
 7  if [[ $? != 0 || "$o_help" != "" ]]; then
 8      echo "Usage: $IAM [-n LINES] [-h]"
 9      exit 1
10  fi
11  
12  o_line=$o_line[2]
13  files=($@)
14  [[ $o_line -le 0 ]] && exit
15  [[ $#      -eq 0 ]] && files=(/dev/stdin)
16  
17  IFS=''
18  for f in $files; do 
19      n=0
20      while read -r line; do
21      print "${line//\\/\\\\}"
22      n=n+1
23      [[ $n -ge $o_line ]] && break
24      done < $f
25  done

De regels 1-10 zorgen voor de optie parsering en initialiseren wat variabelen. Vanaf regel 12 wordt het interessant. De variabele $o_line heeft in het tweede element het aantal regels dat we willen zien. Hier pakken we dat getal.

Regel 13; de array files wordt gevuld met de overgebleven argumenten.

Regel 14; als het aantal regels dat we willen zien kleiner gelijk 0 is, zijn we snel klaar.

Regel 15; geen files opgegeven? Dan gebruiken we standaard input.

Regel 17; zorg ervoor de er geen interpretaties plaatsvinden door IFS (Internal Field Seperator) variabele leeg te maken.

Regel 18; start de loop die over onze files heen loopt, deze loop eindigt op regel 25.

Regel 20; lees een regel uit de file, gebruik -r voor raw mode (geen interpretatie).

Regel 21: als we een escape karakter tegenkomen, escape deze dan nogmaals, zodat deze weer normaal op het scherm terecht komt als we gaan printen.

Regels 22-23: hebben we al genoeg regels gelezen? Zo ja, ga dan verder met de volgende file.

Regel 24: laat de while-read-loop uit de huidige file lezen.

tail

Hier de implementatie voor tail:

 1  #!/bin/zsh
 2  IAM="${0##*/}"
 3  typeset -i n=0
 4  
 5  o_line=(-n 10)
 6  zparseopts -D -K -- n:=o_line h=o_help
 7  if [[ $? != 0 || "$o_help" != "" ]]; then
 8      echo "Usage: $IAM [-n LINES] [-h]"
 9      exit 1
10  fi
11  
12  o_line=$o_line[2]
13  files=($@)
14  [[ $o_line -le 0 ]] && exit
15  [[ $#      -eq 0 ]] && files=(/dev/stdin)
16  
17  IFS=''
18  for f in $files
19  do
20      lines=()
21      n=1
22      while read -r line
23      do
24          lines[$n]+="${line//\\/\\\\}\n"
25          n=n+1
26  
27          if [[ $n -gt $o_line ]]
28          then
29              let b=$n-$o_line-1
30              lines[$b]=""
31          fi
32      done < $f
33      print "${lines%%\\n}"
34  done

Het begin van tail is bijna identiek aan die van head. De belangrijkste loop begint hier op regel 18. Het gebruikte algoritme van tail is om de laatste N regels te onthouden zodat die, als we het einde van de file hebben bereikt, geprint kunnen worden.

Een tweede iets dat hier gebruikt wordt is dat een waarde in een array in ZSH geleegd kan worden door er een lege string aan toe te wijzen (regels 30 en 31). Zo houden we niet de hele file in memory, maar alleen het stuk dat we willen tailen.

Regel 33 is nodig om de laatste newline in $lines er weer af te strippen.

Is het nu sneller?

Laten we een paar tests doen met een file op een Linuxsysteem, namelijk /proc/interrupts. De scripts hierboven zijn voor deze tests omgebouwd tot de functies: tail_zsh en head_zsh. Dit heeft tot gevolg dat er geen fork wordt uitgevoerd.

Voor de tests gebruiken we de volgende command line:

time ( for i in $(seq 0 20000); do $prog -n 15 /proc/interrupts > /dev/null; done )

Waarbij $prog, respectievelijk head, head_zsh, tail en tail_zsh is.

head vs head_zsh

Voor head:

0.11s user 0.01s system 0.12s elapsed

En head_zsh:

0.11s user 0.01s system 0.12s elapsed

tail vs tail_zsh

Voor tail is de timing:

0.11s user 0.02s system 0.12s elapsed

En voor tail_zsh:

0.11s user 0.01s system 0.12s elapsed

Het lijkt erop dat onze implementaties dus net zo snel zijn als de standaard Linux tools. Waarschijnlijk is de standaard tail implementatie bij grotere files wel veel sneller, aangezien die in een keer naar het einde van de file kan springen. Onze tail moet eerst de gehele file doorspitten.