Moin, wir haben in einem Uni-Projekt einen SPARC-Prozessor so veraendert, dass er in einem interleaved Betrieb mehrere Threads gleichzeitig ausfuehren kann. Dem Programm erscheint der Prozessor dabei wie sechs parallele Rechner. Bei einem Reset beginnt der Prozessor jeden Thread an einer bestimmten Stelle im Bytecode. Das funktioniert mit einfachen Programmen bestens, aber wie mache ich es mit komplizierteren, in die Bibliotheken gelinkt werden? Gibt es eine Moeglichkeit, die einzelnen Threads soweit zu linken, dass die Bibliotheken schon eingebunden sind, und dann das ganze in ein Programm mit den entsprechenden Einsprungstellen zu linken? Muss ich dabei fuer jedes Programm einen eigenen Linkerscript schreiben oder geht es mit einem zentralen? Speziell, wie behandle ich die einzelnen init-Sektionen und wie unterscheide ich die? Gruss, Joern
Dein Grundproblem ist, soweit ich verstanden habe, die Trennung der Adressräume der einzelnen Programme voneinander. In üblichen Multitasking-Umgebungen hilft es enorm, wenn die CPU eine MMU hat und jedes Programm so seinen eigenen virtuellen Adressraum erhält, wenn der Scheduler des Betriebssystem dem Programm seinen Rechenzeitabschnitt zuteilt. Was du mit "interleaved Betrieb" meinst, ist mir unklar. Habit ihr den üblichen Scheduler durch Veränderung der CPU per Hardware implementiert?
Die normale SPARC-Implementierung besitzt eine siebenstufige Pipeline. Wir haben diese so veraendert, dass sie mit jedem Takt den Thread wechselt, so dass nur unabhaengige Threads gleichzeitig in der Pipeline sind, was einige Hazards zu vermeiden hilft und speziell bei uns die praktisch gleichzeitige Ausfuehrung mehrerer Interrupthandler ermoeglichen soll. Eine MMU besitzt der SPARC auch, die wollten wir aber ungern veraendern, weil dafuer die Zeit wohl nicht reicht. Statt dessen wuerden wir gern die einzelnen Threads so linken, dass sie ein Programm in einem zusammenhaengenden Adressraum ergeben. Das geht mit einfachen Programmen bestens, aber initialisierungs Code im .init-Segment stellen mich da vor ein Problem. Im Moment ist das Multithreading so geloest, dass der Prozessor nach einem Reset sieben verschiedene Einsprungstellen nacheinander laed. Kann ich nun die einzelnen .init-Segmente so linken, dass er fuer jeden Thread zu dessen .init-Code springt? Gruss, Joern
Ich sehe da zwei Wege, verstehe aber den Benefit eurer Modifizierung nicht. 1/ Anlehnend an deine Idee wird jedes Programm für sich inkl. dem benötigten Startupcode und den Libraries gelinkt. Allerdings nicht wie üblich alle ab der gleichen Startadresse. Sondern jedes Programm bekommt seinen eigenen Adressraum. Eingestellt wird die Lage des Adressraums über die Linkercontrolskripte. Die fertigen Binärfiles werden dann zusammengefügt. Es kann mühsam sein, die Grösse der einzelnen Sektionen im Voraus abzuschätzen. 2/ Wenn man eine thread-safe C-Library und ggf. auch einen solchen Startupcode hat, dann kann man den mehrfachen Librarycode und ggf. Startupcode einsparen, indem man diesen Code einmal in eine eigene Sektion legt. Die Restprogramme werden wie bei 1/ erzeugt und in jeweils eigene Sektionen gelegt. Bei beiden Methoden kann man Thread/Programm-gemeinsame Daten haben, die dann ebenfalls in eine eigene, gemeinsame RAM-Sektion kommen. Der Nachteil bei beiden Methoden ist die durch das Linken an eine absolute Adresse die feste Zuordnung der Programme zu einem Speicherbereich. Gerade das wäre der Benefit einer MMU - alle Programme würden an eine gleiche Startadresse gelinkt und dann durch die MMU auf unterschiedliche physikalische Adressen abgebildet. Was ich nicht verstehe ist, welchen Nutzen das Ummodeln der Pipeline in eurem Sinn hat (ausser dem Lerneffekt und dem Forschungsdrang und dem Spass). Abgesehen von einer Performanceeinbusse durch den Verzicht auf die Pipeline und Möglichkeiten zur Codeoptimierung für eine CPU mit Pipeline sehe ich da viele Herausforderungen gegenüber einem konventionellen Kernel mit Scheduler, der sich gleichzeitug auch ale Einziger um die Hardwareresourcen (Interrupts, Periferie wie z.B. UART, ...) kümmern kann. Wenn eure Threads/Programme solche Resourcen wollen, wird es IMHO mit eurem Verfahren ohne Kernel schwierig.
Danke erstmal, das hoert sich doch schon ziemlich hilfreich an. Kann man den Linker irgendwie mit dem Verbinden der einzelnen Programme betrauen? Schließlich moechte ich die Einsprungstellen alle am Anfang haben, da eine Assemblerdatei einlinken und von der aus zu den jeweiligen Prozeduren springen. Das ginge zwar auch noch irgendwie so, waere aber mit dem Linker wohl weniger umstaendlich. Das Projekt ist natuerlich ziemlich akademisch und auch nicht so der richtige Spass. Der einzige Vorteil dieser Interleaved Pipeline ist die Moeglichkeit, die Worst Case Execution Time einschaetzen zu koennen und gleichzeitig beliebig unvorhersehbare (auch statistisch unvorhersehbare) asynchrone Interrupts behandeln zu koennen. Geopfert wird dabei neben der zusaetzlichen Chipflaeche natuerlich jede Menge Leistung. Ich werde dann doch mal einen Blick in die MMU werfen, auch wenn eine Anpassung dort wohl den Umfang des Projektes sprengen duerfte. Gruss, Joern
Oh, für das Verbinden den einzelnen Programme halte ich den Linker für zu mächtig. Der Linker arbeitet auf Objektcode-Ebene, d.h. alle Symbole sind noch sichtbar. In den einzelnen Programmen sind bei Alternative 1 alle Symbole kritisch, die gleich sind; bei Alternative 2 einige die Probleme machen können (z.B. main) und einige, die harmlos sind (z.B. die aus der thread-safe Library). Das wird ein Riesenkuddelmuddel wg. mehrfachen Definitionen oder man muss alle kritischen Symbole unterscheidbar machen ;-( So ein Tool, das wie Objcopy arbeitet, wäre wohl besser geeignet. http://www.gnu.org/software/binutils/manual/html_chapter/binutils_3.html Die Arbeitsweise wäre, aus allen gelinkten Programmen und dem übersetzten Assemblerfile zunächst Binaries zu machen. Dann diese per Shell copy binär zu einem Megabinary aneinander hängen. Das Eintragen der Einsprungadressen in das Megabinary kann man banal mit einem Binärpatch im Endprodukt oder im übersetzten Assemblerfile machen oder gleich im Assemblerfile hart als Konstante codieren. Anschliessend das Megabinary ggf. in ein Hexfile o.ä. umwandeln, so wie es das Programmertool braucht. Du ahnst sicher den Haken dahinter. Man braucht von Anfang an eine Idee wo die Startadressen zu liegen kommen und wie gross die Speicherslots für die Programme sind, um das Linkerskript zu machen... Entweder brutal indem man den realen Spricher durch die Zahl der Programme teilt oder indem man eine Versuchsserie fährt und den Platz dann nach Bedarf zuteilt.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.