Dr.Godfried-Willem RAES

Kursus Experimentele Muziek: Boekdeel 1: Algoritmische Kompositie

Hogeschool Gent : Departement Muziek & Drama


<Terug naar inhoudstafel kursus>

<Web:Multitaskers>

<Web: GMT>

1134:

Multitasking

Het in de inleiding (1130) vermelde bezwaar dat de komputer terwijl hij bezig is met tellen, of met het aflezen van de interne klok, voor geen andere taken beschikbaar is kan niet echt ondervangen worden. Dit probleem is nauw verbonden met het feit dat de personal-komputer zoals we die thans nog kennen wezenlijk een sekwentiele machine is. Dit maakt het grootste verschil uit tussen een biologisch intelligent organisme, dat kan worden opgevat als een trage maar massief parallelle machine en een komputer.

Multitasking nu, is een programmeertechniek die toelaat dit sekwentieel karakter te omzeilen door de komputer met diverse taken tegelijkertijd te belasten op zo'n wijze dat hij de rekentijd gelijkelijk (of volgens een of ander hierarchisch programmeerbaar prioriteitenschema) over verschillende programmasegmenten of zelfs programmas verdeelt. Tenzij men gebruik maakt van de allersnelste beschikbare PC's (vanaf de 80486 geklokt op 90MHz) zijn de rezultaten hiervan voor komplexe muzikale toepassingen bijna steeds ontgoochelend.

Zowat het beste wat m.i. kan gehaald worden kunnen geinteresseerden analyzeren in de kode voor mijn komposities <A Book of Moves>, <Songbook> en vooral <Mach96>, die integraal lopen onder een in Basic geschreven multitasker. Dat ik het sedert dit stuk heb toegepast kwam echter vooral doordat heel veel rekenintensieve taken in <A Book of Moves> als interaktief stuk, door parallel werkende analoge komputers werden opgelost. Overigens dient opgemerkt dat deze multitasker de vergelijking met het Windows- besturingssysteem goed kan doorstaan. De multitasker van Windows is zelfs een stukje trager dan die gerealizeerd in <A Book of Moves>...

De enige echte oplossing bestaat er immers in gebruik te maken van verschillende parallel werkende processoren, die elk onafhankelijk een taak te verwerken krijgen en toch onderling gegevens kunnen uitwisselen. Dit noemt men parallel-processing. Voor de muzikus was dit domein tot voor kort eigenlijk alleen praktisch toegankelijk wanneer hij gebruik maakte van zelf te programmeren dedicated processorboards (8054 bvb.). Het opzet van een dergelijk systeem valt evenwel (misschien voorlopig) buiten het opzet van deze syllabus.

We zeggen voorlopig, omdat het in de lijn der technische verwachtingen ligt dat we binnenkort in zowat alle PC's zgn. DSP processoren zullen gaan aantreffen waarmee heel wat taken parallel met hoofdprocessor kunnen worden afgehandeld. Vooralsnog zijn er nog geen programmeertalen beschikbaar -en zeker geen Basic- waarmee ook deze chips kunnen worden geprogrammeerd.

Elementaire maar performante parallelle systemen zijn ook wel op te bouwen met erg eenvoudige en goedkope processoren zoals bvb. de fameuze 'Basic Stamp' Pic controller.

Multitaskers zijn dus protezen voor echte parallelle systemen. Gezien de snel toenemende kapaciteit van de PC's , hebben we gemeend ook het schrijven multitaskers voor PC's vanaf het Pentium platform ook in deze kursus te kunnen opnemen. We geloven dat vooral in het domein van de real-time algoritmische kompositie, multitaskers zowat de enige overzichtelijke en handzame oplossing bieden.


Opbouw van een multitasker

Stap 1: bepaling van een aantal uit te voeren taken.

Elke taak (een procedure, of een extern gelinkt programma) is al dan niet aktief, en, indien aktief wordt zij gekenmerkt door een eigen prioriteit. Deze prioriteit is steeds een funktie van de periodiciteit waarmee de taak wordt uitgevoerd: hoe hoger de frekwentie, hoe hoger de prioriteit.

Dit kunnen we bvb. implementeren alsvolgt:

' - definieer een variabele waarmee taken kunnen worden geset of gereset en waarmee de prioriteit kan worden bepaald:

CONST nrtask = 4

CONST False = 0

CONST True= NOT False

COMMON SHARED rsi%()

de pointer in dit array komt overeen met het nummer van de betreffende taak. Wanneer het getal in rsi%() 0 is, dan is de taak niet aktief. Wanneer het getal positief is , is de taak aktief. Hoe groter het getal, hoe geringer de prioriteit van de taak zal zijn.

[Memo: rsi staat voor ReSchedule Interval.]

' - bepaal 5 taken, als procedures:

DECLARE SUB Task0

DECLARE SUB Task1

DECLARE SUB Task2

DECLARE SUB Task3

DECLARE SUB Task4

' - dimensioneer het task-scheduling array:

DIM SHARED rsi%(0 TO nrtask)

' - leg prioriteiten vast: (deze kunnen binnen de multitasker zelf gewijzigd worden)

rsi%(0)= 4

rsi%(3)= 255

' - Multitasker:

Counter%=0

DO

Counter%= (Counter%+1) AND &H3FFF

' binnen deze snelle lus worden nu gesette taken afgehandeld:

IF rsi%(0) THEN

IF Counter% MOD rsi%(0) = False THEN Task0

END IF

IF rsi%(1) THEN

IF Counter% MOD rsi%(1) = False THEN Task1

END IF

IF rsi%(2) THEN

IF Counter% MOD rsi%(2) = False THEN Task2

END IF

IF rsi%(3) THEN

IF Counter% MOD rsi%(3) = False THEN Task3

END IF

IF rsi%(4) THEN

IF Counter% MOD rsi%(4) = False THEN Task4

END IF

LOOP

END

De uitvoeringssnelheid van deze multitasker in gekompileerd Basic beloopt meer dan 20000 lussen per sekonden wanneer geen taken zijn geaktiveerd op een Pentium 90MHz in een DOS-venster onder Win95. De praktische lussnelheid hangt uiteraard af van de snelheid van de gebruikte komputer enerzijds, maar ook van de komplexiteit van de kode van de diverse taken zelf evenals van het aantal aktieve taken. Een goed multitasking programma wordt opgebouwd uit een groot aantal zo klein mogelijke taken.

Een taak die beeindigd is kan binnen zijn eigen procedure zichzelf uitschakelen door zijn rsi%() waarde False te maken.

Een van de grote voordelen van multitasking kode, is dat de polling- snelheid van de kode precies kan worden afgestemd op de verversingssnelheid van de te pollen informatie. Een eenvoudig voorbeeld moge dit verduidelijken:

Stel dat we het keyboard zouden aftasten binnen een DO... LOOP konstruktie middels een klassieke INKEY instruktie. Wanneer de loop nu bvb. 5000 keer per sekonde loopt, dan wordt de INKEY instruktie minstens 100 keer meer uitgevoerd dan nodig zou zijn om zelfs de allersnelste typist te volgen. Wanneer we echter de gewraakte INKEY instruktie in ons programma opnemen als een taak waarbij de periodiciteit zo hoog mogelijk nemen -zo dat we net geen binnenkomende tekens missen en geen keyboard-buffer overflow krijgen- dan loopt ons programma reeds heel wat sneller en efficienter.

Voor interaktieve midi-toepassingen is een dergelijke aanpak zelfs imperatief. Een goed voorbeeld van een interaktieve midi-toepassing is terug te vinden in de kode voor mijn <Songbook> uit 1994/1995 en in <Mach96> uit 1996.

De midi-routine -gedefinieerd als een taak- maakt hierbij gebruik van twee fifo-geheugenarrays:

FifoIn%(0 TO MidiBuffer) voor de binnenkomende gegevens

FifoUit%(0 TO MidiBuffer) voor de uit te sturen gegevens.

De procedurekode voor de taak ziet eruit alsvolgt:

SUB Midi

DO

WHILE INP(SP) < 128: FifoIn%(ii%)=INP(DP):ii%=(ii%+1) AND MidiBuffer: WEND

IF jj% <> j% THEN WAIT SP,64,64: OUT DP, FifoUit%(jj%): jj%=(jj%+1) AND MidiBuffer

LOOP UNTIL jj%=j%

END SUB

Merk op dat de pointers ii% en jj% de lokale pointers zijn binnen de procedure. DP, SP en MidiBuffer werden als konstanten gedeklareerd binnen de hoofdmodule:

CONST DP = &H330

CONST SP = &H331

CONST MidiBuffer = &H3FF

Het analyzeren van de in-buffer vormt een afzonderlijke taak. Uitschrijven van gegevens in de uit-buffer eveneens.

In de kode voor automatische interaktieve instrumenten zoals <Autosax> (1996/97) werd de verwerking van real-time midi data nog verder geoptimaliseerd door gebruik te maken van fixed-lenght strings als buffergeheugen voor de midi-input. Dit vereenvoudigt tevens sterk het terugvinden en dekoderen van specifieke midi-berichten, waarbij gebruik kan worden gemaakt van de krachtige basic stringfunkties zoals INSTR, MID$... .


Autoregulering in Multitaskers

We zagen dat taken zichzelf kunnen uitschakelen wanneer ze zijn afgehandeld. Maar, zij kunnen eveneens hun eigen periociteit (her)programmeren. Dit maakt autoregulering mogelijk waarbij we bvb. de frekwentie waarmee een taak dient te worden uitgevoerd kunnen uitdrukken in absolute en dus machineonafhankelijke tijdseenheden. De kode kan verlopen volgens diverse stramienen. Een eerste voorbeeld zou kunnen gaan alsvolgt:

Eerst definieren we een funktie die het aantal lussen per sekonde waaraan de multitasker loopt retourneert:

FUNCTION Lps& (cnt%)

' op een hele snelle machine moet cnt - de waarde van de multitasking teller in de hoofdlus van de multitasker- een long integer zijn om negatieve getallen en overflows te voorkomen...

Static oudetijd!, oldLps&, toggle%

IF toggle% = False THEN

Toggle%= TRUE

oldLps& = 15000 :' anything goes here. Only needed for start-up

ENDIF

' kijk hoeveel tijd er verstreken is sedert vorige oproep:

deltaT! = oudetijd! - tijd!

IF deltaT! > 0 THEN

Lp& = (oldLps& * 3 / 4)+ (cnt% / (deltaT! * 4)) :' low pass filter to eliminate jitter and noise...

ELSE

Lp& = oldLps& :' indien de tijd te klein was, behoudt dan de vorige waarde

END IF

Lps& = Lp&

END FUNCTION

Vervolgens kunnen we binnen elke taak die autoregulerend dient te zijn, aan het einde van de taak-kode, volgende instruktie toevoegen:

Rsi%(taaknummer) = Lps&(cnt%) / gewenstefrekwentie%

Het nadeel van deze konstruktie is dat cnt% shared moet zijn en dat de Lps& funktie misschien al te veel wordt opgeroepen.

Een alternatieve aanpak bestaat erin een zelfregulerende taak te schrijven met een periodiciteit van bvb. minstens 1Hz die een shared variable retourneert met de Lps& waarde.

Op te merken valt dat welke aanpak ook gekozen wordt, de kloktikken van een multitasker nooit helemaal vrij van jitter kunnen worden gemaakt (tenzij natuurlijk alle taken uit identieke kode zouden bestaan en deze dan nog met konstante en gelijke peiodiciteiten zouden worden uitgevoerd... in welks geval we trouwens beter geen multitasker hadden opgezet).

Uitgewerkte kodevoorbeelden kunnen gevonden worden in de bronkode voor mijn komposities <Mach96>, <Winter97> en later dergelijke komposities geschreven binnen GMT. Via mijn homepage kan je ook het in het engels geschreven meer beschouwend artikel lezen over multitaskers als kompositiekoncept. (cfr. link)

Voorts stellen we voor studenten en (real-time) komponisten in spe een library en een manual ter beschikking waarmee ze binnen Basic zelf met multitaskers volgens dit koncept aan de slag kunnen. De nodige files, libraries EN sourcekode is beschikbaar op het web via de URL: ../gmt/Gmt_manual.html. Het hele softwarepakket heb ik <GMT> gedoopt, en ook via de Logos homepage kan er er makkelijk komen. Aanvankelijk was de kode voor gebruik met de professionele Microsoft Basic compiler geschreven en beschikbaar. Sedert 1998 echter is de hele source kode omgezet (en uitgebreid) voor kompilatie met de absoluut superieure Power Basic Windows compiler (V7.02) .

Versies voor C++ zijn ook beschikbaar en werden gemaakt in het kader van afstudeerprojekten toegepaste informatika aan de Gentse universiteit (Prof.Dr.Walter Bossaert) naar aanleiding van de verdere ontwikkeling van mijn onzichtbaar muziekinstrument.


Filedate: 970202/971021/971201/ minor updates on: 2003-11-25

Terug naar inhoudstafel kursus: <Index Kursus>

Naar homepage dr.Godfried-Willem RAES

Naar GMT

Multitaskers .