page header

Programmeren is een kunst...


Geplaatst door jc op 2010-03-01 14:19:32 | Permanente link | Categorie: programmeren | Reacties: 0

Er was eens....

een bank met vele kantoren door het land. De medewerkers in de kantoren klaagden dat de nieuwe computers te traag waren. Dit speelde in de tijd dat electronisch bankieren, pinnen en geldautomaten nog een onbeduidende rol speelden. Klanten gingen naar de bank om geld op te nemen, en door de trage computers ontstonden er lange rijen. Daarom wilde de bank af van het contract met de leverancier.

Maar de leverancier stuurde een performance analyse en tuning expert om de oorzaak van de problemen te onderzoeken. Hij zag al snel dat één specifiek programma vrijwel alle CPU capaciteit opsoupeerde. Met een profiling tool kon hij inzoomen op het programma, en vond hij de uiteindelijke oorzaak. In de source code van het programma stond:

for (i=0; i<strlen(s); ++i) {
    if (... s[i] ...) ...
}

Die string s was gemiddeld vele duizenden karakters lang en iedere aanroep van strlen loopt langs alle karakters van de string op zoek naar de afsluitende null-byte. De string veranderde echter nooit in het lusje, dus hoefde de programmeur ook maar één keer de lengte vast te stellen. Daarmee zouden duizenden aanroepen van strlen bespaard kunnen worden, en dus miljoenen karaktervergelijkingen.

De code (door de bank zelf geschreven) werd snel aangepast, en de bankbedienden leefden nog lang en gelukkig:

n=strlen(s);
for (i=0; i<n; ++i) {
    if (... s[i] ...) ...
}

Had de programmeur niet beter zijn best moeten doen? Hij had toch moeten weten dat door de code zo op te schrijven als hij gedaan had, de code CPU-tijd nodig heeft die kwadratisch schaalt met de lengte van de string?

Iedere programmeur kent het motto: "first make it work, then make it work fast". Hiermee worden de valkuilen van micro-optimalisatie voorkomen. Maar het bovenstaande voorbeeld zou je bijna doen geloven dat de programmeur een Machiavelliaans motto aanhing "first make it work slowly."

Deze onnadenkendheid komt regelmatig voor. En het is niet alleen maar een kwestie van "je moet niet proberen het wiel opnieuw uit te vinden". Soms tikken onwetende programmeurs zonder na te denken "in het wilde weg" en hebben ze op die manier zomaar bubble sort "uitgevonden". En dan zijn ze er misschien nog trots op ook!

Naast het kiezen van het goede algoritme, moet je ook de goede datastructuur kiezen voor het soort probleem dat je aan het oplossen bent. De keuze voor een datastructuur kan erg veel invloed hebben. Als je bijvoorbeeld een gelinkte lijst gebruikt voor de opslag van miljoenen items waar je ook nog in wilt kunnen zoeken, heb je weer een suboptimale oplossing gevonden. Een gehashte datastructuur of een binaire boom laat je in dit geval de te zoeken data veel sneller vinden.

Programmeurs moeten dus het wiel niet proberen uit te vinden, en zoveel mogelijk gebruik maken van bestaande bibliotheken. Maar om problemen zoals die van de bank hierboven te vermijden, moeten de programmeurs wel wéten wat de eigenschappen van algoritmes en datastructuren zijn. Goed programmeerwerk begint dus bij een goede opleiding. Is het alleen maar de mooie opschmück in moderne tekstverwerkers die er voor zorgt dat ze net zo traag aanvoelen als old-school programma's zoals WordStar die in de jaren 80 van de vorige eeuw op 8-bits processor's draaiden in computers met 64KB geheugen?

Velen zeggen dat hergebruik is waar het om draait. Maar bovenal moeten programmeurs weten wanneer je wat op welke manier moet hergebruiken. Ze moeten dus kennis hebben van het probleemdomein, en van algoritmes en datastructuren.

Een goede programmeur weet ook wanneer een inferieur algoritme toch betere resultaten op zal leveren. Als je bijvoorbeeld zeker weet dat je nooit meer dan vijf items wilt sorteren (denk aan de vijf dobbelstenen in een Yahtzee spel), kun je misschien wel het beste kiezen voor bubble sort, omdat dat bubble sort gegeven de beperkte probleemgrootte het snelst en simpelst is.

Dus: leer van anderen (open source helpt!) en lees goede boeken (die je dan wel ook moet snappen). En mocht je de boekenserie bij uitstek goed lezen (Donald Knuths ``The art of computer programming'') zou je nog mazzel kunnen hebben en je onsterfelijk kunnen maken ook: Don Knuth betaalt een hexadecimale dollar ($2,56) voor iedere fout die je in het boek ontdekt.

Hotpluggen van input-devices


Geplaatst door martijn op 2010-02-10 12:41:47 | Permanente link | Categorie: Systeembeheer | Reacties: 0

Ik maak voor mijn clients thuis geen gebruik van een bepaalde distributie en compileer alle software zelf. Dit betekent dat bij mij niet alles zomaar werkt. Een voorbeeld van iets dat niet meteen werkte was het gebruik van een USB muis. Ik gebruikte altijd een PS/2 muis en configureerde Xorg via het configuratiebestand /etc/X11/xorg.conf om de PS/2 muis te gebruiken. Bij de nieuwere versies van Xorg is het configuratiebestand niet meer nodig en ik besloot met de aanschaf van een USB muis meteen over te stappen op de automagische configuratiemethode van Xorg. Ik zal hieronder kort beschrijven wat er nodig is om hotplugging van input-devices onder Xorg aan de praat te krijgen.

Voor hotplugging van input-devices (USB muizen, keyboards, enz.) zijn op dit moment vier componenten van belang op een Linux systeem. Namelijk, de kernel, udev, d-bus, en HAL. De kernel heeft de taak om nieuwe hardware te detecteren. Udev heeft als taak voor de gedetecteerde hardware een device-file (indien nodig) in /dev aan te maken. HAL heeft de taak om de gedetecteerde hardware te identificeren en programma's (zoals Xorg) op de hoogte te stellen dat een bepaald type hardware is aangesloten en hoe deze aangesproken kan worden. De D-bus wordt gebruikt voor de communicatie tussen udev, HAL en programma's die geïnteresseerd zijn in de gedetecteerdehardware.

Ik gebruik momenteel de volgende versies van bovengenoemde software:

  • kernel 2.6.25.9
  • udev 1.13
  • HAL 0.5.13
  • D-Bus 1.2.16
  • Xorg 7.4

Voor de kernel moet ondersteuning voor USB (uhci, ehci) en voor input-devices (Human Interface Devices) worden aangezet. Daarnaast moet ook de "Event interface" worden aangezet. Dit laatste levert device nodes in /dev onder de naam eventX waarbij X dan een nummer is. Via deze device nodes worden dan events van input-devices toegankelijk gemaakt voor bijvoorbeeld de X server. Voor udev dienen we de juiste regels in /etc/udev/rules.d/ toe te voegen zodat de eventX device-files worden aangemaakt. Gelukkig voldoen de standaard bijgeleverde regels van udev. Ik sluit de muis aan en kijk met udevmonitor wat de kernel en udevd voor events uitzetten.

bash-3.2# udevmonitor
udevmonitor will print the received events for:
UDEV the event which udev sends out after rule processing
UEVENT the kernel uevent

...
UEVENT[1265218519.642876] add /devices/pci0000:00/0000:00:10.3/usb5/5-1/5-1:1.0/input/input8/mouse0 (input)
UEVENT[1265218519.659071] add /devices/pci0000:00/0000:00:10.3/usb5/5-1/5-1:1.0/input/input8/event4 (input)
...
UDEV  [1265218519.734160] add /devices/pci0000:00/0000:00:10.3/usb5/5-1/5-1:1.0/input/input8/mouse0 (input)
UDEV  [1265218519.738460] add /devices/pci0000:00/0000:00:10.3/usb5/5-1/5-1:1.0/input/input8/event4 (input)

Ah kijk, daar zien we dat er een input-apparaat wordt gedetecteerd. De udev daemon (udevd) heeft er blijkbaar ook een regel voor (anders zouden we de UDEV regel niet krijgen). Als je wilt zien welke acties udevd allemaal uitvoert op basis van een kernel event (UEVENT) kun je bovenstaande UEVENTs als argument opgeven aan udevtest. Je krijgt dan een hoop tekst te zien maar voor het apparaat waar het hier om gaat is alleen het volgende echt van belang:

bash-3.2# udevtest /devices/pci0000:00/0000:00:10.3/usb5/5-1/5-1:1.0/input/input8/event4
...
udev_node_add: creating device node '/dev/event4', major=13, minor=68, mode=0660, uid=0, gid=0
...

In bovenstaand voorbeeld zien we dat de juiste device-file wordt aangemaakt. Xorg zal dit bestand uitlezen om erachter te komen hoe de muis wordt bewogen. De device-file is een character device en we kunnen deze met bijvoorbeeld met het commando cat uitlezen:

bash-3.2# cat /dev/event4

Als we dan de muis bewegen worden er een heleboel rare karakters op het scherm getoond. Mij zeggen deze karakters niets, maar Xorg weet er hopelijk wel raad mee.

Dit is veel belovend dus ik start Xorg op en probeer de mouse pointer te bewegen over het scherm. Helaas geen beweging in te krijgen. Dat wordt verder puzzelen. Problemen oplossen is vooral het uitsluiten van mogelijke oorzaken. De kernel detecteert de muis en udev pikt het ook op. Dus daar hoef ik me niet op te concentreren. Wellicht dat HAL het apparaat nog niet juist herkend. Eens even kijken of mijn muisje wel wordt opgepikt door HAL.

# hal-device | grep 'input.'
0: udi = '/org/freedesktop/Hal/devices/usb_device_ffffffff_ffffffff_noserial_0_logicaldev_input'
  info.category = 'input'  (string)
  info.capabilities = { 'input', 'input.mouse' } (string list)
  input.originating_device = '/org/freedesktop/Hal/devices/usb_device_ffffffff_ffffffff_noserial_0' (string)
  input.device = '/dev/event4'  (string)
  input.product = 'Kensington USB Mouse'  (string)
  linux.subsystem = 'input'  (string)
  input.x11_driver = 'evdev'  (string)
  info.subsystem = 'input'  (string)
  info.udi = '/org/freedesktop/Hal/devices/usb_device_ffffffff_ffffffff_noserial_0_logicaldev_input' (string)
  linux.sysfs_path = '/sys/devices/pci0000:00/0000:00:10.3/usb5/5-1/5-1:1.0/input/input4/event4' (string)

De daemon hald ziet het apparaat dus correct als input-device. Nog even controleren of ik Xorg wel met HAL ondersteuning gecompileerd heb. Dit is het geval, dus daar kan het ook niet aan liggen. Even controleren of de D-Bus daemon wel draait. Ja, die draait ook. Hmmm, tja, dan weet ik het even niet meer. Ik heb een vermoeden dat Xorg nog een module mist, maar welke? Er zit niets anders op dan de alwetende te raadplegen:

http://www.google.com/search?q=Xorg+HAL+input+devices

Ik krijg een aantal sites als resultaat waarvan de volgende:

http://wiki.archlinux.org/index.php/Xorg_Input_Hotplugging

me duidelijk maakt dat Xorg de module xf86-input-evdev nodig heeft voor input hotplugging. Die had ik inderdaad nog niet gebouwd omdat dat in mijn oude setup niet nodig was. Nadat ik de module gecompileerd en geïnstalleerd heb en Xorg opnieuw heb opgestart probeer ik met vol goede moed mijn muisje. Woohoo! Het kruisje beweegt netjes mee met mijn muisje! En dit allemaal zonder /etc/X11/xorg.conf.

De HAL soap

Bovenstaand verhaal over mijn muisje heeft nog een klein staartje. In de toekomst zal ik bovenstaande waarschijnlijk weer op een andere manier moeten doen aangezien HAL wordt uitgefaseerd. HAL is erg monolithisch en lastig te onderhouden. Om dit op te lossen heeft men HAL opnieuw (modulair) ontwikkeld onder de naam devicekit. Echter, devicekit heeft voordat het enigzins gebruikt werd (Ubuntu en Fedora gebruiken het deels) alweer de doodsteek gekregen en men is tot het inzicht gekomen dat de functionaliteit thuis hoort in udev. In de toekomst zal Xorg dan geen gebruik meer maken van HAL of devicekit maar direct udev aanspreken.

SSH display problemen getackeld


Geplaatst door Ton Kersten op 2010-02-08 11:03:07 | Permanente link | Categorie: Systeembeheer, Tips and Tricks | Reacties: 0

AT Computing heeft enige tijd geleden besloten over te gaan op een compleet nieuwe infrastructuur. Het gewone, bekende spul, zoals een SAN, virtualisatie en Linux.

Nu heb ik aardig wat van die systemen ingericht en geconfigureerd en ik wilde op een duidelijke manier kunnen zien op welke server ik zat. Nu kan dat in de prompt en op allerlei andere manieren, maar mij leek het leuk om dat voor het daadwerkelijke inloggen te doen. Met SSH is het mogelijk om in de configuratie te zetten dat er voor het inloggen een banner wordt getoond. Dit is van oorsprong bedoeld om juridische teksten over het gebruik van het systeem te tonen, maar dat kun je natuurlijk ook voor andere zaken gebruiken.

Nu alleen nog de inhoud van de banner file. Hiervoor heb ik het programma Figlet gebruikt en wanneer ik nu inlog op de server zou het er zo uit moeten zien:

 _ __ ___  _   _ ___  ___ _ ____   _____ _ __ 
| '_ ` _ \| | | / __|/ _ \ '__\ \ / / _ \ '__|
| | | | | | |_| \__ \  __/ |   \ V /  __/ |   
|_| |_| |_|\__, |___/\___|_|    \_/ \___|_|   
           |___/

Maar zo af en toe als ik in log staat er niet wat ik verwacht, maar

 _ __ ___  _   _ ___  ___ _ ____   _____ _ __ 
| '_ ` _ \\| | | / __|/ _ \\ '__\\ \\ / / _ \\ '__|
| | | | | | |_| \\__ \\  __/ |   \\ V /  __/ |   
|_| |_| |_|\\__, |___/\\___|_|    \\_/ \\___|_|   
           |___/

Nou, dat is niet wat ik bedoel. Alle backslashes worden verdubbeld en ik weet nog niet waarom. Discussie met collega's stuurde me richting het programma mingetty, omdat dat de inlog procedure afhandelt. Op ons CentOS 5.4 systeem staat in de source code van mingetty

if ((fd = fopen (ISSUE, "r"))) {
    while ((c = getc (fd)) != EOF) {
        if (c == '\\')
            output_special_char (getc(fd));
        else
            putchar (c);
    }
    fflush (stdout);
    fclose (fd);
}

dus dat zou het best wel eens kunnen zijn.

Om nu niet direct mingetty opnieuw te compileren en allerlei andere problemen te veroorzaken, heb ik als eerste test een mingetty escape code in de banner file opgenomen. Bij het inloggen werd die niet door mingetty geparsed, dus dat kon de oorzaak niet zijn. Even verder nadenkend kwam ik tot de conclusie dat mingetty in het hele spel niet voor komt en dat dit dus een dood spoor is.
Dan zijn er niet meer zo heel veel opties over.

Uit de OpenSSH server source code bleek duidelijk dat daar het probleem niet kon zitten, omdat deze de banner file met een 'atomic write' naar de overkant stuurt. Daar zit dus geen enkele vorm van processing tussen.

Maar als het de server niet is, dan misschien de client. Verder zoekend in de source code toonde aan dat hier het probleem zou moeten zitten. In de file sshconnect2.c staat (in mijn versie, OpenSSH version 5.3p1) de functie input_userauth_banner die de banner laat zien die door de server gestuurd wordt. Op regel 417 staat:

strnvis(msg, raw, len * 4 + 1, VIS_SAFE|VIS_OCTAL);

Dus "unsafe" characters en "octal" tekens worden gecodeerd. De manual pagina van strnvis zegt:

There is one additional flag, VIS_NOSLASH, which inhibits the doubling of backslashes and the backslash before the default format

Ik heb de regel dus veranderd in

strnvis(msg, raw, len * 4 + 1, VIS_SAFE|VIS_OCTAL|VIS_NOSLASH);

en daarna SSH opnieuw gecompileerd. Als ik nu met deze nieuwe client inlog in de nieuwe server, dan is het probleem spoorloos verdwenen.

Toen ik dit probleem als bug report wilde aanmelden bij de OpenSSH ontwikkelaars bleek dat ongeveer een uur voor mij iemand anders dezelfde bug en patch al had ingediend. Het probleem zal worden opgelost in versie 5.4, maar het kan wel even duren voordat het in de distributies beschikbaar is.

Masterbootrecord: R.I.P.


Geplaatst door jacco op 2010-01-26 12:17:25 | Permanente link | Categorie: Systeembeheer | Reacties: 0

Harddiskfabrikanten zitten niet stil. De maximale grootte van een harddisk verdubbelt ongeveer elk jaar.
We leven nu in 2010 en als je naar de beter gesorteerde computerboer gaat kun je probleemloos een 2 terabyte (TB) grote harddisk kopen. Dat kost je de kop niet. Knoop er een paar aan elkaar in een RAID-array en je hebt een hele flinke "disk". Als je een Storage Area Network hebt, kon je al jaren disken van die grootte toekennen.
2 TiB (iets meer dan 2 TB) is voor PC's een magische grens en daarover wil ik het nu hebben.

Die 2 TiB is geen enkel probleem voor de meeste UNIX-filesystemen. Het onder Linux veelgebruikte ext2/ext3-filesysteem kan bijvoorbeeld al files van 2 TiB aan op een filesysteemgrootte van maximaal 16 TiB. En voor ext4 ligt de horizon helemaal ver weg: die kan filesystemen tot 1 EiB (exbibyte) aan (1 EiB ~ 1.048.576 TiB).
Het probleem zit ook niet in de herkenning van de grootte door het BIOS. Want dat werkt al jaren met 48-bits Logical Block Addressing, waarmee tot 128 PiB (pebibyte) aangesproken kan worden.
Maar een filesysteem leg je op een partitie, en het probleem zit hem in de partitionering.
Voor je een disk in gebruik neemt, zul je er een partitietabel op aan moeten maken. De partitietabel is ondergebracht in het Master Boot Record (MBR), een gebied aan het begin van de disk met een omvang van wel 512 hele bytes.

De eerste 440 bytes van het MBR bevatten de bootloader. Deze is nodig om een besturingssysteem te kunnen starten. Daarnaast staat voor elke primaire partitie - waarvan er maximaal 4 op een disk mogen staan - aangegeven wat de start-sector en de lengte van die partitie zijn.
De MBR-layout gebruikt 32 bits adressering, waardoor er 4.294.967.296 sectoren aangesproken kunnen worden. En omdat de meeste harddisken gebruik maken van sectoren van 512 bytes, kan hij tellen tot 2 TiB (4.294.967.296 * 512 = 2.199.023.255.552 bytes = 2048 GiB = 2 TiB).

Laten we eens een partitie van 3 TiB proberen aan te maken op een disk van 4 TiB:


# fdisk /dev/sdb
Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-996142336, default 1): 
Using default value 1
Last cylinder or +size or +sizeM or +sizeK (1-536870911, default 536870911): +3000G
Value out of range.

Hmmm ... value out of range. Dat gaat dus niet werken.
Je kunt de grootte in KiB, MiB, GiB of cylinders opgeven. 1 cylinder bestaat uit 8 sectoren van 512 bytes. De maximale cylinder die je kunt opgeven is 536.870.911, wat overeenkomt met 2048 GiB. fdisk is te oud en kan niet overweg met zeer grote partities/disken.

Maar het MBR - waardoor de beperking tot 2 TiB veroorzaakt wordt - kun je ook niet straffeloos overboord gooien. Want hoe kan een PC anders te weten komen welke partities er op een disk staan en waarvan moet hij dan opstarten?
Je kunt ook de grenzen binnen het masterbootrecord niet oprekken, want daarvoor is geen ruimte beschikbaar.
De oplossing is uitgevonden door Intel en zit in de EFI (Extensible Firmware Interface). EFI is bedoeld als BIOS-vervanger. Onderdeel van EFI is de GPT (GUID Partition Table).
GPT biedt de oplossing voor het 2 TiB probleem. Het mooie is dat GPT los van EFI te gebruiken is. Maar dan moeten de besturingssystemen die gebruik maken van de disk dat wel ondersteunen. Linux doet dat al jaren (RedHat bijvoorbeeld al sinds versie 7.2 uit 2001). Maar Windows XP raakt hiervan compleet van de leg.

Het basisprincipe van GPT is: zet in het masterbootrecord een pointer naar een fake partitie, waar de daadwerkelijke partitie-indeling staat. Om GPT te kunnen gebruiken moet de disk aangemerkt zijn als eentje van het type GPT (i.t.t. tot het "standaard" type MSDOS). Dit kun je niet met fdisk doen, want die doet niet aan GPT, maar wel met parted (uit de stal van GNU) of zijn grafische broerje gparted.


sles10:~ # parted /dev/sdc
GNU Parted 1.6.25.1
Copyright (C) 1998 - 2005 Free Software Foundation, Inc.
This program is free software, covered by the GNU General Public License.

Using /dev/sdc
(parted) mklabel gpt                                                      
(parted) mkpart primary 0 3000G
(parted) print                                                            
Disk geometry for /dev/sdc: 0kB - 4080GB
Disk label type: gpt
Number  Start   End     Size    File system  Name      Flags
1       17kB    3000GB  3000GB 
(parted) quit

Met mklabel gpt geef je aan dat je gebruik gaat maken van GPT, i.p.v. het ouderwetse MBR.

Is GPT noodzakelijk? Ja, zolangzamerhand wel.
Is het dan alles goud wat er blinkt? Nee, dat ook weer niet. Want er zitten nog wel een paar haken en ogen aan het gebruik van GPT:

  • Wanneer het een multi-boot systeem is moet je uitkijken. Windows XP en lager (en nee, daar valt Vista niet onder ...) kunnen niet omgaan met GPT.

  • De Linux-distributie moet kernel-ondersteuning hebben voor GPT. Nu is dat niet zo'n probleem, want alle distro's die de afgelopen 5 jaar zijn uitgekomen hebben dat.

  • Een als MSDOS gelabelde disk - dus met een ouderwets MBR - kun je niet omzetten naar GPT zonder de al bestaande partities kwijt te raken.

Nota Bene: Als je Mac OS X gebruikt (op originele Apple hardware ...), doe je automatisch al aan EFI en GPT.

Meer leesvoer op de websites van IBM of Intel.

De nieuwe taal: Go


Geplaatst door miekg op 2010-01-25 10:37:43 | Permanente link | Reacties: 0

Zeggen de volgende namen je wat? Rob Pike, Ken Thompson en Russ Cox. Misschien zegt die laatste naam je niks, maar de eerste twee personen zijn betrokken geweest bij de ontwikkeling van Unix in 1969. Waarbij Thompson Unix zo'n beetje eigenhandig bij elkaar getypt heeft.

Ook de taal C ontwikkeld door Dennis Ritchie is beinvloed door Thompson. Ritchie en Thompson waren immers collega's bij Bell Labs. C is de afgelopen jaren de standaard geweest voor systeem programmering. Bij systeem programma's kun je denken aan de Linux kernel of lowlevel programma's zoals web- en DNS servers. C is daarin nogal succesvol gebleken...

Tegenwoordig blijkt dat C niet meer voor de volle 100% procent voldoet:

  • Geheugen beheer is en blijft lastig. Jezelf aanleren dat je malloc() moet gebruiken en daarna het gebruikte geheugen weer vrij moet geven met free() kost discipline;
  • Multi-core processoren worden niet door C ondersteund. Tuurlijk, je kunt een C programma schrijven dat prachtig loopt met meerdere processoren, maar makkelijk is het niet en in de taal zelf zit er geen ondersteuning voor ingebakken;
  • De header include files die in C is ontstaan is complex;
  • C is steeds langzamer geworden tijdens de compilatie slag.

Tijd voor een nieuwe taal, die deze en andere nadelen van C goed oplost. Daarom Go!

Go heeft:

  • Automatisch garbage collection; geen malloc() en free() meer, de taal verzorgt dit voor je;
  • Door middel van het go-keyword kun je functies afvuren zodat die als een apart, licht gewicht proces draaien;
  • Communicatie met de go-routines gaat door middel van channels;
  • Supersnelle compilatie, denk hieraan compilaties die binnen 1 - 2 seconden klaar zijn;
  • UTF-8 ondersteuning in strings en in de programma code. Eindelijk Griekse symbolen in je berekening;
  • Strings ingebouwd in de taal (net zoals in Perl, Python, etc.)
  • Een opgelegde coding style;
  • Lol! Go probeert de lol in programmeren terug te brengen.

Hello World

Zoals bij elke nieuwe taal wordt ook de taal Go aangekondigd met het volgende programma:

package main

import fmt "fmt" // Package voor geformatteerde I/O.

func main() { 
    fmt.Printf("Hello, world) 
}

Programmeurs zullen weinig moeite hebben met de bovenstaande code. De accolades van C komen terug in Go, maar de puntkomma's zijn weggelaten. Vergelijkbaar met C begint de uitvoering van een programma door het starten van de functie main(), bij Go hoort deze functie ook nog in het package main te zitten.

Echo

Hier een wat langer voorbeeld uit de introductie van Go, een her-implementatie van het Unix commando echo:

package main

import ( 
    "os"
    "flag" // commando regel opties parser
) 

var omitNewline = flag.Bool("n", false, "print geen regel overgang")

const ( 
    Space = " " 
    Newline = "\n" 
)

func main() { 
    flag.Parse() // Parseer de commando regel
    var s string = "" 
    // Bouw de nieuwe string op 
    for i := 0; i < flag.NArg(); i++ { 
        if i > 0 { 
            s += Space 
        } 
        s += flag.Arg(i) 
    } 
    if !*omitNewline { 
        s += Newline 
    } 
    // Schrijf de string naar buiten
    os.Stdout.WriteString(s) 
}

Wat opvalt aan de bovenstaande code is de eenvoud en de lengte. Een ander innovatief aspect van Go is dat de type aanduiding bij variabelen niet vooraan staat maar achteraan:

var s string

declareert de variabele s als een string. Meerdere variabelen zijn te declareren als:

var s,t string

Natuurlijk raak ik hier maar het topje van de ijsberg en is er nog veel meer te vertellen. Zie daarom ook de links aan het eind van dit document.

Coding style

Een stap waar de Go-auteurs al veel kritiek op hebben gekregen is het afdwingen van een bepaalde codeer stijl. Vergelijkbaar met hoe de taal Python dat doet, maar met een twist. Voor Go geldt het volgende:

De afgesproken codeer stijl is de stijl zoals het programma gofmt het weergeeft.

Alle bibliotheken (packages in Go) zijn ook geformatteerd door gofmt. En, ik moet zeggen, het is ook wel gemakkelijk, nooit meer discussie over waar de opening accolade nu precies moet komen te staan.

Starten met Go

De volgende links zijn interessant, mocht je je meer willen verdiepen in Go.

De Go introductie en geavanceerd programmeren.

Een video, door Rob Pike, over een voorloper taal van Go, Newsqueak genaamd. Hierin zitten veel aspecten die ook in Go terecht zijn gekomen. Newsqueak is nooit vrij gegeven buiten Google.

Een andere taal met vergelijkbare features is Erlang. Deze taal draait op een VM (ala Java), en is een meer functionele taal.

Aangezien de grote namen die achter deze taal staan en omdat het ook nog eens gesponsord wordt door Google verwacht ik er aardig wat van. (Beginners) documentatie op dit moment schaars, maar ook daar wordt aan gewerkt. Wie weet, geeft AT Computing over jaar wel Go cursussen.

Let wel op, de taal zelf is nog volop in ontwikkeling, dus ook op taal niveau worden zaken aangepast c.q. verbeterd.

Vergrotingssoftware


Geplaatst door hjt op 2010-01-05 22:17:54 | Permanente link | Categorie: Tips and Tricks | Reacties: 0

Onlangs kregen we een verzoek of een slechtziende persoon aan een van onze cursussen zou kunnen deelnemen. We hebben in het verleden vaker slechtziende en blinde cursisten gehad, en met wat extra moeite komen zij en wij daar in het algemeen erg tevreden uit.

De docent moet zijn woorden, zijn gebaren, en het schrijven op het bord zorgvuldig op elkaar afstemmen. Dat vereist wat oefening en discipline. Ook de uit te reiken cursusdocumentatie moet aangepast worden afgedrukt, en/of als PDF beschikbaar worden gesteld. Tenslotte moet de werkplek op maat worden ingericht. Over die werkplek gaat de rest van dit verhaaltje.

Deze cursist liet ons weten dat hij graag gebruik zou maken van vergrotingssoftware vergelijkbaar met het produkt ZoomText van ai squared onder Windows. Letters van 2 cm hoogte zouden ideaal zijn.

schermvergroting

Bij zulke grote letters wil je ook een groot scherm. We hebben bij AT een werkplek met een Apple Cinema HD 30 beeldscherm, 40x64 cm, 2560x1600 pixels. Daar hoort natuurlijk een flinke grafische kaart bij: Nvidia GeForce 9600GT. De betreffende computer is ingericht met een recente Ubuntu Linux. Het is een uiterst comfortabele werkplek!

Bij Ubuntu is "gnome-terminal" het gebruikelijke shell-venster. Met de maximale "zoom-in" levert dat op het genoemde beeldscherm 7 mm hoge (m-height) characters. Dat was dus nog niet genoeg. En grafische programma's gebruiken geen gnome-terminal, maar moeten wel mee worden vergroot.

In eerste instantie denk je aan het commando "xmag", maar dat kan alleen statische delen van het scherm vergroten, en is niet echt meer van deze tijd.

In onze Ubuntu Certified Professional cursus komt onder andere "Accessibility" (kort) aan bod. Daaruit wisten we dat de compiz window manager ook zoom-support kan leveren. Daarvoor moet je wel het pakket "simple-ccsm" apart downloaden en installeren. Met de Ubuntu "apt-get" is dat in een paar tellen gebeurd.

Instellen gaat vervolgens via het Ubuntu-menu: System -> Preferences -> Appearance, en daar selecteer je Visual Effects -> Custom

Daarna kun je de combinatie van scrollwiel en "Special"-toets (dat is dan de Windows-toets, zie foto van het keyboard) gebruiken om in- en uit te zoomen. Windows-key Bewegen van de muis geeft "panning": het vergrootglas over de ondergrond bewegen. Het mooie hieraan is dat het hele scherm wordt vergroot. Op de andere foto ziet u een stukje van onze website, gefotografeerd op het betreffende grote beeldscherm, en een telefoontoestel erbij als referentie.

Meer informatie is te vinden op: http://www.howtoforge.com/enabling-compiz-fusion-on-an-ubuntu-9.10-desktop-nvidia-geforce-fx-5200-p2

Voor de volledigheid moet worden gezegd dat naast deze compiz-gebaseerde faciliteiten ook het Orca-project in de gnome window manager uitgebreide faciliteiten voor slechtziende en blinde gebruikers bevat. Een projectbeschrijving vindt u hier en op de website van Willi Walker, de voortrekker van dit project.

Het is qua rekentijd allemaal niet gratis, maar je krijgt wel wat moois. De cursist "voelde zich met deze werkplek verwend".

Inotify


Geplaatst door miekg op vr dec 4 10:00:31 CET 2009 | Permanente link | Categorie: Systeembeheer | Reacties: 0

Tijdens onze werkzaamheden bij Octrooicentrum Nederland kwam er iemand met het volgende probleem. Er was die nacht een bestand aangemaakt in een directory en hij wilde eigenlijk weten welk proces daarvoor verantwoordelijk was. Een interessante vraag en mijn eerste reactie was: "Kan niet".

Totdat ik me 's avonds bedacht dat het misschien wel kon, met het inotify framework in Linux. Met inotify kun je je filesysteem in de gaten houden en een seintje krijgen als er iets wordt aangemaakt, wordt gelezen, wordt beschreven, etc.

Met man 7 inotify lees je hoe een en ander geimplementeerd is. De bijbehorende tools kunnen met:

# apt-get install inotify-tools

geinstalleerd worden. Daarmee krijg je toegang tot de inotify API. Er worden een tweetal tools geinstalleerd inotifywatch en inotifywait.

Inotify kan standaard maar een beperkt aantal directories in de gaten houden. Om dat op te rekken moeten we in /proc naar een bepaalde file een nieuwe waarde schrijven:

% sudo -s
# echo $((2 ** 16)) > /proc/sys/fs/inotify/max_user_watches

64K watches zou genoeg moeten zijn voor deze tests. Het daadwerkelijk starten van inotifywait gaat met:

% inotifywait -m  -r --format '%:e %f' ~
Setting up watches.  Beware: since -r was given, this may take a while!
Watches established.

Waar

  • -m: blijf wachten;
  • --format '%:e %f': iets andere output (zie de manual page)
  • -r: recursief, bekijk alles onder ~.

Nu maak ik in mijn home directory een file aan:

% touch bliep

En ik zie in mijn andere schermpje aardig wat output voorbij komen, waaronder:

CREATE bliep
OPEN bliep
ATTRIB bliep
CLOSE_WRITE:CLOSE bliep

Oftewel, er is gedetecteerd dat de file ~/bliep is aangemaakt. Verder zie je dat touch blijkbaar de file daarna opent, de meta data verandert (ATTRIB regel) en de file daarna sluit.

Schrijvend process ontdekken

We creeeren hier een race conditie omdat er tijd zit tussen het daadwerkelijk aanmaken van de file en het kijken met lsof. Dus dit is niet bullet proof.

We starten onze inotifywait en wel zo dat we kijken of de file bliep wordt gemaakt en zo ja, dan controleren we meteen of we het proces kunnen achterhalen.

% inotifywait -m  -r --format '%:e %f' ~ | grep -q 'CREATE bliep' && \
lsof -t ~/bliep | xargs pstree -a -h

Met lsof kun je achterhalen welk proces de file ~/bliep geopend heeft, lsof print (als die iets vindt) de PID op standard output. Deze PID vangen we op met xargs en geven we door aan pstree die de naam van het process achterhaalt.

Dus als ik nu intussen in een andere terminal:

% touch bliep && tail -f bliep

geef, dan zal de inotifywait pipeline hierboven als output geven:

tail -f bliep

Oftewel het tail commando is nu nog bezig met de file bliep. Het touch commando krijgen we niet te pakken want die is al lang en breed klaar.

Inotify is een krachtig framework waar je interessante toepassingen voor kunt bedenken. En waarvan dit er een is. Een ander idee is bijvoorbeeld een on-the-fly backup toepassing.

Andere tools die gebaseerd zijn op inotify zijn onder meer:

incron
cron-like daemon met support voor filesysteem events
inotail
tail vervanger die inotify gebruikt, waarschijnlijk sneller dan de huidige GNU tail -f

Wat meer achtergrondinformatie is hier te vinden, gemaakt door de originele auteur van het framework Robert Love.

Git Hash filters


Geplaatst door tonk op do okt 1 13:58:58 CEST 2009 | Permanente link | Reacties: 0

Enige tijd geleden schreven Miek en ik hier op het blog over de evolutie van scripts. Het gebruikte script, met de naam vigit is enige tijd naar tevredenheid op onze systemen gebruikt. Maar er zat mij toch iets dwars. Wanneer een bestand met behulp van vigit bewerkt werd, dan werd het wel netjes in de git repository ingechecked, maar daarna werd ook automatisch de Hash:: regel aangepast. Het commando

git diff

leverde dan ook altijd veel verschillen ten opzichte van de respository op.

Weer eens zwervend op het wereld wijde web ontdekte ik plotseling iets over Git filters. Dat bracht mij op de gedachte om de Hash:: verandering door een filter te laten doen, zodat de inhoud van de repository overeenkomt met de huidige versie.

Als eerste dient Git te weten welk filter gebruikt moet worden en waar de onderdelen van dit filter staan. Per filter zijn twee filter mogelijkheden aanwezig, namelijk clean; die wordt gebruikt bij het inchecken en smudge, die wordt gebruikt bij het uitchecken.

In het bestand ~/.gitconfig staan nu de volgende regels:

[filter "git_vi"]
    smudge = /usr/local/bin/git.expand
    clean = /usr/local/bin/git.collapse

Hierbij zijn natuurlijk ook de twee filter programma's nodig.

Dit is git.expand

#!/bin/bash
spc="$(printf "%80s" "")"
who=${SUDO_USER:-${LOGNAME}}
id=$(git show -s --pretty=format:"%H (${who})")
id="${id}${spc}"
sed -e 's!\([[:space:]]*\$[H]ash::\).*\$:!\1 '"${id:0:66}"'\$:!'

en git.collapse

#!/bin/bash
spc="$(printf "%80s" "")"
sed -e 's!\([[:space:]]*\$[H]ash::\).*\$:!\1 '"${spc:0:66}"'\$:!'

Maar, git moet ook weten voor welk bestand welk filter aangeroepen moet worden. Deze informatie staat in het bestand .gitattributes in de directory waar ook de .git repository directory staat.

De inhoud van dit bestand is:

*.[ch]  filter=git_vi
*.sh    filter=git_vi
*.pl    filter=git_vi
*.tex   filter=git_vi
*.cls   filter=git_vi

Wanneer dit allemaal geconfigureerd is, dan wordt bij een checkin het filter programma git.collapse uitgevoerd, dat de Hash:: regel netjes opruimt. In de Git repository staat dan ook geen Hash:: informatie in de ingecheckte bestanden.

Bij een checkout wordt het git.expand filter-programma uitgevoerd. Dit programma haalt de Hash informatie voor dit bestand uit Git en plaatst dat op de Hash:: regel van het bestand.

Om dit allemaal mogelijk te maken, waren ook wat veranderingen nodig aan het vigit programma. Om problemen te voorkomen is het programma dan ook omgedoopt tot git.vi.

Het volledige git.vi programma is hier te vinden.

40 jaar UNIX


Geplaatst door jc op ma jul 20 08:45:49 CEST 2009 | Permanente link | Categorie: Meta | Reacties: 0

UNIX - a giant leap for mankind...

Zomer 1969: Op 20 juli zit de hele wereld aan de TV gekluisterd om de eerste voetstappen van een mens op de maan te zien.

Terwijl Neil Armstrong zijn woorden "A small step for a man, a giant leap for mankind" uitspreekt, vindt in AT&T Bell laboratories in Murray Hill, New Jersey een technische revolutie plaats die zo mogelijk nog meer directe invloed op ons leven nu heeft: Ken Thompson en Dennis Ritchie bedenken UNIX.

De basis-ideeen in UNIX uit die zomer van 1969 waren baanbrekend. Daarom worden de concepten nog steeds gebruikt, niet alleen in UNIX varianten (waaronder Linux en MacOS X) maar ook in andere moderne besturingssystemen zoals Windows XP en zijn opvolgers. Niet voor niets mochten Thompson en Ritchie in 1983 de Turing award ontvangen voor hun werk. De Turing award wordt wel gezien als de Nobelprijs van de informatica.

Na 10 jaar UNIX systemen beheerd te hebben beginnen Ger Austen en Hendrik-Jan Thomassen (A en T) in 1985 het bedrijf AT Computing; het eerste cursus- en consultancybedrijf op het gebied van UNIX in Nederland.

Ruim 20 jaar na het ontstaan van UNIX bouwt in 1991 de Finse student Linus Torvalds het UNIX compatible systeem Linux.

Inmiddels zijn we veertig jaar na de eerste schreden van Neil Armstrong, en heeft Linux met zijn 18 jaren een volwassen leeftijd! En wat zien we: Het aantal UNIX-achtige systemen en dan met name Linux groeit en groeit.

UNIX en Linux worden gebruikt op zeer kleine en zeer grote installaties. Zo is kans groot dat als u een ADSL router heeft, u daar Linux in heeft draaien. Dat geldt ook voor navigatie apparaten, televisies, digitale videorecorders, kassa's bij supermarkten en warenhuizen, reclamezuilen etc etc. En wie een hippe iPhone van Apple gebruikt, beleeft ook dagelijks plezier van het UNIX dat binnenin het kleinood zijn werk doet...

Ook grote UNIX en Linux installaties worden door iedereen dagelijks gebruikt: Het is algemeen bekend dat zoekdienst Google vele honderduizenden Linux systemen laat samenwerken tot de website die iedereen kent. En bekende sites als Ebay, Amazon, bol.com en de Nederlandse Spoorwegen zijn UNIX en Linux grootgebruikers. Van de 500 grootste en snelste computers in de wereld werkt ruim 95% met UNIX of Linux.

Kortom: Is UNIX na 40 dienstjaren pensioengerechtigd en afgeschreven? Nee, integendeel! UNIX is springlevend! U zult nog veel van UNIX en Linux gebruik maken.

AT Computing - Verstand van UNIX, gevoel voor UNIX - al 25 jaar.

Vol filesysteem en output redirection


Geplaatst door miekg op wo jun 24 10:39:42 CEST 2009 | Permanente link | Categorie: Systeembeheer | Reacties: 0

Tijdens het geven van een cursus maakte een cursist mij attent op het volgende:

$ ps -ef > /tmp/file

op een vol filesystem (/tmp is 100% gevuld) geeft dit geen foutmelding!

Dit artikel beschrijft de achter liggende oorzaken en geeft een verklaring voor dit gedrag.

Eerst is het zaak om een filesystem (partitie) 100% gevuld te krijgen. Het filesystem dat we gebruiken is gemount onder /media/disk.

$ cp /dev/zero /media/disk/GROTEFILE                 
cp: writing `/media/disk/GROTEFILE': No space left on device

Om te testen maken we een klein test programmaatje in C:

int 
main(void) 
{
    write(1, "hallo\n", 6);
}

Dit schrijft 6 bytes hallo\n naar standard output. Let op: we vergeten hier opzettelijk om te controleren of het schrijven goed is gegaan. De write() system call geeft namelijk terug hoeveel karakters er daadwerkelijk zijn geschreven. Zie ook man 2 write.

Na een compilatie hebben we ons programmaatje schrijf:

$ gcc schrijf.c -o schrijf

Nu kunnen we de normale input/output redirection toepassen en die doet wat je verwacht:

$ ./schrijf > tijdelijke_file
$ cat tijdelijke_file
hallo

Laten we dit nu eens uit proberen op het filesysteem dat 100% vol is.

$ ./schrijf > /media/disk/tijdelijke_file

Geen foutmeldingen - dus blijkbaar is het goed gegaan.

$ ls -l /media/disk/tijdelijke_file
-rw-rw-r-- 1 miekg miekg 0 Jun 10 12:47 /media/disk/tijdelijke_file

De file is blijkbaar wel aangemaakt, maar heeft als grootte 0 bytes. We kunnen ons nu 2 vragen stellen. Waarom is de file eigenlijk aangemaakt, het filesystem zat toch vol? En ten tweede, waarom zit er geen data in de file aangezien er geen enkele foutmelding is?

Directories

Als je onder Linux (en ook Unix) een directory aanmaakt dan geeft ls -ldh weer dat deze (lege) directory 4.0K groot is:

$ mkdir /tmp/test
$ ls -ldh /tmp/test
drwxrwxr-x 2 miekg miekg 4.0K Jun 10 12:52 /tmp/test

De 4.0K wordt alvast gereserveerd, als ik nu files (en/of subdirectories) aanmaak onder /tmp/test zal de grootte van de directory /tmp/test pas vergroot worden als we over de 4.0K heen gaan. Typisch wordt de grootte dan 12.0K (op Linux)

$ cd /tmp/test
$ for i in $(seq 0 260); do echo $i; touch file.$i; done
$ ls -ldh /tmp/test
drwxrwxr-x 2 miekg miekg 12K Jun 10 12:59 /tmp/test

Dus zolang je de reservering niet overschrijdt kun je (lege) files blijven aanmaken.

Op een vol filesysteem is het meestal nog mogelijk om een file aan te maken als je daarmee maar niet de reservering overschrijdt.

Schrijven van de data

Als we ./schrijf > media/disk/tijdelijke_file opschrijven, dan weet schrijf niet dat hij naar disk schrijft. schrijf schrijft naar zijn stdout. En in dit geval controleert schrijf ook niet of het schrijven gelukt is. Als we deze controle wel inbouwen, dan is de situatie geheel anders.

Eerst passen we de source aan:

int 
main(void) 
{
    if (write(1, "hallo\n", 6) != 6) {
        write(2, "schrijf: schrijf fout\n", 20);
        return 1;
    }
    return 0;
}

Opnieuw compileren

$ gcc schrijf.c -o schrijf

Opnieuw testen met:

$ ./schrijf > /media/disk/tijdelijke_file
schrijf: schrijf fout

Nu is in schrijf dit euvel verholpen, maar het zal je misschien verbazen dat het ook in andere programma's mis gaat.

De volgende commando's gaan allemaal de mist in zonder een foutmelding te geven:

$ ps -ef > /media/disk/tijdelijke_file  

$ free > /media/disk/tijdelijke_file     

$ grep 'as' testfile > /media/disk/tijdelijke_file           

$ perl -e 'print "hallo";' > /media/disk/tijdelijke_file

Gelukkig zijn er ook nog programma's die het wel goed doen:

$ who > /media/disk/tijdelijke_file
who: write error: No space left on device

Ook veel (zo niet alle) programma's gemaakt door GNU vertonen het juiste gedrag.