Herzeel

advertisement
Abstract
The recent multicore revolution presents us with a great challenge: If we want our software to take
advantage of multicore processors, we need to switch to parallel computing, after more than sixty years of
mainly sequential thinking. In this dissertation, we take the stance that the physical parallelism offered by
multicore processors should be treated as a resource that is managed by the virtual machine. That is to say,
we envision virtual machines that automatically parallelize the execution of existing sequential programming
languages. As a concrete case study, we develop an interpreter that automatically parallelizes the execution
of arbitrary (recursive) Scheme code. We choose Scheme for our experiments because it is a minimal
language with all the basic ingredients for expressing the major programming paradigms. Our interpreter by
default parallelizes the execution of procedure calls, speculatively evaluates conditional expressions, and
relies on work stealing for scheduling the generated parallelism. We identify a set of requirements for
correctly combining parallel procedure calling, speculative computation, and side effects, so that the parallel
execution of a program matches the sequential semantics of Scheme. Our most important contribution is the
continuator concept, which automatically manages all of these requirements. The continuator is essentially a
tree-based representation of the execution trace that the interpreter builds as a program runs, to keep track
of the control dependences between program expressions. It allows the interpreter to manage the control
flow of the different parallel threads, makes it possible to abort incorrectly speculated computations without
entirely freezing the interpreter’s execution, and keeps track of the order of side effects to avoid data races.
As one part of the validation, we discuss the results of running an optimized implementation of continuators
against the Clinger benchmark suite for Scheme. The numbers show linear speedups for functional
programs, but code with side effects currently runs in constant time, independent from the number of
available processor cores. This is due to our conservative strategy to treat every side effect as a
synchronization point, but it should be possible to optimize this in future work. We argue that the positive
benchmark numbers show that the overhead of the continuator infrastructure is in an acceptable range, and
that our approach can effectively lead to speedups. A second part of our validation investigates the
reusability of the continuator concept for developing different kinds of parallel interpreters. To this end, we
discuss the design of a pipelined interpreter that also uses the continuator—without any changes—for
managing the control flow of a program. In future work, we plan to integrate our interpreter with dynamic
compilation and hotspot analysis, for example to detect at runtime which parts of a program are interesting
to parallelize, to perform branch prediction, or to detect side effects before their execution is parallelized.
Keywords: Multicore processors, automatic parallelization, parallel programming, interpreters, speculative
computation, continuator
Samenvatting
De recente overschakeling naar multikernprocessoren vormt een ware uitdaging op het gebied van
software-ontwikkeling. Indien we beogen dat onze programma’s voordeel halen uit multikernprocessoren,
dan zullen we moeten overschakelen naar parallel programmeren, hoewel we ons de voorbije zestig jaar
voornamelijk hebben toegespitst op het schrijven van sequentiële programma’s. In deze verhandeling
nemen wij het standpunt in dat we het parallelisme in multikernprocessoren moeten behandelen als een
systeemfaciliteit. Onze visie bestaat eruit virtuele machines te ontwerpen die de uitvoer van programma’s
volledig automatisch paralleliseren. Als een concreet experiment ontwikkelen wij een vertolker die de uitvoer
van Scheme programma’s—zonder enige beperkingen—automatisch paralleliseert. Wij hebben in onze
experimenten voor Scheme gekozen omdat het enerzijds een zeer compacte programmeertaal is en
anderzijds omdat het in Scheme mogelijk is om de meest gangbare programmeerparadigma’s uit te
drukken. Onze vertolker paralleliseert per definitie de uitvoer van procedure-oproepen, speculeert over de
uitvoer van conditionele expressies, en maakt gebruik van de work-stealing techniek om het parallelisme te
verdelen over de verschillende processorkernen. In ons discours identificeren wij de vereisten om parallelle
uitvoer van procedure-oproepen, speculatieve berekeningen, en instructies die de programmastaat
veranderen, te combineren zodat de parallelle uitvoer van een programma overeenkomt met diens
sequentiële semantiek. Onze belangrijkste bijdrage is de continuator, een concept dat ons toelaat om al
deze vereisten in de vertolker in te bouwen. De continuator is een voorstelling van de programma-uitvoer in
de vorm van een boom die door de vertolker opgebouwd wordt tijdens het uitvoeren van een programma.
De vertolker gebruikt deze boomvoorstelling van de programma-uitvoer om de volgorde tussen programmaexpressies bij te houden. Het is dankzij de continuator dat onze parallelle vertolker in staat is om de
volgorde-afhankelijkheden tussen de verschillende parallelle berekeningen bij te houden. De continuator
maakt het ook mogelijk om verkeerdelijk gespeculeerde berekeningen te annuleren zonder dat de vertolker
daarvoor gepauzeerd dient te worden. Tenslotte garandeert de continuator dat de volgorde behouden wordt
van de instructies die de programmastaat aanpassen. Ter validatie hebben we een geoptimaliseerde
implementatie gemaakt van een vertolker die gebruikt maakt van continuatoren. Wij bespreken de resultaten
die we voor deze implementatie verkregen bij het uitvoeren van de Clinger benchmark-testen voor Scheme.
Voor functionele code krijgen we lineaire speedups, maar voor programma’s die veelvuldig gebruik maken
van instructies die de programmastaat aanpassen, krijgen we helemaal geen speedups. Dit is te wijten aan
het feit dat we de uitvoer van zulke instructies altijd synchroniseren—hoewel dat eigenlijk niet altijd nodig is.
Wij denken dit in de toekomst te kunnen verbeteren. Desalniettemin tonen de positieve benchmark-testen
aan dat de overhead van de continuatorinfrastructuur aanvaardbaar is, en dat onze parallelisatiestrategie
kan leiden tot speedups. Een tweede deel van onze validatie bestaat eruit na te gaan of de continuator als
concept herbruikbaar is om andere parallelle vertolkers te implementeren. Om dit te onderzoeken,
bespreken we de implementatie van een vertolker die georganiseerd is als een pipeline, en de continuator—
zonder enige aanpassing—hergebruikt. In toekomstig werk zijn wij van plan om onze vertolker uit te breiden
met dynamische analyse en compilatie, bijvoorbeeld om te detecteren welke delen van een programma het
meeste baat hebben bij parallelle uitvoer, om te kunnen voorspellen welke tak van een conditionele
expressie het meeste kans maakt om uitgevoerd te worden, of om instructies die de programmastaat
aanpassen te detecteren voor ze geparalleliseerd worden.
Trefwoorden: Multikernprocessoren, automatische parallelisatie, parallel programmeren, vertolkers,
speculatieve uitvoer, continuator
Download