Übersicht und Vergleichstest des PCs "Elbrus 401 - PC". Dritter Teil - Entwicklungswerkzeuge

Wir überprüfen weiterhin den neuen Haushaltscomputer. Nach einer kurzen Einführung in die Funktionen der Elbrus-Architektur werden wir die uns angebotenen Softwareentwicklungstools betrachten.

Vorder- und Seitenansicht der Elbrus 401-PC-SystemeinheitBeispielprogramm für Maschinensprache E2K



Erinnern Sie sich an die Struktur des Artikels:

  1. Hardware-Überprüfung :
    • Akquisitionsprozess;
    • Hardware
  2. Software-Überprüfung :
    • Betriebssystemstart;
    • reguläre Software;
  3. Übersicht über Entwicklungswerkzeuge:
  4. Benchmarking-Leistung :
    • Beschreibung der Konkurrenzcomputer
    • Benchmark-Ergebnisse;
    • zusammenfassend.

Viel Spaß beim Lesen!

Architekturmerkmale


Das Wesentliche der E2K-Architektur in einem Satz kann wie folgt formuliert werden: 64-Bit-Register, explizite Parallelität der Befehlsausführung und streng kontrollierter Speicherzugriff.

Beispielsweise sind x86- oder SPARC-Architekturprozessoren implizit , die mehr als einen Befehl pro Zyklus (superskalar) ausführen können und manchmal auch nicht in der richtigen Reihenfolge sindParallelität: Der Prozessor analysiert direkt in Echtzeit die Abhängigkeiten zwischen Anweisungen auf einem kleinen Codeabschnitt und lädt, wenn er dies für möglich hält, gleichzeitig bestimmte Aktoren. Manchmal handelt er zu optimistisch - spekulativ -, indem er das Ergebnis verwirft oder die Transaktion im Falle einer erfolglosen Vorhersage zurücksetzt. Im Gegenteil, manchmal ist es zu pessimistisch - es werden Abhängigkeiten zwischen den Werten der Register oder Teilen der Register angenommen, die tatsächlich nicht aus Sicht des ausführbaren Programms sind.

Wenn  explizitParallelität (explizit paralleles Befehlsrechnen, EPIC) Die gleiche Analyse findet in der Kompilierungsphase statt, und alle für die parallele Ausführung definierten Maschinenbefehle werden in einem sehr großen Befehlswort (VLIW) geschrieben, und Elbrus hat die Länge davon "Wörter" sind nicht fest und können aus 1 bis 8 Doppelwörtern bestehen (in diesem Zusammenhang hat ein einzelnes Wort eine Kapazität von 32 Bit).

Zweifellos verfügt der Compiler über viel größere Funktionen in Bezug auf die abgedeckte Codemenge, den Zeit- und Speicheraufwand, und wenn der Maschinencode manuell geschrieben wird, kann der Programmierer eine noch intelligentere Optimierung durchführen. Dies ist jedoch theoretisch und in der Praxis ist es unwahrscheinlich, dass Sie Assembler verwenden. Daher hängt alles davon ab, wie gut der optimierende Compiler ist, und das Schreiben eines Compilers ist, gelinde gesagt, keine leichte Aufgabe. Wenn bei impliziter Parallelität "langsame" Anweisungen weiterarbeiten können, ohne den Empfang der folgenden Anweisungen für andere Aktuatoren zu blockieren, wartet der gesamte breite Befehl bei expliziter Parallelität auf den vollständigen Abschluss. Schließlich hilft ein optimierender Compiler bei der Interpretation dynamischer Sprachen wenig.

All dies ist im MCST natürlich gut verstanden, und daher implementiert Elbrus auch spekulative Ausführungstechnologien, vorinstallierten Code und Daten sowie kombinierte Rechenoperationen. Anstatt zu theoretisieren und sich unendlich zu fragen, wie viele hypothetische Gigaflops diese oder jene Plattform unter erfolgreichen Umständen ausgeben kann, nehmen wir im vierten Teil des Artikels nur die tatsächliche Leistung realer Programme - angewendet und synthetisch - und bewerten sie.

VLIW: ein Durchbruch oder eine Sackgasse?
, VLIW   : ,   ‑ Transmeta Crusoe —  «». ,     Efficeon (   )    .  ,   x86-   ,   . ,  Pentium M  ,   Pentium 4 , .      VIA C3, x86.

Aufgrund seiner exotischen Natur ist die Technologie der geschützten Ausführung von Programmen in C / C ++ - Sprachen, bei der die Verwendung von Zeigern eine Vielzahl von Möglichkeiten bietet, sich in den Fuß zu schießen, nicht weniger interessant. Das Konzept des Kontextschutzes, das vom Compiler in der Assemblyphase und vom Prozessor zur Laufzeit gemeinsam implementiert wird, sowie das Betriebssystem in Bezug auf die Speicherverwaltung erlauben es nicht, den Umfang der Variablen zu verletzen, unabhängig davon, ob auf eine private Klassenvariable, private Daten eines anderen Moduls oder lokale Variablen der aufrufenden Funktion zugegriffen wird . Manipulationen mit Änderung der Zugriffsebene sind nur in Richtung einer Einschränkung der Rechte zulässig. Das Speichern von Links zu kurzlebigen Objekten in langlebigen Strukturen ist blockiert. Versuche werden auch daran gehindert, tote Links zu verwenden: Wenn das Objekt, zu dem der Link einmal empfangen wurde, bereits gelöscht wurde,Selbst der Standort einer anderen neuen Einrichtung an derselben Adresse wird nicht als Entschuldigung für den Zugriff auf deren Inhalt angesehen. Ermutigt, Daten als Code zu verwenden und die Kontrolle überall zu übertragen.

Sobald wir von Redewendungen auf hoher Ebene zu Zeigern auf niedriger Ebene übergehen, erweisen sich alle diese Sichtbarkeitsbereiche als nichts anderes als syntaktisches Salz. Einige (einfachste) Fälle von Missbrauch von Zeigern können manchmal dazu beitragen, statische Quellcode-Analysatoren abzufangen. Wenn das Programm jedoch bereits in x86- oder SPARC-Maschinenanweisungen übersetzt wurde, hindert nichts daran, den Wert aus der falschen Speicherzelle oder der falschen Größe zu lesen oder zu schreiben, was zu einem Absturz an einer völlig anderen Stelle führt - und hier sitzen Sie und betrachten den beschädigten Stapel und Sie haben keine Ahnung, wo Sie mit dem Debuggen beginnen sollen, da auf dem anderen Computer derselbe Code erfolgreich ausgeführt wird. Und der Stapelüberlauf und die daraus resultierenden Sicherheitslücken sind nur die Geißel beliebter Plattformen. Es ist erfreulich, dass unsere Entwickler diese Probleme systematisch angehen.und nicht darauf beschränkt, immer mehr Krücken anzuordnen, deren Wirkung immer noch eher einem Rechen ähnelt. Schließlich kümmert es niemanden, wie schnell Ihr Programm funktioniert, wenn es nicht richtig funktioniert. Darüber hinaus zwingt eine strengere Kontrolle durch den Compiler Sie dazu, "übelriechenden" und unerträglichen Code neu zu schreiben, was bedeutet, dass dies indirekt die Programmierkultur verbessert.

Die Bytereihenfolge beim Speichern von Zahlen in Elbrus 'Speicher ist im Gegensatz zu SPARC Little Endian (das untere Byte steht an erster Stelle), dh wie bei x86. Da die Plattform x86-Code unterstützen soll, gibt es keine Einschränkungen für die Ausrichtung von Daten im Speicher.

Ordnung, Ausrichtung und Portabilität
 , Intel, ,       (, 32‑   0x04000005) —   , ,   ,   . - ,   ,    , — ,   (   , UTF‑16),   , ,   ,    ‑. ,   , — , SPARC, —   .

Weitere Informationen zum Design von MCST-Computern auf SPARC- und E2K-Architekturen finden Sie im Buch „Mikroprozessoren und Rechenkomplexe der Elbrus-Familie“, das vom Peter-Verlag in einer  minimalen Auflage veröffentlicht wurde und seit langem verkauft wird, aber kostenlos als PDF ( 6 MB ) erhältlich ist. und gegen eine geringe Gebühr bei  Google Play . Vor dem Hintergrund des Mangels an anderen detaillierten Informationen im öffentlichen Bereich ist diese Veröffentlichung nur ein Wissensspeicher. Der Text konzentriert sich jedoch hauptsächlich auf die Hardware, die Betriebsalgorithmen von Puffern und Pipelines, Caches und arithmetisch-logischen Geräten - das Thema des Schreibens [effektiver] Programme wird überhaupt nicht angesprochen, und selbst das bloße Erwähnen von Maschinenanweisungen kann an den Fingern gezählt werden.

Maschinensprache


Neben der Kompilierung der Hochsprachen C, C ++, Fortran wird in der Dokumentation bei jeder Gelegenheit nicht vergessen, die Möglichkeit zu erwähnen, Programme direkt in Assembler zu schreiben. Es wird jedoch nirgends angegeben, wie genau Sie sich an dieser filigranen Kunst beteiligen können, bei der Sie zumindest einen Verweis auf Maschinenanweisungen erhalten können. Glücklicherweise verfügt das System über einen GDB-Debugger, der den Code zuvor kompilierter Programme zerlegen kann. Um den Rahmen des Artikels nicht zu überschreiten, schreiben wir eine einfache arithmetische Funktion, die einen guten Rückstand für die Parallelisierung aufweist.

uint64_t CalcParallel(
	uint64_t a,
	uint64_t b,
	uint64_t c,
	uint32_t d,
	uint32_t e,
	uint16_t f,
	uint16_t g,
	uint8_t h
) {
	return (a * b) + (c * d) - (e * f) + (g / h);
}

Folgendes wird beim Kompilieren im -O3- Modus übersetzt :

0x0000000000010490 <+0>:
	muld,1 %dr0, %dr1, %dg20
	sxt,2 6, %r3, %dg19
	getfs,3 %r6, _f32,_lts2 0x2400, %g17
	getfs,4 %r5, _lit32_ref, _lts2 0x00002400, %g18
	getfs,5 %r7, _f32,_lts3 0x200, %g16
	return %ctpr3
	setwd wsz = 0x5, nfx = 0x1
	setbp psz = 0x0
0x00000000000104c8 <+56>:
	nop 5
	muld,0 %dr2, %dg19, %dg18
	muls,3 %r4, %g18, %g17
	sdivs,5 %g17, %g16, %g16
0x00000000000104e0 <+80>:
	sxt,0 6, %g17, %dg17
	addd,1 %dg20, %dg18, %dg18
0x00000000000104f0 <+96>:
	nop 5
	subd,0 %dg18, %dg17, %dg17
0x00000000000104f8 <+104>:
	sxt,0 2, %g16, %dg16
0x0000000000010500 <+112>:
	ct %ctpr3
	ipd 3
	addd,0 %dg17, %dg16, %dr0

Das erste, was auffällt, ist, dass jeder Befehl sofort in mehrere parallel ausgeführte Anweisungen dekodiert wird. Die mnemonische Bezeichnung von Anweisungen ist im Allgemeinen intuitiv, obwohl einige Namen nach Intel ungewöhnlich erscheinen: Beispielsweise wird eine nicht signierte Erweiterungsanweisung hier als sxt und nicht als  movzx bezeichnet . Der Parameter vieler Rechenbefehle ist neben den Operanden selbst die Nummer des ausführenden Geräts - nicht ohne Grund steht ELBRUS für eine explizite Planung der Nutzung grundlegender Ressourcen, dh eine „explizite Planung für die Verwendung grundlegender Ressourcen“.

Um auf den vollständigen 64-Bit-Registerwert zuzugreifen, wird das Präfix „ d"; Theoretisch ist es auch möglich, auf die unteren 16 und 8 Bits des Wertes zuzugreifen. Der Bezeichnung globaler Allzweckregister, von denen es 32 Teile gibt, wird vor der Nummer „ g “ und lokalen Prozedurregistern das Präfix „ rvorangestellt . Die Fenstergröße der durch den Befehl setwd angeforderten lokalen Register kann 224 erreichen, und die Pumpe wird bei Bedarf automatisch auf den Stapel geschoben .

Die Art und Weise, wie Sie bestimmte Anweisungen anwenden, ist verwirrend: Geben Sie beispielsweise zurückWie Sie vielleicht erraten haben, dient dies dazu, die Steuerung an die aufrufende Prozedur zurückzugeben. In allen untersuchten Codebeispielen erfolgt diese Anweisung jedoch lange vor dem letzten Befehl (wo auch eine Art Kontextmanipulation vorhanden ist), manchmal sogar im allerersten Befehlswort, wie hier. Obwohl das oben genannte Buch einen ganzen Absatz zu diesem Thema enthält, ist es uns noch nicht klar geworden. Update vom 9. Februar 2016: Die Kommentare deuten darauf hin, dass die return-Anweisung nur den Weg für die Rückkehr aus dem Unterprogramm vorbereitet und es dem Prozessor ermöglicht, die nächsten Befehle der aufrufenden Prozedur zu laden, und das Steuerelement selbst zurückkehrt, wenn die Ausführung den Befehl  ct erreicht .

"Leicht zu lesender Code" und "effizienter Code" sind jedoch bei Maschinenanweisungen bei weitem nicht gleich. Wenn Sie ohne Optimierung kompilieren, ist der Code konsistenter und ähnelt der Stirnberechnung, jedoch auf Kosten der Verlängerung: Anstelle von 6 gesättigten Befehlswörtern werden 8 spärliche generiert.

Lassen Sie uns die Wahrsagerei auf Kaffeesatz für die Sim beenden, bevor wir uns völlig lächerliche Annahmen vorstellen. Hoffen wir, dass eines Tages die Befehlsreferenz sowie der Programmier- und Optimierungsleitfaden veröffentlicht werden.

Entwicklungswerkzeuge


Der Standard-C / C ++ - Sprachcompiler im Elbrus-Betriebssystem ist LCC, eine proprietäre Entwicklung des Unternehmens MCST, die mit GCC kompatibel ist. Detaillierte Informationen zu Struktur und Prinzipien dieses Compilers werden nicht veröffentlicht. Laut einem Interview mit einem ehemaligen Entwickler einer von mehreren entwickelten Unterarten des Compilers verwendet die Edison Design Group ein Frontend für die Analyse von Quellcodes auf hoher Ebene Die Übersetzung in Maschinenanweisungen auf niedriger Ebene kann auf verschiedene Arten durchgeführt werden - ohne Optimierung oder mit Optimierung. Es ist der optimierende Compiler, der Endbenutzern nicht nur auf der E2K-Plattform zur Verfügung gestellt wird, für die es einfach keine alternativen Maschinencodegeneratoren gibt, sondern auch auf der SPARC-Plattformfamilie, auf der auch das übliche GCC als Teil des MSVS-Betriebssystems verfügbar ist.

In Anbetracht der oben aufgeführten Architekturmerkmale - offensichtliche Parallelität, sichere Ausführung von Programmen - implementiert der LCC-Compiler offensichtlich viele einzigartige Lösungen, die der strengsten Untersuchung und Prüfung in der Praxis würdig sind. Leider hat der Autor zum Zeitpunkt des Schreibens dieser Zeilen weder ausreichende Qualifikationen dafür noch Zeit für solche Studien; Ich hoffe, dass dieses Problem früher oder später von einem viel größeren Kreis von Vertretern der IT-Community, einschließlich kompetenterer, angesprochen wird.

Nach dem, was Sie beim Erstellen von Programmen zum Testen der Leistung mit bloßem Auge bemerkt haben, warnt LCC auf E2K häufiger als andere vor möglichen Fehlern, Analphabeten oder einfach verdächtigen Stellen im Code. Der Autor ist mit GCC zwar nicht so vertraut, um die Unterscheidung zwischen eindeutigen LCC-Nachrichten auf Russisch und einfach übersetzten zu gewährleisten (außerdem ist die Übersetzung selektiv), und ich bin nicht sicher, ob ein intensiverer Strom von Warnungen keine Folge der automatisch abgeschlossenen Baugruppenkonfiguration ist. Da die Semantik eines bestimmten Codeabschnitts nicht bekannt ist, ist es manchmal schwierig zu verstehen, wie klug der Compiler darin ist, versteckte Fehler zu finden oder einen Fehlalarm auszulösen. Beispielsweise wird im Postgresql-Code dasselbe Konstrukt viermal in derselben Datei mit geringfügigen Abweichungen gefunden:

for (i = 0, ptr = cont->cells; *ptr; i++, ptr++) {

	//....//

	/* is string only whitespace? */
	if ((*ptr)[strspn(*ptr, " \t")] == '\0')
		fputs("&nbsp; ", fout);
	else
		html_escaped_print(*ptr, fout);

	//....//
}


Der Compiler sagt mit dem Aufruf der Funktion strspn einen möglichen Ausweg aus dem eindimensionalen Array in der Zeichenfolge voraus . Unter welchen Umständen dies passieren kann, versteht der Autor nicht (und es gab keine solche Warnung auf anderen Plattformen, obwohl der Überprüfungsmodus Warray-gebunden istist Standard für GCC), es ist jedoch bemerkenswert, dass mehrere Replikationen desselben nicht trivialen Designs (da es notwendig war, seinen Zweck im Kommentar zu erläutern), anstatt es in eine separate Funktion mit einem beredten Namen zu setzen, der keiner Erklärung bedarf. Selbst wenn sich der Alarm als falsch herausstellte, ist das Erkennen eines übelriechenden Codes ein nützlicher Effekt. Die Autoren des statischen Analysators PVS - Studio bleiben ohne Arbeit. Im Ernst, es wäre amüsant und nützlich zu vergleichen, welche zusätzlichen Fehler im Code das LCC aufgrund der einzigartigen Merkmale der E2K-Architektur wirklich erkennen kann - gleichzeitig könnte die Welt der freien Software einen weiteren Stapel von Fehlerberichten erhalten.

Ein weiteres Ergebnis eines neugierigen Bekannten mit redseligen LCC war der Autor der Bildung, und dann seine erfahrenen Kollegen, was trigraphs ( trigraphs ) in C / C ++ Sprachen, und warum sie nicht standardmäßig unterstützt werden, zum Glück. Sie leben so und ahnen nicht, dass sich die scheinbar harmlose Kombination von Satzzeichen in Textliteralen oder Kommentaren als Zeitbombe herausstellen kann - oder als hervorragendes Material für ein Programm-Lesezeichen, je nachdem, auf welcher Seite der Barrikade Sie sich befinden.

Eine unangenehme Folge der Autarkie von LCC ist, dass sich das Nachrichtenformat von dem von GCC unterscheidet. Wenn diese Nachrichten aus einer Entwicklungsumgebung (z. B. Qt Creator) kompiliert werden, fallen sie nur in das allgemeine Arbeitsprotokoll, nicht jedoch in die Liste der erkannten Probleme. Vielleicht kann dies auf irgendeine Weise angepasst werden, entweder von der Seite des Compilers oder in der Entwicklungsumgebung, aber zumindest sofort versteht es sich nicht.

Aufgrund ihrer relativ geringen Leistung ist dies für inländische Plattformen traditionell akut. Es besteht das Problem der Kreuzkompilierung, dh der Zusammenstellung von Programmen für die Zielarchitektur und eines bestimmten Satzes von Systembibliotheken unter Verwendung der Ressourcen leistungsfähigerer Computer mit unterschiedlicher Architektur und anderer Software. Gemessen an den Identifikationslinien im Kern des Elbrus-Systems und im LCC-Compiler selbst sind sie unter Linux i386 zusammengestellt, aber dieses Toolkit für x86 ist natürlich nicht im Distributionspaket des Systems selbst enthalten. Es ist interessant, aber ist es möglich, das Gegenteil zu tun: auf Elbrus Programme für andere Plattformen zu sammeln? (Der Autor war nicht weiter als bis zur ersten Phase der GCC-Assembly für i386 erfolgreich.)

Versionen der wichtigsten Pakete für den Entwickler:

  • Compiler: lcc 1.19.18 (gcc 4.4.0 kompatibel);
  • : erlang 15.b.1, gawk 4.0.2, lua 5.1.4, openjdk 1.6.0_27 (jvm 20.0‑b12), perl 5.16.3, php 5.4.11, python 2.7.3, slang 2.2.4, tcl 8.6.1;
  • : autoconf 2.69, automake 1.13.1, cmake 2.8.10.2, distcc 3.1, m4 1.4.16, make 3.81, makedepend 1.0.4, pkgtools 13.1, pmake 1.45;
  • : binutils 2.23.1, elfutils 0.153, patchelf 0.6;
  • : boost 1.53.0, qt 4.8.4, qt 5.2.1;
  • : expat 2.1.0, ffi 3.0.10, gettext 0.18.2, glib 2.36.3, glibc 2.16.0, gmp 4.3.1, gtk+ 2.24.17, mesa 10.0.4, ncurses 5.9, opencv 2.4.8, pcap 1.3.0, popt 1.7, protobuf 2.4.1, sdl 1.2.13, sqlite 3.6.13, tk 8.6.0, usb 1.0.9, wxgtk 2.8.12, xml‑parser 2.41, zlib 1.2.7;
  •  : cppunit 1.12.1, dprof 1.3, gdb 7.2, perf 3.5.7;
  • : anjuta 2.32.1.1, glade 2.12.0, glade 3.5.1, qt‑creator 2.7.1;
  • : bzr 2.2.4, cvs 1.11.22, git 1.8.0, patch 2.7, subversion 1.7.7.

Wenn Sie GCC 5, PHP 7 und Java 9 erwartet haben, dann sind dies Ihre Probleme, wie ein berühmter Fußballer sagt. In diesem Fall muss ich mich auch dafür bedanken, dass zumindest nicht GCC 3.4.6 (LCC 1.16.12) wie in den Vorgängerversionen des Elbrus-Systems oder GCC 3.3.6 in der Zusammensetzung des MSVS 3.0; Der Hauptcompiler in MSVS 3.0 ist übrigens immer noch GCC 2.95.4 (und warum sollte man sich wundern, wenn es einen Kernel aus einem 2.4-Zweig gibt?). Im Vergleich zur vorherigen Situation, in der es vor zehn Jahren möglich war, auf einen im Upstream behobenen GCC-Fehler zu stoßen, hat das neue System fast himmlische Bedingungen - Sie können es sogar in C ++ 11 durchziehen, wenn Sie die Abwärtskompatibilität nicht beibehalten möchten.

Die Entstehung von OpenJDK, zumindest in irgendeiner Form, kann bereits als großer Durchbruch bezeichnet werden, da Java und Mono nicht mögen in solchen Systemen ist seit langem bekannt; und diese Abneigung kann verstanden werden, wenn sich selbst native Programme kaum bewegen. Da es unter den Kollegen des Autors viele Javisten gibt, die aufgrund der oben genannten Umstände gezwungen sind, die wunderbaren Impulse der Seele zurückzuhalten, wurde beschlossen, eine separate Reihe von Leistungstests für Java durchzuführen. Mit Blick auf die Zukunft stellen wir fest, dass die Ergebnisse auch relativ gesehen entmutigend waren: Mit dem gleichen Erfolg können Sie wahrscheinlich interpretierte Skripte in PHP oder Python schreiben.

Die Unterstützung für C und C ++ allein beschränkt sich nicht nur auf die Kompatibilität mit der GNU Compiler Collection: Das System verfügt weiterhin über einen Fortran-Übersetzer. Da der Autor nur mit Professor Fortran vertraut ist, kann jeder Interessierte das Dezember- Thema „Made with Us“ empfehlen., wo die Kommentare die Verwendung dieser Sprache als Benchmark berühren.

Zum Nachtisch haben wir die leckersten auf Lager: Der letzte Teil des Artikels widmet sich der Untersuchung der Leistung von Elbrus im Vergleich zu einer Vielzahl von Hardware- und Softwareplattformen, einschließlich inländischer Plattformen.

Source: https://habr.com/ru/post/de389927/


All Articles