Discussion:
cache coherence
(zu alt für eine Antwort)
Jan Bruns
2014-12-04 04:57:56 UTC
Permalink
Hallo.

Ich hab da mal eine Frage zum Thema "cache coherence"
zwischen CPU Kernen: Wie verlässlich und in welcher
Absolutheit ist eine solche denn inzwischen
üblicherweise (d.h. hier auch: low budget) gegeben?

Also Anlass zu der Frage ist eigentlich nur, daß halt
irgendwelcher Code von und bei mir nicht so
funktioniert, wie gewünscht, was nun mit ganz hoher
Wahrscheinlichkeit auch an diesem Code liegen kann.

Auf der anderen Seite ist das aber einfach ein Thema,
das neu für mich ist, so daß ich da einfach zu wenig
Erfahrungswerte bzgl. realer Hardware habe (und
im Zweifel ist letztere ja auch nur so sorgfältig
gestaltet, daß "Fehler" nicht so auffallen).


Also ich stelle mal unten das wichtigste vom Code
dazu, dann ist das nicht so abstrakt. Die Idee war,
für eine (grosse) Sammlung von Objekten Threadlocks
zur Verfügung zu stellen, also eine "freiwillige",
Möglichkeit für Threads, jeweils exclusiv Zugriff
zu Objekten zu erhalten (mit dem Risiko, beim
"Antrag" erstmal eingeschläfert zu werden).

Dazu gibt's für jedes Objekt ein int32, das über
Compare-and-Swap Operationen mit Informationen hält:
zu Lock-holder, Lock-count (ein Thread bzw.
AccessPoint-Object darf das Objekt mehrfach locken),
sowie einen Schlüssel zu Informationen über
auf das Objekt wartende AccessPoints.

Im Prinzip scheints zu funktionieren, aber so etwa
einmal pro 1Mio. Lock-Operationen sieht es
zumindest symptomatisch so aus, als würde die
Compare-and-Swap Operation unerlaubt swappen (der
erste wartende Thread wird korrekt geweckt, hat aber
das Lock dann gar nicht, und bekommt es auch nicht
mehr).

Also eh' ich jetzt noch weiter rumlaber, kippe
ich mal den Code ab. Vielleicht hat ja wer 'ne Idee
(Barrieren um die InterlockedOPs habe ich schon
probiert, obwohl die Massenahme nicht gut zur
Symptomatik passt).

Gruss

Jan bruns






procedure TparlocCol.lockObj(o : Toid; ap : TparlocAP);
var ap2 : TparlocAP; a, wc, old : longint; lv : Plongint;
begin
RTLeventResetEvent(ap.locksig);
lv := locate_locvar(o);
repeat
// assume there currently is no lock
a := (ap.id shl lsb_lock_holder) + 1;
old := InterlockedCompareExchange(lv^,a,0);
if (old=0) then break
else begin
a := (old shr lsb_lock_holder) and apidmask;
if (a = ap.id) then begin
{ we already have the lock. just inc. }
a := old and lockcountmask;
if (a>=lockcountlimit) then begin
raise parlocAPexcpt.Create('Too many locks on object.');
end else begin
a := InterlockedCompareExchange(lv^,old+1,old);
if (a=old) then break;
end;
end else begin
{ another AP has the lock. try linking into
the chain of waiters. }
wc := (old shr lsb_lock_waiter) and apidmask;
if (wc=0) then begin
wc := start_new_waitchain(o,ap);
a := old or (wc shl lsb_lock_waiter);
a := InterlockedCompareExchange(lv^,a,old);
if (a=old) then begin
unlock_waitchain(wc);
wait_waitchain(wc,o,ap);
break;
end else discard_waitchain(wc); // and retry
end else begin
if try_append_waitchain(wc,o,ap) then begin
wait_waitchain(wc,o,ap);
break;
end; // else retry
end;
end;
end;
until false;
end;

procedure TparlocCol.unlockObj(o : Toid; ap : TparlocAP);
var ap2 : TparlocAP; a, old, wc, wc2 : longint; lv : Plongint;
begin
lv := locate_locvar(o);
repeat
// assume we had a single lock with no waiters
a := (ap.id shl lsb_lock_holder) + 1;
old := InterlockedCompareExchange(lv^,0,a);
if not(old=a) then begin
a := (old shr lsb_lock_holder) and apidmask;
if (a=ap.id) then begin
a := old and lockcountmask;
if (a>1) then begin
// we had locked the object more than 1 time
InterLockedDecrement(lv^);
break;
end else if (a=1) then begin
{ give the lock to the first waiter. }
wc := (old shr lsb_lock_waiter) and apidmask;
if (wc=0) then begin
raise parlocAPexcpt.Create('No waiters or not?');
end else begin
lock_waitchain(wc); // forced, waited
ap2 := get_first_waiter(wc); // no remove
wc2 := decide_keep_waitchain(wc); // wc, or 0, if waiting<2
a := (ap2.id shl lsb_lock_holder);
a := a or (wc2 shl lsb_lock_waiter);
a := a +1;
a := InterlockedCompareExchange(lv^,a,old);
if not(a=old) then begin
raise parlocAPexcpt.Create('Unexpected lockvar mod during unlock.');
end else begin
if (wc2=0) then begin
discard_waitchain(wc);
end else begin
remove_first_waiter(wc);
unlock_waitchain(wc);
end;
RTLeventSetEvent(ap2.locksig); // wake up the oldest waiting thread
break;
end;
end;
end else begin
raise parlocAPexcpt.Create('Unclean reach of lockcnt=0.');
end;
end else begin
raise parlocAPexcpt.Create('Non-Owner attempt to unlock.');
end;
end else break; // initial assumption correct
until false;
end;
Bernhard Schornak
2014-12-04 13:57:26 UTC
Permalink
Post by Jan Bruns
procedure TparlocCol.lockObj(o : Toid; ap : TparlocAP);
var ap2 : TparlocAP; a, wc, old : longint; lv : Plongint;
begin
RTLeventResetEvent(ap.locksig);
lv := locate_locvar(o);
repeat
// assume there currently is no lock
a := (ap.id shl lsb_lock_holder) + 1;
old := InterlockedCompareExchange(lv^,a,0);
if (old=0) then break
else begin
a := (old shr lsb_lock_holder) and apidmask;
if (a = ap.id) then begin
{ we already have the lock. just inc. }
a := old and lockcountmask;
if (a>=lockcountlimit) then begin
raise parlocAPexcpt.Create('Too many locks on object.');
end else begin
a := InterlockedCompareExchange(lv^,old+1,old);
if (a=old) then break;
end;
end else begin
{ another AP has the lock. try linking into
the chain of waiters. }
wc := (old shr lsb_lock_waiter) and apidmask;
if (wc=0) then begin
wc := start_new_waitchain(o,ap);
a := old or (wc shl lsb_lock_waiter);
a := InterlockedCompareExchange(lv^,a,old);
if (a=old) then begin
unlock_waitchain(wc);
wait_waitchain(wc,o,ap);
break;
end else discard_waitchain(wc); // and retry
end else begin
if try_append_waitchain(wc,o,ap) then begin
wait_waitchain(wc,o,ap);
break;
end; // else retry
end;
end;
end;
until false;
end;
<schnipp>

Mit Sicherheit weder x86 noch 68k Opcodes. Auch HLA oder
RosAsm schaut anders aus. Gibt es auch einen Link zu dem
"Assembler", der mit solch einer merkwürdig formatierten
Mischung aus Text und Hokuspokus etwas anfangen kann?

Zum Thema gibt es grundlegend

http://de.wikipedia.org/wiki/Cache-Koh%C3%A4renz

und vertiefend Kapitel 7.3 in AMDs "AMD64 Architecture
Programmer’s Manual, Volume 2: System Programming" oder
"Intel 64 and IA-32 Architectures Software Developer’s
Manual", Volume 3a, Kapitel 11.

Aus diesen Dokumenten geht eindeutig hervor, dass x86-
Programmierer nicht direkten Einfluss auf die Kohärenz
der diversen Cachehierarchien nehmen können. Auch 68k-
Systeme mit mehreren Prozessoren dürften die möglichen
Kohärenz-Probleme mit einer hardwareseitigen Steuerung
über ihren Chipsatz lösen, da softwareseitige Lösungen
viel zu träge wären, um derlei Aufgaben in Echtzeit zu
erledigen. Eine softwareseitige Lösung könnte nur über
MSRs (Machine State Register) realisiert werden. Diese
müssten von allen Prozessoren ansprechbar sein, was zu
reichlich komplexen Verwaltungsstrukturen - mit daraus
resultierender Entschleunigung - führen würde. Heutige
MSRs haben Zugriffszeiten von zwei- oder dreistelligen
Taktzyklen. Je nach dem, wie viele Prozessoren auf ein
MSR zugreifen, erhöht sich die Zugriffszeit drastisch.
Die interne Lösung regelt das Problem in wenigen Takt-
zyklen. Sie ist für System- und Anwendungsprogramierer
zudem transparent.


Grüsse aus Augsburg

Bernhard Schornak
Jan Bruns
2014-12-04 20:50:15 UTC
Permalink
Mit Sicherheit weder x86 noch 68k Opcodes. Auch HLA oder RosAsm schaut
anders aus. Gibt es auch einen Link zu dem "Assembler", der mit solch
einer merkwürdig formatierten Mischung aus Text und Hokuspokus etwas
anfangen kann?
Eingesetzter Compiler war http://freepascal.org

Der gezeigte Code besteht ja fast ausschliesslich
aus Calls. Die hier wichtigsten (Interlocked*)
Operationen wurden für AMD64 ebenfalls in calls
übersetzt, und zwar zur "System-Unit" des Compilers
(dort bspw. mit "lock cmpxchg" umgesetzt).
Möglicherweise aus Rücksichtnahme auf Zielsysteme,
bei denen diese Operationen nicht mit Einzel-
instruktionen umzusetzen sind. Weiter tauchen
mit (RTLevent*) einige in OS-calls übersetzte
Aufrufe auf, sowie überwiegend Aufrufe zu weiteren,
nicht gezeigten Methoden des Objekts.

Was die Formatierung betrifft (sofern die bei
Dir richtig angezeigt wurde, im Zitat er scheint
die jedenfalls korrekt): Die hat tatsächlich eine
ungewöhnlich ausgeprägte persönliche Note, folgt
aber einem ausgetüfteltem System, das ist
zweckmässig so.
Zum Thema gibt es grundlegend
http://de.wikipedia.org/wiki/Cache-Koh%C3%A4renz
Kenne ich. Also nicht so auswendig, daß diese
ganzen Begriffe mit all ihren Implikationen jederzeit
voll präsent wären, aber ich habe z.B. in 'nem FPGA
schon einen (unicore) Cache implementiert.
und vertiefend Kapitel 7.3 in AMDs "AMD64 Architecture Programmer’s
Manual, Volume 2: System Programming" oder "Intel 64 and IA-32
Architectures Software Developer’s Manual", Volume 3a, Kapitel 11.
Aus diesen Dokumenten geht hervor, daß im Sinne
meiner Fragestellung eine ganz und gar absolute
Cache-Kohärenz zu den Idealen der CPU-Entwickler
zählt. Hast Du vielleicht auch noch einen Link
auf die Bug-Report Liste zur Wald-und-Wiesen-CPU?
Aus diesen Dokumenten geht eindeutig hervor, dass x86- Programmierer
nicht direkten Einfluss auf die Kohärenz der diversen Cachehierarchien
nehmen können.
Auch 68k- Systeme mit mehreren Prozessoren dürften die
möglichen Kohärenz-Probleme mit einer hardwareseitigen Steuerung über
ihren Chipsatz lösen, da softwareseitige Lösungen viel zu träge wären,
um derlei Aufgaben in Echtzeit zu erledigen.
Äh. User-Land und "Einfluss auf die Cache Kohärenz"
sind doch nun wirklich Begriffe, denen man auch
intuitiv kein Zusammenpassen andeutet.

Gruss

Jan Bruns
Bernhard Schornak
2014-12-04 23:09:35 UTC
Permalink
Post by Jan Bruns
Mit Sicherheit weder x86 noch 68k Opcodes. Auch HLA oder RosAsm schaut
anders aus. Gibt es auch einen Link zu dem "Assembler", der mit solch
einer merkwürdig formatierten Mischung aus Text und Hokuspokus etwas
anfangen kann?
Eingesetzter Compiler war http://freepascal.org
Der gezeigte Code besteht ja fast ausschliesslich
aus Calls. Die hier wichtigsten (Interlocked*)
Operationen wurden für AMD64 ebenfalls in calls
übersetzt, und zwar zur "System-Unit" des Compilers
(dort bspw. mit "lock cmpxchg" umgesetzt).
Möglicherweise aus Rücksichtnahme auf Zielsysteme,
bei denen diese Operationen nicht mit Einzel-
instruktionen umzusetzen sind. Weiter tauchen
mit (RTLevent*) einige in OS-calls übersetzte
Aufrufe auf, sowie überwiegend Aufrufe zu weiteren,
nicht gezeigten Methoden des Objekts.
Was die Formatierung betrifft (sofern die bei
Dir richtig angezeigt wurde, im Zitat er scheint
die jedenfalls korrekt): Die hat tatsächlich eine
ungewöhnlich ausgeprägte persönliche Note, folgt
aber einem ausgetüfteltem System, das ist
zweckmässig so.
Davon ging ich aus. Assemblercode schaut - nichtsdestotrotz -
etwas anders aus: http://tinyurl.com/oza4fdz (AT&T-Dialekt).

Noch zweckmässiger wäre es daher doch, das in einer Pascal-NG
zu posten? Hier in d.c.l.a ist zwar nicht gar so viel los wie
in a.l.asm oder c.l.a.x86, das heisst aber nicht, dass irgend
einen Leser in Assembler-NGs HLL-Code wirklich interessiert.

Möglicherweise wärest Du mit "selbstgestrickten" Cachestrate-
gien in alt.os.development besser aufgehoben?
Post by Jan Bruns
Zum Thema gibt es grundlegend
http://de.wikipedia.org/wiki/Cache-Koh%C3%A4renz
Kenne ich. Also nicht so auswendig, daß diese
ganzen Begriffe mit all ihren Implikationen jederzeit
voll präsent wären, aber ich habe z.B. in 'nem FPGA
schon einen (unicore) Cache implementiert.
Schön für Dich! ;)
Post by Jan Bruns
und vertiefend Kapitel 7.3 in AMDs "AMD64 Architecture Programmer’s
Manual, Volume 2: System Programming" oder "Intel 64 and IA-32
Architectures Software Developer’s Manual", Volume 3a, Kapitel 11.
Aus diesen Dokumenten geht hervor, daß im Sinne
meiner Fragestellung eine ganz und gar absolute
Cache-Kohärenz zu den Idealen der CPU-Entwickler
zählt. Hast Du vielleicht auch noch einen Link
auf die Bug-Report Liste zur Wald-und-Wiesen-CPU?
Welche da wäre? Ich bezweifle, das es nur eine einzige gibt!
Post by Jan Bruns
Aus diesen Dokumenten geht eindeutig hervor, dass x86- Programmierer
nicht direkten Einfluss auf die Kohärenz der diversen Cachehierarchien
nehmen können.
Auch 68k- Systeme mit mehreren Prozessoren dürften die
möglichen Kohärenz-Probleme mit einer hardwareseitigen Steuerung über
ihren Chipsatz lösen, da softwareseitige Lösungen viel zu träge wären,
um derlei Aufgaben in Echtzeit zu erledigen.
Äh. User-Land und "Einfluss auf die Cache Kohärenz"
sind doch nun wirklich Begriffe, denen man auch
intuitiv kein Zusammenpassen andeutet.
Was wolltest Du mit dieser Aneinanderreihung vieler komplexer
Worte zu einem noch komplexeren Satzbau eigentlich mitteilen?


Grüsse aus Augsburg

Bernhard Schornak
Jan Bruns
2014-12-05 09:12:59 UTC
Permalink
Möglicherweise wärest Du mit "selbstgestrickten" Cachestrate- gien in
alt.os.development besser aufgehoben?
Sehr witzig.

Welche Plattformunabhängigen, real vorhandenen Betriebssystemcall
schlägst Du denn vor, um bspw. 1 Mio. Objekte mit Threadlocks zu versehen?
Aus diesen Dokumenten geht hervor, daß im Sinne meiner Fragestellung
eine ganz und gar absolute Cache-Kohärenz zu den Idealen der
CPU-Entwickler zählt. Hast Du vielleicht auch noch einen Link auf die
Bug-Report Liste zur Wald-und-Wiesen-CPU?
Welche da wäre? Ich bezweifle, das es nur eine einzige gibt!
Hardware hat genau wie Software immer irgendwelche Bugs.

Dieses Problem hier hat allerdings anscheinend eine andere Ursache,
die bereits dokumentiert ist:

Ich glaube, die Ursache des Problems ist folgende:

CMPXCHG schreibt laut irgendeinem Datenblatt von
AMD oder Intel auf jeden Fall, entweder die
glesenen Daten, oder den Registerwert.

Nun ist da aber auch ein Memory-System, bei
es normal ist, daß bei gleichzeitigen Schreib-
anforderungen von mehreren Seiten nur eine Seite
endgültig geschrieben haben kann.

Wenn dann auf mehreren Kernen gleichzeitig
CMPXCHG ausgeführt wird, und beide auf jeden
Fall schreiben, obwohl nur einer konsistente
Daten liefert, wird sich das Memory-System
regelmässig für die falschen (unveränderten)
Daten entscheiden.

Gruss

Jan Bruns
Bernhard Schornak
2014-12-05 16:43:14 UTC
Permalink
Post by Jan Bruns
Möglicherweise wärest Du mit "selbstgestrickten" Cachestrate- gien in
alt.os.development besser aufgehoben?
Sehr witzig.
Das war (und ist!) durchaus ernst gemeint. Du postest den
Code ja nicht, weil es Dir gerade langweilig ist, sondern
um Dein Wissen mit anderen Menschen zu teilen. In AOD be-
steht immerhin die Möglichkeit, dass sich ein anderer OS-
Entwickler ebenfalls mit Cacheverwaltung beschäftigt, und
seine Erfahrungen gegebenenfalls mit Dir austauscht.
Post by Jan Bruns
Welche Plattformunabhängigen, real vorhandenen Betriebssystemcall
schlägst Du denn vor, um bspw. 1 Mio. Objekte mit Threadlocks zu versehen?
Für Assemblerprogrammierer gibt es ja seit Ewigkeiten den
LOCK-Präfix. Wie es in so genannten "Hochsprachen" gelöst
wird, hängt von der jeweiligen Hochsprache ab. Das könnte
-hier- allerdings nur von Interesse sein, wenn es sich um
eine in Assembler verfasste Funktion / Routine handelte -
Lösungen in Hochsprachen sind nur möglich, wenn diese wie
C eine Möglichkeit bieten, Assemblerbefehle direkt in den
Hochsprachencode einzubinden. Was übrigens den Sinn einer
Hochsprache, nämlich die Unabhängigkeit von der Maschine,
auf der sie gerade läuft, ad absurdum führt...
Post by Jan Bruns
Aus diesen Dokumenten geht hervor, daß im Sinne meiner Fragestellung
eine ganz und gar absolute Cache-Kohärenz zu den Idealen der
CPU-Entwickler zählt. Hast Du vielleicht auch noch einen Link auf die
Bug-Report Liste zur Wald-und-Wiesen-CPU?
Welche da wäre? Ich bezweifle, das es nur eine einzige gibt!
Hardware hat genau wie Software immer irgendwelche Bugs.
Das beantwortet die Frage nicht. Da Du die Existenz einer
"Wald-und-Wiesen-CPU" deklarierst, solltest Du Hersteller
und Typbezeichnung doch jederzeit benennen können.

Es gibt sowohl von AMD als auch von iNTEL dicke PDFs, die
Listen mit allen bekannten Fehlern und "Workarounds" ent-
halten.

Das "Perfekte an und für sich" ist eine Illusion -dummer-
Menschen, die mangels Denkvermögen nicht erfassen können,
dass etwas "perfektes" in einem sich selbst entwickelnden
Universum schon prinzipbedingt nicht existieren kann. Was
auch entwickelt wird - es gibt immer eine Möglickeit, das
aktuelle Modell noch weiter zu verbessern.
Post by Jan Bruns
Dieses Problem hier hat allerdings anscheinend eine andere Ursache,
CMPXCHG schreibt laut irgendeinem Datenblatt von
AMD oder Intel auf jeden Fall, entweder die
glesenen Daten, oder den Registerwert.
Nun ist da aber auch ein Memory-System, bei
es normal ist, daß bei gleichzeitigen Schreib-
anforderungen von mehreren Seiten nur eine Seite
endgültig geschrieben haben kann.
Wenn dann auf mehreren Kernen gleichzeitig
CMPXCHG ausgeführt wird, und beide auf jeden
Fall schreiben, obwohl nur einer konsistente
Daten liefert, wird sich das Memory-System
regelmässig für die falschen (unveränderten)
Daten entscheiden.
Im von Dir vorgegebenen Szenario -können- die Prozessoren
nur unveränderte Daten lesen, da Änderungen erst nach der
vorgenommenen Manipulation an die Speicherhierarchie (vom
L1-Cache bis hin zum Hauptspeicher) weitergegeben werden.
Deshalb wurde ja der LOCK-Befehl eingeführt. Er wirkt auf
den Datenbus des Systems, und sperrt alle Prozessoren bis
auf einen, so lange ein R-M-W-Schreibzugriff erfolgt. Was
auf der Kostenseite (da Gewinn[x] = Verlust[y]) R-M-W-Zu-
griffe für alle Prozessoren verlangsamt.

Wer verwendet schon freiwillig CMPXCHG? In derselben Zeit
können parallel (abhängig von der Zahl der Pipes) mehrere
MOV-CMP-MOV-Operationen ausgeführt werden.


Grüsse aus Augsburg

Bernhard Schornak
Jan Bruns
2014-12-05 20:20:30 UTC
Permalink
Post by Jan Bruns
Möglicherweise wärest Du mit "selbstgestrickten" Cachestrate- gien in
alt.os.development besser aufgehoben?
Sehr witzig.
Das war (und ist!) durchaus ernst gemeint. Du postest den Code ja nicht,
weil es Dir gerade langweilig ist, sondern um Dein Wissen mit anderen
Menschen zu teilen. In AOD be- steht immerhin die Möglichkeit, dass sich
ein anderer OS- Entwickler ebenfalls mit Cacheverwaltung beschäftigt,
und seine Erfahrungen gegebenenfalls mit Dir austauscht.
Was denn für Wissen?
Nö, ich habe den Code wie gesagt abgekippt, um den Kontext der
Fragestellung nach dem Verhalten moderner CPU zu veranschaulichen.

Und "Cacheverwaltung"? Was ist das?

Das Anwendungsbeispiel für den (so ja nicht sinnvoll funktionieren
Code) wäre sowas wie eine Datenbank, deren Datenelemente von mehren
Prozessorkernen gleichzeitig beabreitet werden könnten. Dazu müssen
der Kerne sich irgendwie absprechen, damit sich nicht auf halbfertige
Daten verlassen werden muss.
Für Assemblerprogrammierer gibt es ja seit Ewigkeiten den LOCK-Präfix.
Wie es in so genannten "Hochsprachen" gelöst wird, hängt von der
jeweiligen Hochsprache ab.
Ich habe aber doch schon gesagt, daß es sich eifach um ganz
stinkpiefnormale x86 calls zu stimkoefnormalen x86 Unterfunktionen
handelt:

Zum Beispiel eine Ausgabe vom linux tool "perf":

: Disassembly of section .text:
:
: 0000000000410f88 <FPC_INTERLOCKEDCOMPAREEXCHANGE>:
1,60 : 410f88: push %rbp
9,29 : 410f89: mov %rsp,%rbp
1,28 : 410f8c: sub $0x10,%rsp
3,85 : 410f90: mov %edx,%eax
0,96 : 410f92: lock cmpxchg %esi,(%rdi)
83,01 : 410f96: leaveq


Mit dem Lock-Präfix habe ich bisher noch nie zu tun gehabt, das schien
mir bisher auch hauptsächlich ein Relikt aus der ISA-Bus Ära zu sein, und
bisher wollte ich einfach noch kein #LOCK-Signal.

Dem Anschein nach bewirkt es nicht wirklich zuverlässig das, was andere
Leute sich davon zu erhoffen scheinen (etwa das, was ich von der gerade
gezeigten INTERLOCKEDCOMPAREEXCHANGE erhofft habe, eben eine vollständig
atomische Operation auch in dem Sinne, daß deren Wirkung von allen Kernen
aus gleich aussieht, und der caller zuverlässig entscheiden kann, was
andere Kerne durch diie Operation zu sehen bekommen).
Das könnte -hier- allerdings nur von
Interesse sein, wenn es sich um eine in Assembler verfasste Funktion /
Routine handelte - Lösungen in Hochsprachen sind nur möglich, wenn diese
wie C eine Möglichkeit bieten, Assemblerbefehle direkt in den
Hochsprachencode einzubinden. Was übrigens den Sinn einer Hochsprache,
nämlich die Unabhängigkeit von der Maschine, auf der sie gerade läuft,
ad absurdum führt...
Naja, im Zweifel geht ja auf jeden Fall serialisieren, also
den ganzen Kram mit nur einem Kern erledigen. Genau das wollte ich aber
ja eigentlich vermeiden.
Es gibt sowohl von AMD als auch von iNTEL dicke PDFs, die Listen mit
allen bekannten Fehlern und "Workarounds" ent- halten.
Tatsächlich? Interessant. Wo?
Post by Jan Bruns
CMPXCHG schreibt laut irgendeinem Datenblatt von AMD oder Intel auf
jeden Fall, entweder die glesenen Daten, oder den Registerwert.
Nun ist da aber auch ein Memory-System, bei es normal ist, daß bei
gleichzeitigen Schreib- anforderungen von mehreren Seiten nur eine
Seite endgültig geschrieben haben kann.
Wenn dann auf mehreren Kernen gleichzeitig CMPXCHG ausgeführt wird, und
beide auf jeden Fall schreiben, obwohl nur einer konsistente Daten
liefert, wird sich das Memory-System regelmässig für die falschen
(unveränderten) Daten entscheiden.
Leteres solle aber ja eigentlich, wie Du schriebst, und wie auch viele
andere meinen, durch das Lock-Präfix vermieden werden.
Im von Dir vorgegebenen Szenario -können- die Prozessoren nur
unveränderte Daten lesen, da Änderungen erst nach der vorgenommenen
Manipulation an die Speicherhierarchie (vom L1-Cache bis hin zum
Hauptspeicher) weitergegeben werden. Deshalb wurde ja der LOCK-Befehl
eingeführt. Er wirkt auf den Datenbus des Systems, und sperrt alle
Prozessoren bis auf einen, so lange ein R-M-W-Schreibzugriff erfolgt.
Was auf der Kostenseite (da Gewinn[x] = Verlust[y]) R-M-W-Zu- griffe für
alle Prozessoren verlangsamt.
Bus? Sehe ich nicht. Die Zeiten, in denen das Spass gemacht haben kann,
sich in Datenblättern die Funktion einzelner Pins anzusehen jeweils
aktueller CPUs anusehen, sind ja erstmal vorbei.
Wer verwendet schon freiwillig CMPXCHG? In derselben Zeit können
parallel (abhängig von der Zahl der Pipes) mehrere
MOV-CMP-MOV-Operationen ausgeführt werden.
Klingt jetzt erstmal nach serialisieren. Z.B. könne ich eine ObjektId
(Toid) dazu verwenden, eine critical section, oder sowas auszuwählen,
damit die Kerne sich seltener gegenseitig aufhalten.

Angenehm wäre mir allerdings, wenn sich dieses unerwartete LOCK CMPXCHG
Verhalten (so es nicht an irgendwelchen sonstigen Fehlern lag)
aufklären täte. Ich könnte ja problemlos damit leben, da eben
falsche Erwartungen gehabt zu haben, nur wo, das wäre dann schon
interessant. Hat mich immerhin schon einige Stunden gekostet, mir
dieses compare-and-swap basierte System auszudenken.

Gruss

Jan Bruns
Bernhard Schornak
2014-12-06 11:13:45 UTC
Permalink
Post by Jan Bruns
Post by Jan Bruns
Möglicherweise wärest Du mit "selbstgestrickten" Cachestrate- gien in
alt.os.development besser aufgehoben?
Sehr witzig.
Das war (und ist!) durchaus ernst gemeint. Du postest den Code ja nicht,
weil es Dir gerade langweilig ist, sondern um Dein Wissen mit anderen
Menschen zu teilen. In AOD be- steht immerhin die Möglichkeit, dass sich
ein anderer OS- Entwickler ebenfalls mit Cacheverwaltung beschäftigt,
und seine Erfahrungen gegebenenfalls mit Dir austauscht.
Was denn für Wissen?
Das, das Du Dir bei der Entwicklung des geposteten Texts ange-
eignet hast?
Post by Jan Bruns
Nö, ich habe den Code wie gesagt abgekippt, um den Kontext der
Fragestellung nach dem Verhalten moderner CPU zu veranschaulichen.
Dazu musstest Du Dich aber -irgendwann einmal- mit dem Problem
auseinandersetzen?
Post by Jan Bruns
Und "Cacheverwaltung"? Was ist das?
Alles, was mit der Verwaltung der Caches zu tun hat - z.B. das
MESI/MOESI-Protokoll, die Befehle CLFLUSH, INVD, WBINDV, Hints
wie MOVNTDQ, und so weiter...
Post by Jan Bruns
Das Anwendungsbeispiel für den (so ja nicht sinnvoll funktionieren
Code) wäre sowas wie eine Datenbank, deren Datenelemente von mehren
Prozessorkernen gleichzeitig beabreitet werden könnten. Dazu müssen
der Kerne sich irgendwie absprechen, damit sich nicht auf halbfertige
Daten verlassen werden muss.
Das kann ich leider nicht nachvollziehen, da Dein merkwürdiger
Text keine einzige Zeile Assemblercode enthält. Wie gesagt: Du
schreibst in einer NG, die sich an Assemblerprogrammierer (und
nicht an Hochsprachenfreaks...) richtet.
Post by Jan Bruns
Für Assemblerprogrammierer gibt es ja seit Ewigkeiten den LOCK-Präfix.
Wie es in so genannten "Hochsprachen" gelöst wird, hängt von der
jeweiligen Hochsprache ab.
Ich habe aber doch schon gesagt, daß es sich eifach um ganz
stinkpiefnormale x86 calls zu stimkoefnormalen x86 Unterfunktionen
1,60 : 410f88: push %rbp
9,29 : 410f89: mov %rsp,%rbp
1,28 : 410f8c: sub $0x10,%rsp
3,85 : 410f90: mov %edx,%eax
0,96 : 410f92: lock cmpxchg %esi,(%rdi)
83,01 : 410f96: leaveq
Was sich auf

mov %edx, %eax
lock cmpxchg %esi, (%rdi)
ret

reduzieren liesse. Der Rest ist redundant, da die einzige hier
ausgeführte Sequenz keinen Stapelrahmen (stackframe) benötigt.
Die verwendeten Register sind laut "64 Bit Calling Convention"
der Linux-API als "volatile" definiert, sie müssen somit nicht
gesichert und wieder hergestellt werden. Bei Windows-64 müsste
man RDI und RSI sichern. Es geht auch ganz ohne Stapelrahmen:

http://tinyurl.com/oxwepcr
Post by Jan Bruns
Mit dem Lock-Präfix habe ich bisher noch nie zu tun gehabt, das schien
mir bisher auch hauptsächlich ein Relikt aus der ISA-Bus Ära zu sein, und
bisher wollte ich einfach noch kein #LOCK-Signal.
http://www.i8086.de/asm/8086-88-asm-lock.html
Post by Jan Bruns
Dem Anschein nach bewirkt es nicht wirklich zuverlässig das, was andere
Leute sich davon zu erhoffen scheinen (etwa das, was ich von der gerade
gezeigten INTERLOCKEDCOMPAREEXCHANGE erhofft habe, eben eine vollständig
atomische Operation auch in dem Sinne, daß deren Wirkung von allen Kernen
aus gleich aussieht, und der caller zuverlässig entscheiden kann, was
andere Kerne durch diie Operation zu sehen bekommen).
Genaue Informationen könntest Du über das verwendete Protokoll,
MESI bei iNTEL / MOESI bei AMD, erfahren. Diese Protokolle sind
für die Kommunikation zwischen den Kernen verantwortlich.
Post by Jan Bruns
Das könnte -hier- allerdings nur von
Interesse sein, wenn es sich um eine in Assembler verfasste Funktion /
Routine handelte - Lösungen in Hochsprachen sind nur möglich, wenn diese
wie C eine Möglichkeit bieten, Assemblerbefehle direkt in den
Hochsprachencode einzubinden. Was übrigens den Sinn einer Hochsprache,
nämlich die Unabhängigkeit von der Maschine, auf der sie gerade läuft,
ad absurdum führt...
Naja, im Zweifel geht ja auf jeden Fall serialisieren, also
den ganzen Kram mit nur einem Kern erledigen. Genau das wollte ich aber
ja eigentlich vermeiden.
Mit LOCK CMPXCHG(x) dauert es wesentlich länger, die selbe Auf-
gabe abzuarbeiten, da alle am Bus hängenden Prozessoren auf die
Abarbeitung aller signalisierten LOCKs warten müssen.
Post by Jan Bruns
Es gibt sowohl von AMD als auch von iNTEL dicke PDFs, die Listen mit
allen bekannten Fehlern und "Workarounds" ent- halten.
Tatsächlich? Interessant. Wo?
Revision Guide for AMD Family 10h Processors PDF: 41322
Revision Guide for AMD Family 15h Models 00h-0Fh
Processors PDF: 48063

Bei iNTEL hab ich noch keine vergleichbaren Dokumente gefunden.
Post by Jan Bruns
Post by Jan Bruns
CMPXCHG schreibt laut irgendeinem Datenblatt von AMD oder Intel auf
jeden Fall, entweder die glesenen Daten, oder den Registerwert.
Nun ist da aber auch ein Memory-System, bei es normal ist, daß bei
gleichzeitigen Schreib- anforderungen von mehreren Seiten nur eine
Seite endgültig geschrieben haben kann.
Wenn dann auf mehreren Kernen gleichzeitig CMPXCHG ausgeführt wird, und
beide auf jeden Fall schreiben, obwohl nur einer konsistente Daten
liefert, wird sich das Memory-System regelmässig für die falschen
(unveränderten) Daten entscheiden.
Leteres solle aber ja eigentlich, wie Du schriebst, und wie auch viele
andere meinen, durch das Lock-Präfix vermieden werden.
LOCK sperrt die Kommunikation für alle am Bus hängenden Geräte,
bis der die Sperrung auslösende Befehl abgearbeitet wurde.
Post by Jan Bruns
Im von Dir vorgegebenen Szenario -können- die Prozessoren nur
unveränderte Daten lesen, da Änderungen erst nach der vorgenommenen
Manipulation an die Speicherhierarchie (vom L1-Cache bis hin zum
Hauptspeicher) weitergegeben werden. Deshalb wurde ja der LOCK-Befehl
eingeführt. Er wirkt auf den Datenbus des Systems, und sperrt alle
Prozessoren bis auf einen, so lange ein R-M-W-Schreibzugriff erfolgt.
Was auf der Kostenseite (da Gewinn[x] = Verlust[y]) R-M-W-Zu- griffe für
alle Prozessoren verlangsamt.
Bus? Sehe ich nicht. Die Zeiten, in denen das Spass gemacht haben kann,
sich in Datenblättern die Funktion einzelner Pins anzusehen jeweils
aktueller CPUs anusehen, sind ja erstmal vorbei.
Einen Prozessor mit Null Pins und ohne interne Verdrahtung gibt
es (noch) nicht...

Gemeint ist hier auch eher der interne Bus, an dem alle "Kerne"
eines Prozessors hängen. Über diesen werden alle Kerne an ihren
Anteil des L2- und L3-Cache und den Hauptspeicher angeschlossen
und kommunizieren miteinander.
Post by Jan Bruns
Wer verwendet schon freiwillig CMPXCHG? In derselben Zeit können
parallel (abhängig von der Zahl der Pipes) mehrere
MOV-CMP-MOV-Operationen ausgeführt werden.
Klingt jetzt erstmal nach serialisieren. Z.B. könne ich eine ObjektId
(Toid) dazu verwenden, eine critical section, oder sowas auszuwählen,
damit die Kerne sich seltener gegenseitig aufhalten.
Das macht das Protokoll automatisch - der Programmierer hat auf
die Kommunikation der Kerne untereinander wenig Einfluss.
Post by Jan Bruns
Angenehm wäre mir allerdings, wenn sich dieses unerwartete LOCK CMPXCHG
Verhalten (so es nicht an irgendwelchen sonstigen Fehlern lag)
aufklären täte. Ich könnte ja problemlos damit leben, da eben
falsche Erwartungen gehabt zu haben, nur wo, das wäre dann schon
interessant. Hat mich immerhin schon einige Stunden gekostet, mir
dieses compare-and-swap basierte System auszudenken.
http://wiki.osdev.org/Spinlock


Grüsse aus Augsburg

Bernhard Schornak
Jan Bruns
2014-12-08 07:29:19 UTC
Permalink
Post by Bernhard Schornak
Was sich auf
mov %edx, %eax
lock cmpxchg %esi, (%rdi)
ret
reduzieren liesse. Der Rest ist redundant, da die einzige hier
ausgeführte Sequenz keinen Stapelrahmen (stackframe) benötigt. Die
verwendeten Register sind laut "64 Bit Calling Convention" der Linux-API
als "volatile" definiert, sie müssen somit nicht gesichert und wieder
hergestellt werden. Bei Windows-64 müsste man RDI und RSI sichern. Es
Ich kann Dir grad gar nicht genau sagen, was für eine calling
convention die Funktion verwendet. Es handelt sich ja wie gesagt
um eine quasi Compiler-eigene Funktion aus der "System-Unit", deren
Quelltext auch aus so vielen Dateien zusammengewürfelt ist, daß man
deren Aufbau nur sehr Mühsam nachvollziehen kann. Jedenfalls hat der
Compiler die Funktion ganz offenbar nicht direkt geinlined (also ganz
ohne call/ret), was er von mir aus auch gerne hätte machen können.

Scheint aber ja "zufällig" nach einem SystemV64-ABI kompatiblen
Aufrauf auszusehen.

Stimmt zwar, daß das unnötige Stackframe irgendwie ranzig aussieht,
aber vielleicht hat das ja Gründe. Denkbar wäre z.B., daß das wegen
irgendwelcher Stack-Unwinding Geschichten angelegt wird. Wenn z.B.
der das cmpxchg zu einer Speicherzugriffsverletzung führt, erhalte
ich ja nicht nur einfach eine Exception, sondern auch noch daren
letzte Gegenmassnahme, die sich in diesem Fall so ausgestaltet,
daß mir ein ungewindeter Call-Trace angezeigt wird, vielleicht
sogar mit den Namen der Quelltextdateien und Zeilennummern.

Gruss

Jan Bruns
Bernhard Schornak
2014-12-08 15:55:59 UTC
Permalink
Post by Jan Bruns
Post by Bernhard Schornak
Was sich auf
mov %edx, %eax
lock cmpxchg %esi, (%rdi)
ret
reduzieren liesse. Der Rest ist redundant, da die einzige hier
ausgeführte Sequenz keinen Stapelrahmen (stackframe) benötigt. Die
verwendeten Register sind laut "64 Bit Calling Convention" der Linux-API
als "volatile" definiert, sie müssen somit nicht gesichert und wieder
hergestellt werden. Bei Windows-64 müsste man RDI und RSI sichern. Es
Ich kann Dir grad gar nicht genau sagen, was für eine calling
convention die Funktion verwendet.
Da RDI und RSI nicht gesichert werden, kann es sich nur um Linux
handeln.

http://agner.org/optimize/calling_conventions.pdf
Post by Jan Bruns
Es handelt sich ja wie gesagt
um eine quasi Compiler-eigene Funktion aus der "System-Unit", deren
Quelltext auch aus so vielen Dateien zusammengewürfelt ist, daß man
deren Aufbau nur sehr Mühsam nachvollziehen kann. Jedenfalls hat der
Compiler die Funktion ganz offenbar nicht direkt geinlined (also ganz
ohne call/ret), was er von mir aus auch gerne hätte machen können.
Scheint aber ja "zufällig" nach einem SystemV64-ABI kompatiblen
Aufrauf auszusehen.
Stimmt zwar, daß das unnötige Stackframe irgendwie ranzig aussieht,
aber vielleicht hat das ja Gründe. Denkbar wäre z.B., daß das wegen
irgendwelcher Stack-Unwinding Geschichten angelegt wird. Wenn z.B.
der das cmpxchg zu einer Speicherzugriffsverletzung führt, erhalte
ich ja nicht nur einfach eine Exception, sondern auch noch daren
letzte Gegenmassnahme, die sich in diesem Fall so ausgestaltet,
daß mir ein ungewindeter Call-Trace angezeigt wird, vielleicht
sogar mit den Namen der Quelltextdateien und Zeilennummern.
Der einzige Grund, redundanten Code zu generieren, ist der, dass
diejenigen, die derartige Konstrukte produzieren, keinen blassen
Schimmer von Assemblerprogrammierung haben. Bei Exceptions würde
die Inhalte aller Register vor der Abarbeitung gesichert und zu-
dem in Logfiles gespeichert, um dem Anwendungsprogrammierern die
Fehlersuche zu ermöglichen - sicher kein Argument für den Aufbau
überflüssiger Stapelrahmen...


Grüsse aus Augsburg

Bernhard Schornak
Jan Bruns
2014-12-09 03:18:14 UTC
Permalink
Post by Bernhard Schornak
Post by Jan Bruns
Ich kann Dir grad gar nicht genau sagen, was für eine calling
convention die Funktion verwendet.
Da RDI und RSI nicht gesichert werden, kann es sich nur um Linux
handeln.
cmpxchg %esi, (%rdi)

verändert doch RDI und RSI gar nicht, also bräuchte auch dann
nichts gesichert werden, wenn der callee die zu erhalten hätte.
Post by Bernhard Schornak
Post by Jan Bruns
Stimmt zwar, daß das unnötige Stackframe irgendwie ranzig aussieht,
aber vielleicht hat das ja Gründe. Denkbar wäre z.B., daß das wegen
irgendwelcher Stack-Unwinding Geschichten angelegt wird. Wenn z.B. der
das cmpxchg zu einer Speicherzugriffsverletzung führt, erhalte ich ja
nicht nur einfach eine Exception, sondern auch noch daren letzte
Gegenmassnahme, die sich in diesem Fall so ausgestaltet, daß mir ein
ungewindeter Call-Trace angezeigt wird, vielleicht sogar mit den Namen
der Quelltextdateien und Zeilennummern.
Der einzige Grund, redundanten Code zu generieren, ist der, dass
diejenigen, die derartige Konstrukte produzieren, keinen blassen
Schimmer von Assemblerprogrammierung haben. Bei Exceptions würde die
Inhalte aller Register vor der Abarbeitung gesichert und zu- dem in
Logfiles gespeichert, um dem Anwendungsprogrammierern die Fehlersuche zu
ermöglichen - sicher kein Argument für den Aufbau überflüssiger
Stapelrahmen...
Hast Du schonmal versucht, den call-stack zurückzuverfolgen?
Ist das dabei wohl hilfreich, wenn jeder call seine frames beliebig
gestaltet? Dann musst man zum unwinden eine Tabelle haben, in der
für jeden call-codepunkt, und zudem für jeden Ort, an dem eine
Exception auftreten kann, die für den Position verwendete Stackverwendung
verzeichnet ist. Kann man auch machen, aber b da nicht einfach zu faul
zu ist, ist natürlich eine andere Frage. Dann bleibt aber nur noch die
Wahl, entweder auf solche hilfreichen anwinds zu verzichten, oder
eben zuweilen überflüssige Stackframes anzulegen.

Überhaupt nervt das übrigens ein wenig, so dieses andauernde
thematisieren der Kompetenz anderer Leute. Da könntest Du mal
dran arbeiten, das zu minimieren.


Gruss

Jan Bruns
Bernhard Schornak
2014-12-09 14:54:47 UTC
Permalink
Post by Bernhard Schornak
Post by Bernhard Schornak
Post by Jan Bruns
Ich kann Dir grad gar nicht genau sagen, was für eine calling
convention die Funktion verwendet.
Da RDI und RSI nicht gesichert werden, kann es sich nur um Linux
handeln.
cmpxchg %esi, (%rdi)
verändert doch RDI und RSI gar nicht, also bräuchte auch dann
nichts gesichert werden, wenn der callee die zu erhalten hätte.
Das weiss der Compiler, der diese Sequenz erzeugt hatte, ganz
sicher nicht. Er weiss nur, dass er RSI und RDI nicht sichern
muss (selbst dann, wenn er einen Stapelrahmen aufgebaut hat),
da das im "Application Binary Interface" so definiert ist. Da
das Win-64-ABI die Sicherung dieser Register vorschreibt (und
minGW das auch so compiliert), kann es sich nur um ein Linux-
Konstrukt handeln.

Der verschwenderische Umgang mit Ressourcen war unter Anderem
der Grund, weshalb ich (überzeugter Open-Source-Programierer)
2009 von OS/2 nicht auf Linux, sondern auf 64 Bit Windows um-
gestiegen bin. Wenn nur sechs von 32 Registern (18,75%!) nach
einem Aufruf den gleichen Wert wie davor haben, bedeutet das,
dass ich 26 von 32 Registern (81,25%!) vor dem Aufruf sichern
und anschliessend wieder vom Stapel laden muss. Bei Windows64
wurde nur die Hälfte, also 13 von 32 Registern (40,625%), als
"volatile" definiert, was gerade noch im Grenzbereich des Er-
träglichen liegt.

Wer Wert auf unveränderte Register nach einem Funktionsaufruf
legt, muss seine API-Aufrufe in so genannte "Wrapper" packen,
deren einziger Sinn es ist, die vom Betriebssystem zerstörten
Registerinhalte vor jedem Aufruf zu sichern und danach wieder
in die überschriebenen Register zu laden:

https://code.google.com/p/st-open/source/browse/LIB/SOURCES/core/cap.S
Post by Bernhard Schornak
Post by Bernhard Schornak
Post by Jan Bruns
Stimmt zwar, daß das unnötige Stackframe irgendwie ranzig aussieht,
aber vielleicht hat das ja Gründe. Denkbar wäre z.B., daß das wegen
irgendwelcher Stack-Unwinding Geschichten angelegt wird. Wenn z.B. der
das cmpxchg zu einer Speicherzugriffsverletzung führt, erhalte ich ja
nicht nur einfach eine Exception, sondern auch noch daren letzte
Gegenmassnahme, die sich in diesem Fall so ausgestaltet, daß mir ein
ungewindeter Call-Trace angezeigt wird, vielleicht sogar mit den Namen
der Quelltextdateien und Zeilennummern.
Der einzige Grund, redundanten Code zu generieren, ist der, dass
diejenigen, die derartige Konstrukte produzieren, keinen blassen
Schimmer von Assemblerprogrammierung haben. Bei Exceptions würde die
Inhalte aller Register vor der Abarbeitung gesichert und zu- dem in
Logfiles gespeichert, um dem Anwendungsprogrammierern die Fehlersuche zu
ermöglichen - sicher kein Argument für den Aufbau überflüssiger
Stapelrahmen...
Hast Du schonmal versucht, den call-stack zurückzuverfolgen?
Was ist ein "call-stack"? Assembler kennt ein Stacksegment SS
und den Stackpointer rSP. Da das Stacksegment SS in der Regel
vom Betriebssystem gesetzt wird und im Protected Mode von den
Anwendungsprogrammierern und Compilern nicht verändert werden
kann, ist nur der Stapelzeiger rSP änderbar.

HLL-Compiler "wissen", dass rSP bei jedem CALL auf dem Stapel
abgelegt wird und dann vier (32 Bit OS) oder acht (64 Bit OS)
von rSP abgezogen werden. "Stapelrahmen" können konventionell
über das rSP/rBP-Paar oder zeitgemäss mittels Abziehen des in
der Funktion benötigten Platzbedarfs von rSP und Addition der
selben Summe beim Verlassen der Funktion aufgebaut / zerstört
werden.

http://tinyurl.com/oxwepcr
Post by Bernhard Schornak
Ist das dabei wohl hilfreich, wenn jeder call seine frames beliebig
gestaltet? Dann musst man zum unwinden eine Tabelle haben, in der
für jeden call-codepunkt, und zudem für jeden Ort, an dem eine
Exception auftreten kann, die für den Position verwendete Stackverwendung
verzeichnet ist. Kann man auch machen, aber b da nicht einfach zu faul
zu ist, ist natürlich eine andere Frage. Dann bleibt aber nur noch die
Wahl, entweder auf solche hilfreichen anwinds zu verzichten, oder
eben zuweilen überflüssige Stackframes anzulegen.
Könntest Du das bitte auf Deutsch wiederholen? Ich kann jetzt
wild raten, dass das "b" ein "ob" sein sollte, davon wird der
Satz aber nicht unbedingt verständlicher.
Post by Bernhard Schornak
Überhaupt nervt das übrigens ein wenig, so dieses andauernde
thematisieren der Kompetenz anderer Leute. Da könntest Du mal
dran arbeiten, das zu minimieren.
Ich arbeite seit mehr als 35 Jahren mit Assemblern (68k, x86,
x86-64) - es dürfte schwer sein, mir etwas unterzujubeln, das
nicht koscher ist. Wenn ich einen Fehler sehe, weise ich auch
darauf hin, das ist letztendlich der Sinn einer Newsgroup für
Programmierer. Wenn ich Fehler aufzeige, erlaube ich mir, auf
offensichtliche Dinge hinzuweisen. Wenn "Compiler-Bauer" ihre
Compiler vorsätzlich redundanten Code erzeugen lassen, leiden
dadurch nicht nur die Benutzer, sondern auch die Ressourcen -
Milliarden Prozessoren sind unnötigerweise länger beschäftigt
und schalten zwangsläufig weit weniger oft in energiesparende
Betriebsmodi. Es geht somit um ein globales Problem, nicht um
Befindlichkeiten einiger Individuen.

Leider halten wir es heutezutage für unnötig, uns über solche
simplen Zusammenhänge Gedanken zu machen, vergiessen aber ki-
loweise Krokodilstränen über eine globale Erwärmung, die erst
durch unser aktives (Produzenten) oder passives (Konsumenten)
Tun entstand und gedankenlos am Leben erhalten wird.


Grüsse aus Augsburg

Bernhard Schornak
Peter J. Holzer
2014-12-13 10:53:19 UTC
Permalink
Post by Bernhard Schornak
Post by Bernhard Schornak
Post by Bernhard Schornak
Post by Jan Bruns
Ich kann Dir grad gar nicht genau sagen, was für eine calling
convention die Funktion verwendet.
Da RDI und RSI nicht gesichert werden, kann es sich nur um Linux
handeln.
Das ist ein Fehlschluss.
Post by Bernhard Schornak
Post by Bernhard Schornak
cmpxchg %esi, (%rdi)
verändert doch RDI und RSI gar nicht, also bräuchte auch dann
nichts gesichert werden, wenn der callee die zu erhalten hätte.
Das weiss der Compiler, der diese Sequenz erzeugt hatte, ganz
sicher nicht.
Wenn der Sequenz von einem Compiler erzeugt wurde (ich halte es für
nicht unwahrscheinlich, dass die handgeschrieben ist), dann weiß er das
ziemlich sicher sehr wohl. Wie soll er denn Code erzeugen, wenn er nicht
weiß, was eine Instruktion macht?
Post by Bernhard Schornak
Er weiss nur, dass er RSI und RDI nicht sichern
muss (selbst dann, wenn er einen Stapelrahmen aufgebaut hat),
da das im "Application Binary Interface" so definiert ist. Da
das Win-64-ABI die Sicherung dieser Register vorschreibt (und
minGW das auch so compiliert), kann es sich nur um ein Linux-
Konstrukt handeln.
Der verschwenderische Umgang mit Ressourcen war unter Anderem
der Grund, weshalb ich (überzeugter Open-Source-Programierer)
2009 von OS/2 nicht auf Linux, sondern auf 64 Bit Windows um-
gestiegen bin. Wenn nur sechs von 32 Registern (18,75%!) nach
einem Aufruf den gleichen Wert wie davor haben, bedeutet das,
dass ich 26 von 32 Registern (81,25%!) vor dem Aufruf sichern
und anschliessend wieder vom Stapel laden muss. Bei Windows64
wurde nur die Hälfte, also 13 von 32 Registern (40,625%), als
"volatile" definiert, was gerade noch im Grenzbereich des Er-
träglichen liegt.
Der Streit darüber, ob Caller-Save oder Callee-Save besser ist, ist alt.
Aus der Tatsache, dass er noch nicht entschieden ist, kann man
schließen, dass es keine allgemeingültige Antwort gibt.

Generell ist es in beiden Fällen unvermeidlich, dass Register
unnötigerweise gesichert werden. Bei Caller-Save muss der Caller das
Register vor dem Call sichern, wenn er nachher noch braucht, selbst wenn
das Register von der aufgerufenen Funktion nicht geändert wird (weil er
das eben nicht weiß). Umgekehrt muss bei Callee-Save der Callee ein
Register, dass er ändert, sichern, selbst wenn es vom Caller nach dem
Aufruf gar nicht mehr benötigt wird (weil er das eben nicht weiß).
Das ließe sich nur mit globaler Register-Allokation zur Linkzeit
verhindern, und selbst das geht nicht über Shared-Library-Grenzen
hinweg. In der Praxis teilt man daher das Registerfile in einen
Teil, für den der Callee zuständig ist und einen, für den der Caller
zuständig ist und überlässt es dem Compiler (oder dem
Assembler-Programmierer), die Register so zuzuweisen, dass die unnötigen
Saves minimiert werden.

Wie Microsoft und AMD (ich nehme an, dass das Unix AMD64 ABI von AMD
festgelegt wurden) bei der genauen Aufteilung angelangt sind, weiß ich
nicht. Ich würde aber annehmen, dass die ihren Hennessy & Patterson
gelesen haben und verschiedene Aufteilungen mit einer Auswahl relevanter
Programme und Libraries getestet haben.
Post by Bernhard Schornak
Post by Bernhard Schornak
Post by Bernhard Schornak
Post by Jan Bruns
Stimmt zwar, daß das unnötige Stackframe irgendwie ranzig aussieht,
aber vielleicht hat das ja Gründe. Denkbar wäre z.B., daß das wegen
irgendwelcher Stack-Unwinding Geschichten angelegt wird. Wenn z.B. der
das cmpxchg zu einer Speicherzugriffsverletzung führt, erhalte ich ja
nicht nur einfach eine Exception, sondern auch noch daren letzte
Gegenmassnahme, die sich in diesem Fall so ausgestaltet, daß mir ein
ungewindeter Call-Trace angezeigt wird, vielleicht sogar mit den Namen
der Quelltextdateien und Zeilennummern.
Der einzige Grund, redundanten Code zu generieren, ist der, dass
diejenigen, die derartige Konstrukte produzieren, keinen blassen
Schimmer von Assemblerprogrammierung haben. Bei Exceptions würde die
Inhalte aller Register vor der Abarbeitung gesichert und zu- dem in
Logfiles gespeichert, um dem Anwendungsprogrammierern die Fehlersuche zu
ermöglichen - sicher kein Argument für den Aufbau überflüssiger
Stapelrahmen...
Hast Du schonmal versucht, den call-stack zurückzuverfolgen?
Was ist ein "call-stack"? Assembler kennt ein Stacksegment SS
und den Stackpointer rSP. Da das Stacksegment SS in der Regel
vom Betriebssystem gesetzt wird und im Protected Mode von den
Anwendungsprogrammierern und Compilern nicht verändert werden
kann, ist nur der Stapelzeiger rSP änderbar.
HLL-Compiler "wissen", dass rSP bei jedem CALL auf dem Stapel
abgelegt wird und dann vier (32 Bit OS) oder acht (64 Bit OS)
von rSP abgezogen werden. "Stapelrahmen" können konventionell
über das rSP/rBP-Paar oder zeitgemäss mittels Abziehen des in
der Funktion benötigten Platzbedarfs von rSP und Addition der
selben Summe beim Verlassen der Funktion aufgebaut / zerstört
werden.
Und wieviel dann jeweils addiert und subtrahiert wird, findet man nur
mehr durch die Analyse des Codes heraus (wenn es nicht woanders extra
abgelegt wird). Einen Stacktrace auszugeben, wird dann etwas mühsam.

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Bernhard Schornak
2014-12-13 15:09:56 UTC
Permalink
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Bernhard Schornak
Post by Bernhard Schornak
Post by Jan Bruns
Ich kann Dir grad gar nicht genau sagen, was für eine calling
convention die Funktion verwendet.
Da RDI und RSI nicht gesichert werden, kann es sich nur um Linux
handeln.
Das ist ein Fehlschluss.
Ach?

Im Bereich x86-64 gibt es nur zwei ABIs. Das andere, von
Microsoft definierte ABI schreibt das Sichern der beiden
hier nicht gesicherten Register vor.

Mir ist weder ein -drittes- x86-64-ABI noch ein weiteres
Prozessordesign bekannt, dass die für x86-64 definierten
Registernamen verwendet...
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Bernhard Schornak
cmpxchg %esi, (%rdi)
verändert doch RDI und RSI gar nicht, also bräuchte auch dann
nichts gesichert werden, wenn der callee die zu erhalten hätte.
Das weiss der Compiler, der diese Sequenz erzeugt hatte, ganz
sicher nicht.
Wenn der Sequenz von einem Compiler erzeugt wurde (ich halte es für
nicht unwahrscheinlich, dass die handgeschrieben ist), dann weiß er das
ziemlich sicher sehr wohl. Wie soll er denn Code erzeugen, wenn er nicht
weiß, was eine Instruktion macht?
Weil "er" nur den Code abarbeitet, den "sein" "Erzeuger"
(ein Applikationsprogrammierer wie Du oder ich) "ihm" in
die Wiege gelegt hat. Es ist sehr unwahrscheinlich, dass
ein Compiler Instruktionen und ihre Parameter auf -mehr-
als die Einhaltung des gültigen Wertebereichs hin prüft,
respektive die Einhaltung der Syntax im Auge behält. Das
"Denken" bleibt weiterhin den Programmierern überlassen,
da Maschinen dazu (immer noch nicht...) fähig sind.


<schnipp>
Post by Peter J. Holzer
...ich nehme an, dass das Unix AMD64 ABI von AMD festgelegt wurden...
Wie sollte das gehen? Unixderivate, darunter Linux, sind
Produkte etlicher "global Player". Ein Zwerg wie AMD ist
sicher nicht in der Lage, den Industriegiganten ihre ABI
aufzudrängen. Es gab eine Richtlinie von AMD, die später
in die System-V-ABI mit einfloss - die wurde aber sicher
nicht von AMD allein festgelegt...


Schönes Wochenende

Bernhard Schornak
Peter J. Holzer
2014-12-13 19:04:19 UTC
Permalink
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Bernhard Schornak
Post by Bernhard Schornak
Post by Jan Bruns
Ich kann Dir grad gar nicht genau sagen, was für eine calling
convention die Funktion verwendet.
Da RDI und RSI nicht gesichert werden, kann es sich nur um Linux
handeln.
Das ist ein Fehlschluss.
Ach?
Ja.
Post by Bernhard Schornak
Im Bereich x86-64 gibt es nur zwei ABIs. Das andere, von
Microsoft definierte ABI schreibt das Sichern der beiden
hier nicht gesicherten Register vor.
Nein. Das ABI schreibt vor, dass der Callee für das Sichern dieser
Register verantwortlich ist. Aber wenn der Callee diese Register nicht
ändert, muss er sie natürlich auch nirgends hin sichern. Wozu sollte das
gut sein? Da hier die beiden Register nicht geändert werden, ist die
Funktion mit dem Microsoft-ABI kompatibel.
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Bernhard Schornak
cmpxchg %esi, (%rdi)
verändert doch RDI und RSI gar nicht, also bräuchte auch dann
nichts gesichert werden, wenn der callee die zu erhalten hätte.
Das weiss der Compiler, der diese Sequenz erzeugt hatte, ganz
sicher nicht.
Wenn der Sequenz von einem Compiler erzeugt wurde (ich halte es für
nicht unwahrscheinlich, dass die handgeschrieben ist), dann weiß er das
ziemlich sicher sehr wohl. Wie soll er denn Code erzeugen, wenn er nicht
weiß, was eine Instruktion macht?
Weil "er" nur den Code abarbeitet, den "sein" "Erzeuger"
(ein Applikationsprogrammierer wie Du oder ich) "ihm" in
die Wiege gelegt hat. Es ist sehr unwahrscheinlich, dass
ein Compiler Instruktionen und ihre Parameter auf -mehr-
als die Einhaltung des gültigen Wertebereichs hin prüft,
respektive die Einhaltung der Syntax im Auge behält. Das
"Denken" bleibt weiterhin den Programmierern überlassen,
da Maschinen dazu (immer noch nicht...) fähig sind.
Es geht hier nicht darum, ob der Compiler irgendwie im philosophischen
Sinne "denkt", sondern darum, welche Informationen ihm für seine
Aufgabe zur Verfügung stehen. Und dazu gehört natürlich, welche Register
eine CPU hat, und welche Instruktion auf welche Register lesend und
schreibend zugreift. Für eine Multiplikation kann er z.B. "mul reg"
verwenden, um das tun zu können, muss er "wissen", dass der zweite
Operand in EAX stehen muss und dass das Ergebnis nachher in EDX:EAX
steht. Sonst kann er keinen Code erzeugen, der diese Instruktion
verwendet. Oder jedenfalls keinen auch nur annähernd optimalen.

Diese Information kann implizit im Programmcode des Compilers abgelegt
sein, sehr oft ist sie aber explizit - insbesondere bei Compilern wie
dem GCC, die Code für eine breite Palette verschiedener Prozessoren
erzeugen können.
Post by Bernhard Schornak
Post by Peter J. Holzer
...ich nehme an, dass das Unix AMD64 ABI von AMD festgelegt wurden...
Wie sollte das gehen? Unixderivate, darunter Linux, sind
Produkte etlicher "global Player". Ein Zwerg wie AMD ist
sicher nicht in der Lage, den Industriegiganten ihre ABI
aufzudrängen.
Der Zwerg hat es auch geschafft, Intel seine ISA aufzudrängen, das finde
ich viel erstaunlicher, als dass ein Prozessorhersteller auch ein ABI
für seinen Prozessor festlegt.

Zur Frage wie das gehen soll: Einen Compiler zur Verfügung stellen. Wenn
der keine schwerwiegenden Mängel aufweist, werden den alle verwenden,
und damit ist das ABI defacto festgelegt. Im Nachhinein ändert man das
nicht mehr leicht, denn dann muss man ja kompatibel bleiben ...

AMD hat während der Entwicklung mit Microsoft und SuSE
zusammengearbeitet. Als der Prozessor auf den Markt kam, gab es sowohl
für Windows als auch für Linux funktionierende Compiler (und zumindest
im Fall von Linux sogar ein vollständig portiertes Betriebssystem).
Damit haben sie einfach Tatsachen geschaffen.

Interessant ist natürlich, dass die Calling-Conventions für Linux und
Windows doch recht deutlich voneinander abweichen. Das wird zum Teil
daran liegen, dass die von verschiedenen Teams festgelegt wurden (das
GCC-Team und das Microsoft-Team werden sicher nicht identisch gewesen
sein), zum Teil aber wahrscheinlich auch daran, dass der für die beiden
Betriebssysteme "typische" Code unterschiedlich war.

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Bernhard Schornak
2014-12-13 23:55:12 UTC
Permalink
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Jan Bruns
Ich kann Dir grad gar nicht genau sagen, was für eine calling
convention die Funktion verwendet.
Da RDI und RSI nicht gesichert werden, kann es sich nur um Linux
handeln.
Das ist ein Fehlschluss.
Ach?
Ja.
Post by Bernhard Schornak
Im Bereich x86-64 gibt es nur zwei ABIs. Das andere, von
Microsoft definierte ABI schreibt das Sichern der beiden
hier nicht gesicherten Register vor.
Nein. Das ABI schreibt vor, dass der Callee für das Sichern dieser
Register verantwortlich ist. Aber wenn der Callee diese Register nicht
ändert, muss er sie natürlich auch nirgends hin sichern. Wozu sollte das
gut sein? Da hier die beiden Register nicht geändert werden, ist die
Funktion mit dem Microsoft-ABI kompatibel.
Dann müsste es aber

cmpxchg %edx, (%rcx)

heissen, da laut Windows-ABI die ersten zwei Parameter in RCX
und RDX übergeben werden.

Wir könnten jetzt natürlich noch annehmen, dass der Verfasser
des Codes die Parameter direkt in den Registern übergibt, und
die Funktion ohne Parameter aufgerufen wird. Damit wäre diese
Funktion jedoch sowohl in 64 Bit Windows als auch Linux -nur-
von Assemblerfunktionen ansprechbar, da diese Parameter ja in
die zwei Register geschrieben werden müssten. Mit den Aufruf-
konventionen gängiger "Hochsprachen" wäre das nicht unbedingt
kompatibel. Assemblerprogrammierer benötigen auch keine Funk-
tionen, um die Ausführung eines einzelnen Assemblerbefehls in
einer "Hochsprache" zu ermöglichen...
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
Wenn der Sequenz von einem Compiler erzeugt wurde (ich halte es für
nicht unwahrscheinlich, dass die handgeschrieben ist), dann weiß er das
ziemlich sicher sehr wohl. Wie soll er denn Code erzeugen, wenn er nicht
weiß, was eine Instruktion macht?
Weil "er" nur den Code abarbeitet, den "sein" "Erzeuger"
(ein Applikationsprogrammierer wie Du oder ich) "ihm" in
die Wiege gelegt hat. Es ist sehr unwahrscheinlich, dass
ein Compiler Instruktionen und ihre Parameter auf -mehr-
als die Einhaltung des gültigen Wertebereichs hin prüft,
respektive die Einhaltung der Syntax im Auge behält. Das
"Denken" bleibt weiterhin den Programmierern überlassen,
da Maschinen dazu (immer noch nicht...) fähig sind.
Es geht hier nicht darum, ob der Compiler irgendwie im philosophischen
Sinne "denkt", sondern darum, welche Informationen ihm für seine
Aufgabe zur Verfügung stehen. Und dazu gehört natürlich, welche Register
eine CPU hat, und welche Instruktion auf welche Register lesend und
schreibend zugreift. Für eine Multiplikation kann er z.B. "mul reg"
verwenden, um das tun zu können, muss er "wissen", dass der zweite
Operand in EAX stehen muss und dass das Ergebnis nachher in EDX:EAX
steht. Sonst kann er keinen Code erzeugen, der diese Instruktion
verwendet. Oder jedenfalls keinen auch nur annähernd optimalen.
Du verwechselst die Überprüfung von Parametern oder ihrer An-
ordnung innerhalb des Befehls mit der Analyse des "Sinns oder
Zwecks" ganzer Befehlsfolgen (= Funktionen).
Post by Peter J. Holzer
Diese Information kann implizit im Programmcode des Compilers abgelegt
sein, sehr oft ist sie aber explizit - insbesondere bei Compilern wie
dem GCC, die Code für eine breite Palette verschiedener Prozessoren
erzeugen können.
Die Eigenheiten der Prozessoren sind in maschinenspezifischen
Dateien festgehalten. Ich habe früher immer die fehlenden Be-
fehle manuell dazugefügt und meinen "eigenen" GCC kompiliert,
das ist aber seit etlichen Jahren nicht mehr möglich, da nach
einigen Umstellungen alle Dateien so gut versteckt sind, dass
man sie nicht mehr findet.
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
...ich nehme an, dass das Unix AMD64 ABI von AMD festgelegt wurden...
Wie sollte das gehen? Unixderivate, darunter Linux, sind
Produkte etlicher "global Player". Ein Zwerg wie AMD ist
sicher nicht in der Lage, den Industriegiganten ihre ABI
aufzudrängen.
Der Zwerg hat es auch geschafft, Intel seine ISA aufzudrängen, das finde
ich viel erstaunlicher, als dass ein Prozessorhersteller auch ein ABI
für seinen Prozessor festlegt.
Okay. Ich hatte gelernt, dass ISA zusammen mit dem PC von IBM
eingeführt wurde. Offenbar hat AMD trotz geringem Marktanteil
die gesamte Computerindustrie fest in der Hand?
Post by Peter J. Holzer
Zur Frage wie das gehen soll: Einen Compiler zur Verfügung stellen. Wenn
der keine schwerwiegenden Mängel aufweist, werden den alle verwenden,
und damit ist das ABI defacto festgelegt. Im Nachhinein ändert man das
nicht mehr leicht, denn dann muss man ja kompatibel bleiben ...
Im Gegensatz zu iNTEL vertreibt AMD keinen eigenen Compiler -
was AMD bei gängigen Benchmarks laufend zu spüren bekommt...
Post by Peter J. Holzer
Interessant ist natürlich, dass die Calling-Conventions für Linux und
Windows doch recht deutlich voneinander abweichen. Das wird zum Teil
daran liegen, dass die von verschiedenen Teams festgelegt wurden (das
GCC-Team und das Microsoft-Team werden sicher nicht identisch gewesen
sein), zum Teil aber wahrscheinlich auch daran, dass der für die beiden
Betriebssysteme "typische" Code unterschiedlich war.
Es mag daran liegen, dass Windows als Stand-Alone-System kon-
zipiert war, während Linux als UNIX-Derivat für vernetzte Ar-
beitsplätze entwickelt wurde. Je nach Aufgabenstellung ergibt
sich ein recht unterschiedlicher Aufbau der Software, die das
bewerkstelligt.


Schönes Wochenende

Bernhard Schornak
Peter J. Holzer
2014-12-14 14:53:37 UTC
Permalink
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Da RDI und RSI nicht gesichert werden, kann es sich nur um Linux
handeln.
Das ist ein Fehlschluss.
Ach?
Ja.
Post by Bernhard Schornak
Im Bereich x86-64 gibt es nur zwei ABIs. Das andere, von
Microsoft definierte ABI schreibt das Sichern der beiden
hier nicht gesicherten Register vor.
Nein. Das ABI schreibt vor, dass der Callee für das Sichern dieser
Register verantwortlich ist. Aber wenn der Callee diese Register nicht
ändert, muss er sie natürlich auch nirgends hin sichern. Wozu sollte das
gut sein? Da hier die beiden Register nicht geändert werden, ist die
Funktion mit dem Microsoft-ABI kompatibel.
Dann müsste es aber
cmpxchg %edx, (%rcx)
heissen, da laut Windows-ABI die ersten zwei Parameter in RCX
und RDX übergeben werden.
Das ist ein Argument (%edi und %esi sind die beiden ersten
Integer-Parameter im Linux-ABI, das passt also ebenfalls zusammen).
Selbst die Syntax des (Dis-)Assemblers (GNU-Syntax, nicht MS-Syntax)
wäre ein Argument gewesen, wenn auch ein eher schwaches.

Aber aus der Tatsache, dass ein Register, das gar nicht geändert wird,
nicht gesichert wird, kannst Du eben keinen Schluss ziehen.
Diese Optimierung kann jeder Compiler durchführen, und ein menschlicher
Programmierer erst recht (ich hoffe sehr, dass Du in Deinem eigenen
Code, nicht Register völlig unnötig irgendwohin speicherst).

[Arbeitsweise eines Compilers]
Post by Bernhard Schornak
Du verwechselst die Überprüfung von Parametern oder ihrer An-
ordnung innerhalb des Befehls mit der Analyse des "Sinns oder
Zwecks" ganzer Befehlsfolgen (= Funktionen).
Nein. Aber gut, dass Du unten erwähnst, dass Du die Interna des GCC eh
kennst, so kann ich mir sparen, das zu erklären. Wie Deine zur Schau
gestellte Unkenntnis damit zusammenpasst, verstehe ich allerdings
nicht.
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
...ich nehme an, dass das Unix AMD64 ABI von AMD festgelegt wurden...
Wie sollte das gehen? Unixderivate, darunter Linux, sind
Produkte etlicher "global Player". Ein Zwerg wie AMD ist
sicher nicht in der Lage, den Industriegiganten ihre ABI
aufzudrängen.
Der Zwerg hat es auch geschafft, Intel seine ISA aufzudrängen, das finde
ich viel erstaunlicher, als dass ein Prozessorhersteller auch ein ABI
für seinen Prozessor festlegt.
Okay. Ich hatte gelernt, dass ISA zusammen mit dem PC von IBM
eingeführt wurde.
ISA = Instruction Set Architecture
nicht zu verwechseln mit
ISA = Industry Standard Architecture (dem AT-Bus)

Du solltest wirklich versuchen, sinnerfassend zu lesen. Wenn wir von
Prozessorarchitekturen reden, heißt CPI ganz sicher nicht "characters
per inch" und es ist auch eher unwahrscheinlich, dass mit ISA ein
damals schon recht veraltetes Bussystem gemeint ist.
Post by Bernhard Schornak
Offenbar hat AMD trotz geringem Marktanteil die gesamte
Computerindustrie fest in der Hand?
Quatsch. Aber Intel hat das 64-Bit Instruction Set eben von AMD
übernommen und seine eigene 64-Bit-Architektur praktisch aufgegeben.

Daran gibt es nichts herumzudeuteln. Dass Intel dann auch wieder
aufgeholt und heute auch bei 64-Bit-Prozessoren einen wesentlich
größeren Marktanteil als AMD hat, ist ebenso Tatsache. Aber die
Innovation kam von AMD.
Post by Bernhard Schornak
Post by Peter J. Holzer
Zur Frage wie das gehen soll: Einen Compiler zur Verfügung stellen. Wenn
der keine schwerwiegenden Mängel aufweist, werden den alle verwenden,
und damit ist das ABI defacto festgelegt. Im Nachhinein ändert man das
nicht mehr leicht, denn dann muss man ja kompatibel bleiben ...
Im Gegensatz zu iNTEL vertreibt AMD keinen eigenen Compiler -
was AMD bei gängigen Benchmarks laufend zu spüren bekommt...
Dafür haben sie eben mit SuSE und Microsoft zusammengearbeitet: SuSE hat
ein Backend für den GCC (C, C++, Fortran) erstellt, MS eines für Visual
C++. (Und natürlich war die Zusammenarbeit mit MS auch wichtig, weil sie
so den Source-Code für Windows bekommen haben: Wenn Du einen neuen
Prozessor entwickelst, dann willst Du die Betriebssysteme, die darauf
laufen sollen, compilieren können, *bevor* der Prozessor fertig ist.)

Der GCC für x86_64 erzeugt sicher schlechteren Code als der
Intel-Compiler. Aber er war *verfügbar*, bevor es den Prozessor
überhaupt gab. Und damit wurde das von dieser speziellen Portierung des
GCC vorgebene ABI eben zum Standard. Jedes davon abweichende ABI hätte
substanzielle Verbesserungen nachweisen müssen, um das bereits
etablierte noch ablösen zu können. Kompatibilität schlägt Performance.

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Bernhard Schornak
2014-12-14 19:12:21 UTC
Permalink
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
...ich nehme an, dass das Unix AMD64 ABI von AMD festgelegt wurden...
Wie sollte das gehen? Unixderivate, darunter Linux, sind
Produkte etlicher "global Player". Ein Zwerg wie AMD ist
sicher nicht in der Lage, den Industriegiganten ihre ABI
aufzudrängen.
Der Zwerg hat es auch geschafft, Intel seine ISA aufzudrängen, das finde
ich viel erstaunlicher, als dass ein Prozessorhersteller auch ein ABI
für seinen Prozessor festlegt.
Okay. Ich hatte gelernt, dass ISA zusammen mit dem PC von IBM
eingeführt wurde.
ISA = Instruction Set Architecture
nicht zu verwechseln mit
ISA = Industry Standard Architecture (dem AT-Bus)
Du solltest wirklich versuchen, sinnerfassend zu lesen. Wenn wir von
Prozessorarchitekturen reden, heißt CPI ganz sicher nicht "characters
per inch" und es ist auch eher unwahrscheinlich, dass mit ISA ein
damals schon recht veraltetes Bussystem gemeint ist.
Ich kann zwar bruchstückhafte Sätze interpolieren, um ihnen
einen Sinn abzuringen. Bei Abkürzungen, die für den grossen
Teil der Menschheit eine bekannte Bedeutung haben, die dann
von einer Minderheit neu definiert wird, sollte man bei der
Verwendung von alternativen Bedeutungen nicht darauf bauen,
dass anderen Lesern die neue(n) Definition(en) bekannt ist/
sind.

Wer im Bereich Computertechnik nach den von Dir verwendeten
Abkürzungen gurgelt, wird auf den ersten fünf Seiten keinen
einzigen Treffer mit den von Dir nachgereichten Bedeutungen
finden. Wenn Du schon selbstgestrickte Abkürzungen ins Feld
führst, solltest Du ihre Bedeutung zumindest bei der ersten
Verwendung in Klammern dazu schreiben.
Post by Peter J. Holzer
Post by Bernhard Schornak
Offenbar hat AMD trotz geringem Marktanteil die gesamte
Computerindustrie fest in der Hand?
Quatsch. Aber Intel hat das 64-Bit Instruction Set eben von AMD
übernommen und seine eigene 64-Bit-Architektur praktisch aufgegeben.
Dass IA64-Prozessoren nicht mehr auf dem Consumermarkt ver-
trieben werden, heisst nicht, dass iNTEL diese Familie ganz
aufgegeben hat. Sie wird in anderen Marktsegmenten durchaus
noch verwendet und meines Wissens immer noch produziert.


Grüsse aus Augsburg

Bernhard Schornak
Volker Birk
2014-12-14 19:43:44 UTC
Permalink
Post by Bernhard Schornak
ISA = Instruction Set Architecture […]
CPI
[…]
Wer im Bereich Computertechnik nach den von Dir verwendeten
Abkürzungen gurgelt, wird auf den ersten fünf Seiten keinen
einzigen Treffer mit den von Dir nachgereichten Bedeutungen
finden.
https://en.wikipedia.org/wiki/Instruction_set
https://en.wikipedia.org/wiki/Cycles_per_instruction

Was Peter hier referenziert, ist in dieser Gruppe on-topic.
Post by Bernhard Schornak
Aber Intel hat das 64-Bit Instruction Set eben von AMD
übernommen und seine eigene 64-Bit-Architektur praktisch aufgegeben.
Dass IA64-Prozessoren nicht mehr auf dem Consumermarkt ver-
trieben werden, heisst nicht, dass iNTEL diese Familie ganz
aufgegeben hat. Sie wird in anderen Marktsegmenten durchaus
noch verwendet und meines Wissens immer noch produziert.
Das ändert nichts an der Richtigkeit von Peters Ausführungen. In
letzter Zeit mal was von Kittson gehört? Nein? Ich auch nicht.

Viele Grüsse,
VB.
--
“Vor Snowden war das ein Blog mit Verschwörungstheorien.
Nach Snowden ist das ein Security-Newsticker.
Bei unverändertem Inhalt...”
Marc Stibane über Fefes Blog
Bernhard Schornak
2014-12-15 14:51:17 UTC
Permalink
Post by Volker Birk
Post by Bernhard Schornak
ISA = Instruction Set Architecture […]
CPI
[…]
Wer im Bereich Computertechnik nach den von Dir verwendeten
Abkürzungen gurgelt, wird auf den ersten fünf Seiten keinen
einzigen Treffer mit den von Dir nachgereichten Bedeutungen
finden.
https://en.wikipedia.org/wiki/Instruction_set
In der verlinkten deutschen Version des obigen Artikels

https://de.wikipedia.org/wiki/Befehlssatz

wird die Abkürzung ISA nirgendwo erwähnt. Auch dieser Artikel
Post by Volker Birk
https://en.wikipedia.org/wiki/Cycles_per_instruction
ist nur in einer englischen Version verfügbar. Ich sollte ihn
-möglicherweise- kennen, so lange ich in c.l.a.x86 oder a.l.a
diskutiere, im deutschsprachigen Raum sind diesen Abkürzungen
aber eindeutig den ursprünglichen Bedeutungen (wie von mir in
früheren Postings bereits ausgeführt) zugeordnet.
Post by Volker Birk
Was Peter hier referenziert, ist in dieser Gruppe on-topic.
-Das- stand auch niemals zur Debatte. Es ging ausschliesslich
um - ausschliesslich im englischsprachigen Raum - mehrdeutige
Abkürzungen. Im deutschsprachigen Raum haben ISA und CPI seit
je her die ursprüngliche Bedeutung, da sich die Mehrfachdefi-
nitionen nicht durchsetzen konnten. In Deutschland wären

BSA = BefehlsSatz-Architektur

und

TPB = Taktzyklen pro Befehl

unverwechselbare Abkürzungen, die anderweitig noch nicht ver-
wendet werden.
Post by Volker Birk
Post by Bernhard Schornak
Aber Intel hat das 64-Bit Instruction Set eben von AMD
übernommen und seine eigene 64-Bit-Architektur praktisch aufgegeben.
Dass IA64-Prozessoren nicht mehr auf dem Consumermarkt ver-
trieben werden, heisst nicht, dass iNTEL diese Familie ganz
aufgegeben hat. Sie wird in anderen Marktsegmenten durchaus
noch verwendet und meines Wissens immer noch produziert.
In letzter Zeit mal was von Kittson gehört?
Ja. Ich kenne durch Genealogierecherchen jemanden in Hallock,
mit dem ich kürzlich ein paar E-mails austauschte.


Grüsse aus Augsburg

Bernhard Schornak
Steffen Christgau
2014-12-15 22:12:18 UTC
Permalink
Post by Bernhard Schornak
Post by Volker Birk
Post by Bernhard Schornak
ISA = Instruction Set Architecture […]
CPI
[…]
Wer im Bereich Computertechnik nach den von Dir verwendeten
Abkürzungen gurgelt, wird auf den ersten fünf Seiten keinen
einzigen Treffer mit den von Dir nachgereichten Bedeutungen
finden.
https://en.wikipedia.org/wiki/Instruction_set
In der verlinkten deutschen Version des obigen Artikels
https://de.wikipedia.org/wiki/Befehlssatz
wird die Abkürzung ISA nirgendwo erwähnt.
<krümelk*ck>
Stimmt so nicht.

"Will man eine Familie von Prozessoren mit ähnlichem Befehlssatz
zusammenfassen, so spricht man auch von einer Befehlssatzarchitektur
(engl. Instruction Set Architecture, kurz: ISA). Verbreitete
Befehlssatzarchitekturen sind beispielsweise:

* IA-32 (oder auch x86 genannt)"

Die Versiongeschichte zeigt die letzte Änderung am 21. August diesen
Jahres.
</krümelk*ck>
Post by Bernhard Schornak
ist nur in einer englischen Version verfügbar. Ich sollte ihn
-möglicherweise- kennen, so lange ich in c.l.a.x86 oder a.l.a
diskutiere, im deutschsprachigen Raum sind diesen Abkürzungen
aber eindeutig den ursprünglichen Bedeutungen (wie von mir in
früheren Postings bereits ausgeführt) zugeordnet.
Auch wenn die Diskussion jetzt eher off-topic wird, muss ich Peter recht
geben. Wenn hier über die Prozessorinterna geschrieben wird, ist ISA für
mich selbsterklärung - und eben nicht der betagte Bus, um den es in der
gesamten Diskussion bisher auch nicht ging. Und CPI ist meinem Empfinden
nach auch geläufig und ist im Bereich der Rechnerarchitektur/Prozessoren
eben keine Einheit für die Zeichendichte...

Just my 0,02 EUR.

Gruß, Steffen
Bernhard Schornak
2014-12-16 16:48:39 UTC
Permalink
Post by Steffen Christgau
Auch wenn die Diskussion jetzt eher off-topic wird, muss ich Peter recht
geben. Wenn hier über die Prozessorinterna geschrieben wird, ist ISA für
mich selbsterklärung - und eben nicht der betagte Bus, um den es in der
gesamten Diskussion bisher auch nicht ging. Und CPI ist meinem Empfinden
nach auch geläufig und ist im Bereich der Rechnerarchitektur/Prozessoren
eben keine Einheit für die Zeichendichte...
Ich bin nicht gar so geizig und werfe Dir 'n ganzen Euro in'n
Hut:

Es liegt möglicherweise daran, dass unterschiedliche Menschen
unterschiedliche Interessen haben und dann die für ihr Inter-
essengebiet relevanten Publikationen lesen, die ihre eigenen,
interessenspezifischen Schlagwörter und Begriffe verwenden.

In wie weit diese "Insidersprache" sich dann im -allgemeinen-
Sprachgebrauch niederschlägt, hängt sicher davon ab, wie weit
sich ein spezifischer "Hype" unter die Leute bringen lässt.

Ich beschäftige mich hauptsächlich mit Funktionsbibliotheken,
die von den Befehlssätzen aktueller [x86-64]-Prozessoren rege
Gebrauch machen. Ich habe Begriffe wie "iNTEL-Architecture 32
(und 64) Bit" und "AMD-64" in meinen Sprachschatz aufgenommen
und kenne zumindest die fünf AMD-Handbücher für den Bulldozer
so gut, dass ich weiss, wo ich nachschlagen muss, um gesuchte
Informationen zu finden. Über ISA oder CPI bin ich aber weder
in den Publikationen von AMD noch von iNTEL gestossen - wobei
ich unterstelle, dass diese beiden Prozessorschmieden eigent-
lich die ersten sein müssten, die derlei Dinge publizieren...

Addendum:

Ich habe meine gesammelten Datenbücher gerade nach ISA durch-
sucht. Ausser in mISAligned und Ähnlichem ist diese Abkürzung
als eigenständiger Begriff nur im Zusammmenhang mit SIMD (all
das, was mit XMM/YMM/ZMM-Registern arbeitet) in Gebrauch. Für
den ursprünglichen Befehlssatz wird durchgehend IA32, x86 und
AMD64 verwendet, nur die "Legacy SIMD ISA" macht da eine Aus-
nahme...


Grüsse aus Augsburg

Bernhard Schornak
Steffen Christgau
2014-12-17 20:25:59 UTC
Permalink
Post by Bernhard Schornak
Es liegt möglicherweise daran, dass unterschiedliche Menschen
unterschiedliche Interessen haben und dann die für ihr Inter-
essengebiet relevanten Publikationen lesen, die ihre eigenen,
interessenspezifischen Schlagwörter und Begriffe verwenden.
Grundsätzlich geb ich dir recht, dass die verwendete Literatur natürlich
Einfluss auf den Sprachgebrauch hat. Vielleicht sind die
prozessorspezifischen Handbücher hier aber etwas zuuu
architektur/prozessorspezifisch als dass die beiden Begriffe darin öfter
auftauchen (müssten). Aber auch dort finden sich sowohl ISA (Software
Optimization Guide for AMD Family 15h
Processors, S. 38) als auch CPI (Intel 64 and IA-32 Architectures
Optimization Reference Manual, Abschnitt B.6.1). Ja, ich gebe zu, beides
nicht sehr oft, aber es gibt diese Begriffe - nicht nur in den Handbüchern.

Wenn man über die allgemeinere Sicht, die Grundlagen der
Rechnerarchitektur, einsteigt (was angesichts der Komplexität moderner
CPUs durchaus Sinn macht) oder sie sich später aneignet, wird man
schnell mit den genannten Begriffen (u.a.) konfrontiert. Im
Hennessy/Patterson: "Computer Architecture: A Quantitative Approach"
(IMO das Standardwerk auf dem Bereich der Rechnerarchitektur) kommen die
ziemlich weit vorne....
Post by Bernhard Schornak
In wie weit diese "Insidersprache" sich dann im -allgemeinen-
Sprachgebrauch niederschlägt, hängt sicher davon ab, wie weit
sich ein spezifischer "Hype" unter die Leute bringen lässt.
... von daher würde nicht von Hype sprechen. Und Insidersprache
verwenden wir hier auf unserer Assemblerinsel sowieso. Die einen mehr,
die anderen weniger ;-)

Steffen
Bernhard Schornak
2014-12-17 23:07:50 UTC
Permalink
Post by Steffen Christgau
Post by Bernhard Schornak
Es liegt möglicherweise daran, dass unterschiedliche Menschen
unterschiedliche Interessen haben und dann die für ihr Inter-
essengebiet relevanten Publikationen lesen, die ihre eigenen,
interessenspezifischen Schlagwörter und Begriffe verwenden.
Grundsätzlich geb ich dir recht, dass die verwendete Literatur natürlich
Einfluss auf den Sprachgebrauch hat. Vielleicht sind die
prozessorspezifischen Handbücher hier aber etwas zuuu
architektur/prozessorspezifisch als dass die beiden Begriffe darin öfter
auftauchen (müssten). Aber auch dort finden sich sowohl ISA (Software
Optimization Guide for AMD Family 15h
Processors, S. 38) als auch CPI (Intel 64 and IA-32 Architectures
Optimization Reference Manual, Abschnitt B.6.1). Ja, ich gebe zu, beides
nicht sehr oft, aber es gibt diese Begriffe - nicht nur in den Handbüchern.
Welche Ausgabe des AMD 47414 war das? In der aktuellen Version
3.08 vom Januar 2014 sehe ich alle möglichen Kürzel, aber kein
ISA http://tinyurl.com/lfmlywm - auch auf den Seiten davor und
danach nicht.

Intel spricht von Clocks Per Instructions Retired Ratio (CPI),
was nicht mit Befehlen pro Takt gleichzusetzen ist. Es ist ein
angenommenes Verhältnis, kein gemessener Wert.

Insgesamt sind mir AMDs Angaben sympathischer, da es reale (d.
h. nachmessbare) Werte sind.
Post by Steffen Christgau
Wenn man über die allgemeinere Sicht, die Grundlagen der
Rechnerarchitektur, einsteigt (was angesichts der Komplexität moderner
CPUs durchaus Sinn macht) oder sie sich später aneignet, wird man
schnell mit den genannten Begriffen (u.a.) konfrontiert. Im
Hennessy/Patterson: "Computer Architecture: A Quantitative Approach"
(IMO das Standardwerk auf dem Bereich der Rechnerarchitektur) kommen die
ziemlich weit vorne....
Das ist sicher ein (bekanntes?) Werk, das man beim Informatik-
studium zu lesen hat. Als Autodidakt baue ich eher auf eine in
mehr als dreissig Jahren erarbeitete Praxis mit Computern auf.
Die Spezialisierung auf x86 begann 1993, die auf x86-64 2009 -
nicht allzu lange her, aber ausreichend, damit warm zu werden.
Post by Steffen Christgau
Post by Bernhard Schornak
In wie weit diese "Insidersprache" sich dann im -allgemeinen-
Sprachgebrauch niederschlägt, hängt sicher davon ab, wie weit
sich ein spezifischer "Hype" unter die Leute bringen lässt.
... von daher würde nicht von Hype sprechen. Und Insidersprache
verwenden wir hier auf unserer Assemblerinsel sowieso. Die einen mehr,
die anderen weniger ;-)
In der Programmierung herrscht die englische Sprache vor - das
zu Leugnen wäre Blödsinn. Trotzdem versuche ich (im Rahmen der
Möglichkeiten) deutsche Begriffe zu verwenden, um das, was ich
zu sagen habe, einem möglichst breiten "Publikum" verständlich
zu machen. Ich schreibe zwar fast ebenso gut in englischer wie
in deutscher Sprache, empfände es aber als unhöflich, in einer
deuschsprachigen NG mit Anglizismen um mich zu werfen. Wenn es
sich gar nicht vermeiden lässt, schreibe ich demnach immer ein
paar erklärende Worte zu den Fachbegriffen, von denen ich ver-
mute, dass sie nicht jeder wissen muss.


Grüsse aus Augsburg

Bernhard Schornak
Steffen Christgau
2014-12-18 20:37:12 UTC
Permalink
Post by Bernhard Schornak
Post by Steffen Christgau
Post by Bernhard Schornak
Es liegt möglicherweise daran, dass unterschiedliche Menschen
unterschiedliche Interessen haben und dann die für ihr Inter-
essengebiet relevanten Publikationen lesen, die ihre eigenen,
interessenspezifischen Schlagwörter und Begriffe verwenden.
Grundsätzlich geb ich dir recht, dass die verwendete Literatur natürlich
Einfluss auf den Sprachgebrauch hat. Vielleicht sind die
prozessorspezifischen Handbücher hier aber etwas zuuu
architektur/prozessorspezifisch als dass die beiden Begriffe darin öfter
auftauchen (müssten). Aber auch dort finden sich sowohl ISA (Software
Optimization Guide for AMD Family 15h
Processors, S. 38) als auch CPI (Intel 64 and IA-32 Architectures
Optimization Reference Manual, Abschnitt B.6.1). Ja, ich gebe zu, beides
nicht sehr oft, aber es gibt diese Begriffe - nicht nur in den Handbüchern.
Welche Ausgabe des AMD 47414 war das? In der aktuellen Version
3.08 vom Januar 2014 sehe ich alle möglichen Kürzel, aber kein
ISA http://tinyurl.com/lfmlywm - auch auf den Seiten davor und
danach nicht.
Ah, sorry. Ich war noch bei 3.06.

In der 3.08 ist es aber auch drin, eine Seite später (S. 39, ziemlich
weit unten); http://support.amd.com/TechDocs/47414_15h_sw_opt_guide.pdf
Post by Bernhard Schornak
Intel spricht von Clocks Per Instructions Retired Ratio (CPI),
was nicht mit Befehlen pro Takt gleichzusetzen ist.
"Befehle pro Takt" sind "Instructions per Cycle", oder kurz IPC. Klar
ist das nicht gleichzusetzen mit "Clocks [oder Cycles] per Instructions"
bzw. CPI. Hab ich auch nicht getan. Das eine ist das Reziproke vom
anderen. Mir gehts hier nur um die vermeintlich unbekannten
Begrifflichkeiten bzw. Abkürzungen.
Post by Bernhard Schornak
Es [CPI] ist ein angenommenes Verhältnis, kein gemessener Wert.
Mh, aber Intel beschreibt doch in dem angegebenen Werk an der
angegebenen Stelle (s.o), wie CPI zu messen sind: Mit Hilfe von zwei
Hardware-Countern. Da sehe ich ehrlich gesagt nicht, wie das ein
"angenommenes Verhältnis" sein kann.
Post by Bernhard Schornak
Post by Steffen Christgau
Wenn man über die allgemeinere Sicht, die Grundlagen der
Rechnerarchitektur, einsteigt (was angesichts der Komplexität moderner
CPUs durchaus Sinn macht) oder sie sich später aneignet, wird man
schnell mit den genannten Begriffen (u.a.) konfrontiert. Im
Hennessy/Patterson: "Computer Architecture: A Quantitative Approach"
(IMO das Standardwerk auf dem Bereich der Rechnerarchitektur) kommen die
ziemlich weit vorne....
Das ist sicher ein (bekanntes?) Werk, das man beim Informatik-
studium zu lesen hat.
Ja, ist es. Wenn man im Studium was zur Rechnerarchitektur gehört, dann
wird man mit großer Wahrscheinlichkeit auch von oder aus diesem Buch
gehört haben...
Post by Bernhard Schornak
Als Autodidakt baue ich eher auf eine in
mehr als dreissig Jahren erarbeitete Praxis mit Computern auf.
Die Spezialisierung auf x86 begann 1993, die auf x86-64 2009 -
nicht allzu lange her, aber ausreichend, damit warm zu werden.
Sicher. Will ich dir auch nichts absprechen. Aber CPI und ISA als
unbekannte (oder unübliche) Begriffe darzustellen, wollte ich so nicht
stehen lassen.

Gruß, Steffen
Bernhard Schornak
2014-12-19 15:32:50 UTC
Permalink
Post by Steffen Christgau
Post by Bernhard Schornak
Post by Steffen Christgau
Post by Bernhard Schornak
Es liegt möglicherweise daran, dass unterschiedliche Menschen
unterschiedliche Interessen haben und dann die für ihr Inter-
essengebiet relevanten Publikationen lesen, die ihre eigenen,
interessenspezifischen Schlagwörter und Begriffe verwenden.
Grundsätzlich geb ich dir recht, dass die verwendete Literatur natürlich
Einfluss auf den Sprachgebrauch hat. Vielleicht sind die
prozessorspezifischen Handbücher hier aber etwas zuuu
architektur/prozessorspezifisch als dass die beiden Begriffe darin öfter
auftauchen (müssten). Aber auch dort finden sich sowohl ISA (Software
Optimization Guide for AMD Family 15h
Processors, S. 38) als auch CPI (Intel 64 and IA-32 Architectures
Optimization Reference Manual, Abschnitt B.6.1). Ja, ich gebe zu, beides
nicht sehr oft, aber es gibt diese Begriffe - nicht nur in den Handbüchern.
Welche Ausgabe des AMD 47414 war das? In der aktuellen Version
3.08 vom Januar 2014 sehe ich alle möglichen Kürzel, aber kein
ISA http://tinyurl.com/lfmlywm - auch auf den Seiten davor und
danach nicht.
Ah, sorry. Ich war noch bei 3.06.
In der 3.08 ist es aber auch drin, eine Seite später (S. 39, ziemlich
weit unten); http://support.amd.com/TechDocs/47414_15h_sw_opt_guide.pdf
Der Absatz ganz unten bezieht sich (wie bei iNTEL) auf 128 und
256 Bit breite "Media Register" (XMM/YMM). Das Bulldozerdesign
fass ja die beiden 128 Bit breiten FPUs der beiden Kerne einer
Einheit/Unit bei AVX-Befehlen zu einer 256 Bit breiten Einheit
zusammen, weshalb in Taktzyklen mit AVX-Befehlen nur einer der
beiden Kerne über die FPU verfügen kann. Dieses "Nadelöhr" ist
neben dem gemeinsamen Befehlsdekoder wohl die grösste Schwach-
stelle des Bulldozerdesigns...
Post by Steffen Christgau
Post by Bernhard Schornak
Intel spricht von Clocks Per Instructions Retired Ratio (CPI),
was nicht mit Befehlen pro Takt gleichzusetzen ist.
"Befehle pro Takt" sind "Instructions per Cycle", oder kurz IPC. Klar
ist das nicht gleichzusetzen mit "Clocks [oder Cycles] per Instructions"
bzw. CPI. Hab ich auch nicht getan. Das eine ist das Reziproke vom
anderen. Mir gehts hier nur um die vermeintlich unbekannten
Begrifflichkeiten bzw. Abkürzungen.
Es ist nicht das Reziproke: "Cycles Per Instruction" (CPI) be-
ziehen sich auf eine einzelne Executionpipe, "Instructions per
Cycle" auf die Gesamtheit der Executionpipes (Integer + FP) in
einem einzelnen Kern. Das eine ist auch als "Latenz"(zeit) be-
kannt, da andere als "(maximaler) Befehlsdurchsatz".

Wichtig ist in unserem Disput ja nur, dass Intel die Abkürzung
CPI für "Clocks Per Instructions Retired Ratio", nicht "Clocks
per Instruction" verwendet. Die Mehrzahl "Instructions" ergibt
im Englischen nur in Zusammenhang mit Retired einen Sinn - an-
sonsten wäre das "Clocks Per Instructions" nicht viel mehr als
extrem schlechtes, mit Valentins Semmelnknödeln vergleichbares
Englisch.
Post by Steffen Christgau
Post by Bernhard Schornak
Es [CPI] ist ein angenommenes Verhältnis, kein gemessener Wert.
Mh, aber Intel beschreibt doch in dem angegebenen Werk an der
angegebenen Stelle (s.o), wie CPI zu messen sind: Mit Hilfe von zwei
Hardware-Countern. Da sehe ich ehrlich gesagt nicht, wie das ein
"angenommenes Verhältnis" sein kann.
B-51, unten:

"1. Clocks Per Instruction Retired Ratio (CPI):
CPU_CLK_UNHALTED.CORE / INST_RETIRED.ANY.

The Intel Core microarchitecture is capable of reaching CPI
as low as 0.25 in ideal situations. But most of the code has
higher CPI The greater value of CPI for a given workload
indicate it has more opportunity for code tuning to improve
performance. The CPI is an overall metric, it does not
provide specificity of what microarchitectural sub-system
may be contributing to a high CPI value."

Wenn man die beiden Seiten liest, sollte einem eigentlich klar
sein, dass die angegebenen Formeln nur für grobe "Schätzungen"
taugen. Messen kann man keines der auf B-51/B-52 aufgelisteten
Verhältnisse. Wie willst Du z.B. RESOURCE_STALLS.RS_FULL genau
bestimmen, um es dann in die Formel einsetzen zu können? iNTEL
kann den Wert in einem Kern-Simulator wohl bestimmen, dem ein-
fachen Anwendungsprogrammierer steht diese Möglichkeit nun mal
nicht zur Verfügung. (Ob man eigens dafür angelegten MSRs über
den Weg trauen kann, sei dahingestellt.)
Post by Steffen Christgau
Post by Bernhard Schornak
Post by Steffen Christgau
Wenn man über die allgemeinere Sicht, die Grundlagen der
Rechnerarchitektur, einsteigt (was angesichts der Komplexität moderner
CPUs durchaus Sinn macht) oder sie sich später aneignet, wird man
schnell mit den genannten Begriffen (u.a.) konfrontiert. Im
Hennessy/Patterson: "Computer Architecture: A Quantitative Approach"
(IMO das Standardwerk auf dem Bereich der Rechnerarchitektur) kommen die
ziemlich weit vorne....
Das ist sicher ein (bekanntes?) Werk, das man beim Informatik-
studium zu lesen hat.
Ja, ist es. Wenn man im Studium was zur Rechnerarchitektur gehört, dann
wird man mit großer Wahrscheinlichkeit auch von oder aus diesem Buch
gehört haben...
Okay - ich bin auf x86-64 spezialisiert, daher beschäftige ich
mich nur rudimentär (und dann nur mit offen zugänglichen Doku-
menten) über andere Prozessordesigns. Als Hobby-Programmierer/
-Elektroniker muss ich auch nicht alles auswendig wissen...
Post by Steffen Christgau
Post by Bernhard Schornak
Als Autodidakt baue ich eher auf eine in
mehr als dreissig Jahren erarbeitete Praxis mit Computern auf.
Die Spezialisierung auf x86 begann 1993, die auf x86-64 2009 -
nicht allzu lange her, aber ausreichend, damit warm zu werden.
Sicher. Will ich dir auch nichts absprechen. Aber CPI und ISA als
unbekannte (oder unübliche) Begriffe darzustellen, wollte ich so nicht
stehen lassen.
Ich beharre nicht aus purer Sturheit auf Diesem und Jenem, und
bin mit guten Argumenten jederzeit zu überzeugen. Bei mehrfach
belegten Begriffen ist letzteres ein wenig schwieriger als bei
Allerweltsbegriffen. ;)


Schönes Wochenende!

Bernhard Schornak
Peter J. Holzer
2014-12-20 13:59:00 UTC
Permalink
Post by Bernhard Schornak
Wenn man die beiden Seiten liest, sollte einem eigentlich klar
sein, dass die angegebenen Formeln nur für grobe "Schätzungen"
taugen. Messen kann man keines der auf B-51/B-52 aufgelisteten
Verhältnisse. Wie willst Du z.B. RESOURCE_STALLS.RS_FULL genau
bestimmen, um es dann in die Formel einsetzen zu können?
Das ist ein Counter in der CPU, den kannst Du mit

RDPMC—Read Performance-Monitoring Counters

auslesen.

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Bernhard Schornak
2014-12-20 18:01:01 UTC
Permalink
Post by Peter J. Holzer
Post by Bernhard Schornak
Wenn man die beiden Seiten liest, sollte einem eigentlich klar
sein, dass die angegebenen Formeln nur für grobe "Schätzungen"
taugen. Messen kann man keines der auf B-51/B-52 aufgelisteten
Verhältnisse. Wie willst Du z.B. RESOURCE_STALLS.RS_FULL genau
bestimmen, um es dann in die Formel einsetzen zu können?
Das ist ein Counter in der CPU, den kannst Du mit
RDPMC—Read Performance-Monitoring Counters
auslesen.
Danke!


Schönes Wochenende

Bernhard Schornak
Jan Bruns
2014-12-08 08:14:09 UTC
Permalink
Post by Bernhard Schornak
Post by Jan Bruns
Angenehm wäre mir allerdings, wenn sich dieses unerwartete LOCK CMPXCHG
Verhalten (so es nicht an irgendwelchen sonstigen Fehlern lag)
aufklären täte. Ich könnte ja problemlos damit leben, da eben falsche
Erwartungen gehabt zu haben, nur wo, das wäre dann schon interessant.
Hat mich immerhin schon einige Stunden gekostet, mir dieses
compare-and-swap basierte System auszudenken.
http://wiki.osdev.org/Spinlock
Die Idee hinter dem ganzen ist aber doch gerade, Spinlocks im
Userland zu vermdeiden: Fordert ein AP Zugriff auf ein besetztes
Objekt, dann ist völlig unklar, wie lange es noch dauern wird, bis
das Objekt wieder frei ist, und es bedarf der Hilfe des Betriebs-
systems, den Rest der gerade laufenden Time-slice idealerweise auf
den Thread zu verlagern, der das Objekt gerade belegt, oder
wenigstens sonst irgendwie was sinnvolles zu machen.

Ich habe in meinem Code (im nicht gezeigten Teil) ist eine Stelle,
in der anfangs noch ein Spinlock war. Das war an der Stelle, wo
uunlockObj() das Objekt an einen anderen AP weitergibt, dazu aber
erstmal die waitchain sperren muss. Die kann durch einen sich gerade
einklinkenden AP, der das Objekt auch noch haben will, für einen
normalerweise ganz kurzen Moment Zugriffsgeschützt sein. Dieser
kurze Moment kann aber effektiv sehr lang werden, wenn man im
Vergleich zur Anzahl an CPUs viele aktive Threads hat, und der
sich einklingenden Thread im falschen Moment unterbrochen wurde.
Daher mache ich selbst dort nur ganz wenige nackte spinlock loops,
dann einige Durchläufe mit ThreadSwitch()-Versuch, und letzlich
weiter mit (unzuverlässigem) Signalwarten.

Die hier gezeigten loops laufen jedenfalls nur ganz selten mal
eine zweite Runde, obwohl in lockObj() eigentlich auch sowas
passieren kann, wie im vorigen Absatz beschrieben.

Gruss

Jan Bruns
Bernhard Schornak
2014-12-08 15:57:41 UTC
Permalink
Post by Jan Bruns
Post by Bernhard Schornak
Post by Jan Bruns
Angenehm wäre mir allerdings, wenn sich dieses unerwartete LOCK CMPXCHG
Verhalten (so es nicht an irgendwelchen sonstigen Fehlern lag)
aufklären täte. Ich könnte ja problemlos damit leben, da eben falsche
Erwartungen gehabt zu haben, nur wo, das wäre dann schon interessant.
Hat mich immerhin schon einige Stunden gekostet, mir dieses
compare-and-swap basierte System auszudenken.
http://wiki.osdev.org/Spinlock
Die Idee hinter dem ganzen ist aber doch gerade, Spinlocks im
Userland zu vermdeiden: Fordert ein AP Zugriff auf ein besetztes
Objekt, dann ist völlig unklar, wie lange es noch dauern wird, bis
das Objekt wieder frei ist, und es bedarf der Hilfe des Betriebs-
systems, den Rest der gerade laufenden Time-slice idealerweise auf
den Thread zu verlagern, der das Objekt gerade belegt, oder
wenigstens sonst irgendwie was sinnvolles zu machen.
Ich habe in meinem Code (im nicht gezeigten Teil) ist eine Stelle,
in der anfangs noch ein Spinlock war. Das war an der Stelle, wo
uunlockObj() das Objekt an einen anderen AP weitergibt, dazu aber
erstmal die waitchain sperren muss. Die kann durch einen sich gerade
einklinkenden AP, der das Objekt auch noch haben will, für einen
normalerweise ganz kurzen Moment Zugriffsgeschützt sein. Dieser
kurze Moment kann aber effektiv sehr lang werden, wenn man im
Vergleich zur Anzahl an CPUs viele aktive Threads hat, und der
sich einklingenden Thread im falschen Moment unterbrochen wurde.
Daher mache ich selbst dort nur ganz wenige nackte spinlock loops,
dann einige Durchläufe mit ThreadSwitch()-Versuch, und letzlich
weiter mit (unzuverlässigem) Signalwarten.
Die hier gezeigten loops laufen jedenfalls nur ganz selten mal
eine zweite Runde, obwohl in lockObj() eigentlich auch sowas
passieren kann, wie im vorigen Absatz beschrieben.
Wie Du aus dem vorhergehenden Reply entnomen haben solltest, kann
ich als Assemblerprogrammierer (ich verwende keine Hochsprachen!)
nur dann helfen, wenn ich Assemblercode (AT&T oder iNTEL) vor mir
habe. Erst dann kann ich nachvollziehen, was beim Ausführen einer
Funktion auf einem bestimmten Kern passiert und wie sich das dann
auf andere Kerne/Prozessoren auswirken könnte.

Auf Maschinenebene gibt es nur abzuarbeitende Befehle und Daten -
Konstrukte wie Objekte und Threads existieren -nur- in den Köpfen
der Hochsprachenprogrammierer. Während die Maschine nur eine sehr
komplexe Abfolge privilegierter Befehle abarbeitetet, "sieht" der
Hochsprachenprogrammierer hier Threads und Objekte, die kaum mehr
als abstrakte, von der aktuell verwendeten -Hardware- vollständig
losgelöste Gedankenspiele sind.

Es ist müssig, in einer Assembler-NG über hochsprachenspezifische
Probleme zu klagen, ohne eine Zeile Assemblercode vorzulegen, die
das Fehlverhalten der Hochsprache aufzeigen könnte. Der gepostete
Ausschnitt ist sicher nicht die Ursache des Fehlverhaltens - dazu
müsste man schon ein wenig mehr davon sehen, was der Compiler aus
Deinem Code generiert hat. Mit GCCs "-s"-Option lässt sich jeder-
zeit die an AS übergebene Assemblerdatei ausgeben. Vielleicht ist
dann jemand in der Lage, Dir -hier- weiterzuhelfen.


Grüsse aus Augsburg

Bernhard Schornak
Peter J. Holzer
2014-12-06 07:32:26 UTC
Permalink
Post by Bernhard Schornak
Wer verwendet schon freiwillig CMPXCHG?
Leute, die Locking-Primitives schreiben?
Post by Bernhard Schornak
In derselben Zeit können parallel (abhängig von der Zahl der Pipes)
mehrere MOV-CMP-MOV-Operationen ausgeführt werden.
Damit bekommst Du ein race-condition-freies Locking-Primitive hin?

Ich will nicht ausschließen, dass das theoretisch möglich ist, aber ich
glaube doch, dass sich die Intel-Leute was dabei gedacht haben, als sie
(mit dem 486er?) CMPXCHG eingeführt haben.

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Bernhard Schornak
2014-12-06 11:14:12 UTC
Permalink
Post by Peter J. Holzer
Post by Bernhard Schornak
Wer verwendet schon freiwillig CMPXCHG?
Leute, die Locking-Primitives schreiben?
Das hat zwar mit Assembler rein gar nix zu tun, aber trotzdem:

http://locklessinc.com/articles/locks/
Post by Peter J. Holzer
Post by Bernhard Schornak
In derselben Zeit können parallel (abhängig von der Zahl der Pipes)
mehrere MOV-CMP-MOV-Operationen ausgeführt werden.
Damit bekommst Du ein race-condition-freies Locking-Primitive hin?
Wahrscheinlich nicht. Wer viel will, muss viel dafür tun (oder
an der Börse zocken) - ein paar zusätzliche Befehle braucht es
sicher, um das zu realisieren.
Post by Peter J. Holzer
Ich will nicht ausschließen, dass das theoretisch möglich ist, aber ich
glaube doch, dass sich die Intel-Leute was dabei gedacht haben, als sie
(mit dem 486er?) CMPXCHG eingeführt haben.
http://en.wikipedia.org/wiki/Compare-and-swap

Seit wann -denken- iNTEL-Mitarbeiter denn? ;)


Grüsse aus Augsburg

Bernhard Schornak
Peter J. Holzer
2014-12-08 01:45:05 UTC
Permalink
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Wer verwendet schon freiwillig CMPXCHG?
Leute, die Locking-Primitives schreiben?
Das hat zwar mit Assembler rein gar nix zu tun,
Letztendlich muss es in Assembler implemetiert werden. Entweder in einer
Library oder durch den Compiler.
Post by Bernhard Schornak
http://locklessinc.com/articles/locks/
| Unfortunately, we will require a few others that are not,
[ provided by gcc ]
| and so must be implemented in assembly

Da steht's ja.

XCHG macht übrigens ein implizites LOCK, dürfte also nicht wesentlich
billiger sein als ein LOCK CMPXCHG.
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
In derselben Zeit können parallel (abhängig von der Zahl der Pipes)
mehrere MOV-CMP-MOV-Operationen ausgeführt werden.
Damit bekommst Du ein race-condition-freies Locking-Primitive hin?
Wahrscheinlich nicht.
Eben.
Post by Bernhard Schornak
Wer viel will, muss viel dafür tun (oder an der Börse zocken) - ein
paar zusätzliche Befehle braucht es sicher, um das zu realisieren.
Mit "ein paar zusätzlichen Befehlen" werden Race-Conditions meistens
nicht besser.
Post by Bernhard Schornak
Post by Peter J. Holzer
Ich will nicht ausschließen, dass das theoretisch möglich ist, aber ich
glaube doch, dass sich die Intel-Leute was dabei gedacht haben, als sie
(mit dem 486er?) CMPXCHG eingeführt haben.
http://en.wikipedia.org/wiki/Compare-and-swap
| In the x86 (since 80486) and Itanium architectures this is implemented
| as the compare and exchange (CMPXCHG) instruction, though here the
| LOCK prefix should be there to make it really atomic.

Wo ist da der Widerspruch?

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Bernhard Schornak
2014-12-08 15:59:17 UTC
Permalink
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Wer verwendet schon freiwillig CMPXCHG?
Leute, die Locking-Primitives schreiben?
Das hat zwar mit Assembler rein gar nix zu tun,
Letztendlich muss es in Assembler implemetiert werden. Entweder in einer
Library oder durch den Compiler.
Ja - mit der Kompetenz von HLL-Compilerbauern... ;)
Post by Peter J. Holzer
XCHG macht übrigens ein implizites LOCK, dürfte also nicht wesentlich
billiger sein als ein LOCK CMPXCHG.
AMD : 5 Takte FP-Double statt 6/7 Takte Complex
iNTEL: 1.5 (???) statt 5 Takte

Wobei iNTEL's Angaben (mit viertel, drittel und halben Takten)
mit äusserster Vorsicht zu geniessen sind.
Post by Peter J. Holzer
Post by Bernhard Schornak
Wer viel will, muss viel dafür tun (oder an der Börse zocken) - ein
paar zusätzliche Befehle braucht es sicher, um das zu realisieren.
Mit "ein paar zusätzlichen Befehlen" werden Race-Conditions meistens
nicht besser.
Je mehr Code, desto grösser die Verzögerung. Reicht meist aus,
die Schreibarbeit eines anderen Kerns zu "verstecken". Es gibt
aber auch die Möglichkeit, Aufgaben so aufzuteilen, dass jeder
Thread sich mit einem Teil des Speichers beschäftigt, den kein
anderer Thread in absehbarer Zukunft antasten wird. Das dürfte
die Abarbeitung um den Faktor zehn oder mehr beschleunigen.
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
Ich will nicht ausschließen, dass das theoretisch möglich ist, aber ich
glaube doch, dass sich die Intel-Leute was dabei gedacht haben, als sie
(mit dem 486er?) CMPXCHG eingeführt haben.
http://en.wikipedia.org/wiki/Compare-and-swap
| In the x86 (since 80486) and Itanium architectures this is implemented
| as the compare and exchange (CMPXCHG) instruction, though here the
| LOCK prefix should be there to make it really atomic.
Wo ist da der Widerspruch?
Welcher Widerspruch in Relation zu was? Wer daran glaubt, dass
eine Ausführungseinheit (Execution Pipe) in -einem- Taktzyklus
-bis zu vier- Befehle ausgeführt werden können (das heisst: Es
werden 4 Ergebnisse pro Takt geliefert!), der hat Physik durch
Religion ersetzt. Religion fordert Glauben statt Denken - ergo
können die iNTELianer (wie alle guten Bewohner der USA!) nicht
denken... ;)


Grüsse aus Augsburg

Bernhard Schornak
Jan Bruns
2014-12-09 02:49:44 UTC
Permalink
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
http://en.wikipedia.org/wiki/Compare-and-swap
Wo ist da der Widerspruch?
Welcher Widerspruch in Relation zu was?
Du hattest gewitzelt, daß man sich bei intel selbst
möglicherweise nur wenig Gedanken über die Vorteile von CAS
gemacht haben könnte, da "die Wissenschaft" das zuvor schon
theoretisiert hatte.
Post by Bernhard Schornak
Wer daran glaubt, dass eine
Ausführungseinheit (Execution Pipe) in -einem- Taktzyklus -bis zu vier-
Befehle ausgeführt werden können (das heisst: Es werden 4 Ergebnisse pro
Takt geliefert!), der hat Physik durch Religion ersetzt. Religion
fordert Glauben statt Denken - ergo können die iNTELianer (wie alle
guten Bewohner der USA!) nicht denken... ;)
Das ist aber so, solange die Befehle unabhängig
voneinander sind.

Ein ganz zentrales Bauteil, das man dazu braucht,
und das, glaube ich, sehr schön geeignet ist,
wenigstens eine grobe Vorstellung von den Abläufen
zu entwickeln, ist das Mehrport-RAM.

Nehmen wir z.B. an, wir wollten für die Register
eines IA-32 Systems so ein Bauteil haben. Es mag
etwas übertrieben erscheinen, aber fordern wir
doch einfach, daß 4 x86-Befehle ohne Einschränkungen
(abgesehen von der Abhängigkeit der Befehle von
vorigen) gleichzeitig ausgeführt werden können sollen.

Dazu bräuchten wir so im Prinzip ein 12-Port RAM, mit
8 Leseports (4 x86 Befehle könen je 2 Quelloperanden
haben), sowie 4 unabhägige Schreibports, um die
Ergebnisse des vorigen, oder irgendwie noch schöner:
des gleichen Taktes loszuwerden.

Ein solches Bauteil kann man durchaus herstellen:

Man nimmt z.B. für jedes zu implementierende
Registerbit ein einzelnes FlipFlop. Daran kann man
beliebig viele Leseports anschliessen, indem man
die Leseports als MUX-Schaltungen (d.h. one of n)
ausführt, in diesem Fall also, da IA32 nur 8 Register
hat, eine MUX8-Schaltung pro Bit eines Leseports.
Für die 4 Schreibports kann man vor den Dateineingang
eines jeden FlipFlops eine MUX4-Schaltung zur Auswahl
des für dieses Bit zu verwendenden Schreibports
schalten. Weiters das Write-Enable des FlipFlops
beschalten.

Somit haben wir ein letzlich eigentlich ganz
einfaches Teil, an das wir 4 ALUs anschliessen
können, die alle ganz wunderbar gleichzeitig
im selben Takt rechnen können, und unabhängig
voneinander all ihre Ergebnisse wieder zurück
ins Registerfile schreiben können.

Das alles dann so zu koordinieren daß letzlich
nur ein einzelner Befehlsstrom abgearbeitet wird,
ist natürlich kompliziert, aber eben nur in dem
Sinne, daß unsäglich viele Details zu beachten
sind.

Gruss

Jan Bruns
Bernhard Schornak
2014-12-09 14:53:58 UTC
Permalink
Post by Jan Bruns
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
http://en.wikipedia.org/wiki/Compare-and-swap
Wo ist da der Widerspruch?
Welcher Widerspruch in Relation zu was?
Du hattest gewitzelt, daß man sich bei intel selbst
möglicherweise nur wenig Gedanken über die Vorteile von CAS
gemacht haben könnte, da "die Wissenschaft" das zuvor schon
theoretisiert hatte.
Das ist mir neu. Wo genau soll das gewesen sein? Ich traue dem
Monopolisten iNTEL zwar zu, mit unlauteren Mitteln weit unter-
halb der Gürtellinie auf dem Markt zu agieren, man sollte aber
fair bleiben, und iNTEL zugestehen, viele Technologien selbst,
respektive vorhandene Technologien weiterentwickelt zu haben.

"Die Wissenschaft" ist ein schwammiger Begriff, der auf keinen
Fall aus meiner Feder stammt.
Post by Jan Bruns
Post by Bernhard Schornak
Wer daran glaubt, dass eine
Ausführungseinheit (Execution Pipe) in -einem- Taktzyklus -bis zu vier-
Befehle ausgeführt werden können (das heisst: Es werden 4 Ergebnisse pro
Takt geliefert!), der hat Physik durch Religion ersetzt. Religion
fordert Glauben statt Denken - ergo können die iNTELianer (wie alle
guten Bewohner der USA!) nicht denken... ;)
Das ist aber so, solange die Befehle unabhängig
voneinander sind.
Ein ganz zentrales Bauteil, das man dazu braucht,
und das, glaube ich, sehr schön geeignet ist,
wenigstens eine grobe Vorstellung von den Abläufen
zu entwickeln, ist das Mehrport-RAM.
Nehmen wir z.B. an, wir wollten für die Register
eines IA-32 Systems so ein Bauteil haben. Es mag
etwas übertrieben erscheinen, aber fordern wir
doch einfach, daß 4 x86-Befehle ohne Einschränkungen
(abgesehen von der Abhängigkeit der Befehle von
vorigen) gleichzeitig ausgeführt werden können sollen.
Dazu bräuchten wir so im Prinzip ein 12-Port RAM, mit
8 Leseports (4 x86 Befehle könen je 2 Quelloperanden
haben), sowie 4 unabhägige Schreibports, um die
des gleichen Taktes loszuwerden.
Man nimmt z.B. für jedes zu implementierende
Registerbit ein einzelnes FlipFlop. Daran kann man
beliebig viele Leseports anschliessen, indem man
die Leseports als MUX-Schaltungen (d.h. one of n)
ausführt, in diesem Fall also, da IA32 nur 8 Register
hat, eine MUX8-Schaltung pro Bit eines Leseports.
Für die 4 Schreibports kann man vor den Dateineingang
eines jeden FlipFlops eine MUX4-Schaltung zur Auswahl
des für dieses Bit zu verwendenden Schreibports
schalten. Weiters das Write-Enable des FlipFlops
beschalten.
Somit haben wir ein letzlich eigentlich ganz
einfaches Teil, an das wir 4 ALUs anschliessen
können, die alle ganz wunderbar gleichzeitig
im selben Takt rechnen können, und unabhängig
voneinander all ihre Ergebnisse wieder zurück
ins Registerfile schreiben können.
Das alles dann so zu koordinieren daß letzlich
nur ein einzelner Befehlsstrom abgearbeitet wird,
ist natürlich kompliziert, aber eben nur in dem
Sinne, daß unsäglich viele Details zu beachten
sind.
Das hört sich erst einmal so schlüssig an, dass ich mich etwas
gründlicher damit beschäftigen werde. Dagegen spricht, dass es
seit etlichen Prozessorgenerationen nicht mehr die 8 (oder 16)
bekannten Register rAX, rBX, et cetera gibt, sondern ein paar-
hundert Scratch-Register, denen je nach Bedarf einer der Namen
rAX, rBX, et cetera zugewiesen wird. Es wäre durchaus möglich,
jedes dieser Register mit multiplen I/O-Ports auszurüsten, die
gelegentlich sicher einmal genutzt würden. Die dafür benötigte
Verwaltung dürfte andererseits so komplex werden, dass sie auf
keinen Chip mehr passt. Zudem ergäbe sich das Problem, dass es
bei vier in einem einzigen Takt innerhalb einer einzelnen Pipe
abgearbeiteten Befehlen auch vier Datenbusse die 256 I/O-Ports
in einem Takt mit Daten versorgen müssten, was die (maximal 3)
von iNTEL bereit gestellten 64 Bit breiten Datenpfade zwischen
Prozessor und Hauptspeicher (maximal 192 Bit) nicht zulassen.

Abgesehen davon müsste auch der Befehlsdecoder nicht nur eine,
sondern vier Einheiten pro Pipe mit Befehlen versorgen. Insge-
samt bleiben da mehr offene Fragen über, als zuvor beantwortet
wurden. Zudem erklärt das leider noch nicht, wie ein Befehl in
0,33 oder 0,66 Taktzyklen abgearbeitet werden könnte, drei ist
schliesslich keine Zweierpotenz.

(Abgesehen davon: Wie misst man Zeiten, die nur Bruchteile des
Taktes betragen? Bei einer Frequenz von 4 GHz beträgt ein Takt
250 ps. Das Signal legt in dieser Zeit eine Strecke von 7,5 cm
zurück, bei einem Viertel demnach 1,875 cm - eine verlässliche
Messung liesse sich also nur durchführen, wenn der Proband und
das Messgerät nicht mehr als einen Zentimeter voneinander ent-
fernt wären...)


Grüsse aus Augsburg

Bernhard Schornak
Jan Bruns
2014-12-10 06:11:35 UTC
Permalink
Post by Bernhard Schornak
Du hattest gewitzelt, daß man sich bei intel selbst möglicherweise nur
wenig Gedanken über die Vorteile von CAS gemacht haben könnte, da "die
Wissenschaft" das zuvor schon theoretisiert hatte.
Das ist mir neu. Wo genau soll das gewesen sein?
Wie sonst soll man das hier

| > Ich will nicht ausschließen, dass das theoretisch möglich ist, aber ich
| > glaube doch, dass sich die Intel-Leute was dabei gedacht haben, als sie
| > (mit dem 486er?) CMPXCHG eingeführt haben.
|
| http://en.wikipedia.org/wiki/Compare-and-swap
|
| Seit wann -denken- iNTEL-Mitarbeiter denn? ;)

denn deuten? Das hast Du geschrieben in
Date: Sat, 06 Dec 2014 12:14:12 +0100
Post by Bernhard Schornak
Das hört sich erst einmal so schlüssig an, dass ich mich etwas
gründlicher damit beschäftigen werde. Dagegen spricht, dass es seit
etlichen Prozessorgenerationen nicht mehr die 8 (oder 16) bekannten
Register rAX, rBX, et cetera gibt, sondern ein paar- hundert
Scratch-Register, denen je nach Bedarf einer der Namen rAX, rBX, et
cetera zugewiesen wird.
Ja, aber das spricht doch nicht dagegen. Zumindest
nicht so direkt.

Dann muss eben für jedes Bit der Leseports nicht
mehr ein MUX8, sondern ein entsprechend grösseres
MUX her. Bestimmt kann man die dennoch mit einer
effektiven Schaltungstiefe von 2 levels implementieren.

So ein Register-renaming kann sicherlich dabei
helfen, für eine bessere Auslastung zu sorgen.

So spontan fällt mir folgende Situation als
Beispiel ein (natürlich nicht auf irgendeine
bestimmte CPU bezogen):

l1: nop
l2: nop
l3: nop
l4: mov ebx,dword ptr[]

l5: add ebx,eax
l6: inc eax
l7: nop
l8: nop

l9: add ecx,eax
la: nop
lb: nop
lc: nop

Wenn die ersten 4 Befehle gleichzeitig ausgeführt
werden, stellt sich ja wohl heraus, daß einer
davon ein Speicherzugriff ist, der sicherlich
nicht im nächsten Takt schon fertig sein wird.

Somit kann der Befehl bei @l5 im zweiten Takt
noch nicht ausgeführt werden, und muss wenigstens
noch einen Takt warten.

Ohne Register-renaming gälte das dann aber auch
für den Befehl bei @l6, weil der einen Quelloperanden
von @l5 verändert. Somit müsste möglichereise auch @l9
auf einen 4. Zyklus verschoben werden, weil der ja von
@l6 abhängt (ok, ein einfaches inc mag so ein komplexes
Verarbeitungssystem u.U. vielleicht gerade noch so
als Zusatzeigenschaft der Register verwalten können,
wenn dann wieder eine Addition folgt).

Mit register-renaming könnte dagegen sowas zu
machen sein:


l1: nop
l2: nop
l3: nop
l4: mov ebx,dword ptr[] // erster Zyklus

l6: inc eax
l7: nop
l8: nop
l4: mov ebx,dword ptr[] // zweiter Zyklus

l5: add ebx,old_eax
l9: add ecx,eax
la: nop
lb: nop
Post by Bernhard Schornak
Abgesehen davon müsste auch der Befehlsdecoder nicht nur eine, sondern
vier Einheiten pro Pipe mit Befehlen versorgen.
Äh, ja, natürlich.
Z.B. mit einer 4-stufigen pipeline:
Nehmen wir an, man hat ein Bauteil, das in einem
Takt einen Befehl aus einem Datenstrom herausfischen
kann, und einer nachfolgenden Stufe noch mitteilen
kann, wo der nächste Befehl anfangen müsste.
Dann liefern 4 solche Bauteile hintereinandergeschaltet,
wenn der next_pointer der letzten Stufe von
der ersten Stufe aufgegriffen wird, pro Takt 4 Befehle.

Gruss

Jan Bruns
Jan Bruns
2014-12-10 06:46:54 UTC
Permalink
Post by Jan Bruns
Post by Bernhard Schornak
Abgesehen davon müsste auch der Befehlsdecoder nicht nur eine, sondern
vier Einheiten pro Pipe mit Befehlen versorgen.
Äh, ja, natürlich.
Nehmen wir an, man hat ein Bauteil, das in einem Takt einen Befehl aus
einem Datenstrom herausfischen kann, und einer nachfolgenden Stufe noch
mitteilen kann, wo der nächste Befehl anfangen müsste. Dann liefern 4
solche Bauteile hintereinandergeschaltet, wenn der next_pointer der
letzten Stufe von der ersten Stufe aufgegriffen wird, pro Takt 4
Befehle.
Halt, nee, so einfach geht's nicht ganz.
Mit n-stufiger Pipeline ist ja eigentlich gemeint,
daß n Bauteile gleichzeitig arbeiten, aber jeweils
immer um einen Takt verzögert.

So ginge es aber natürlich, wenn die Stufen alle im gleichen
Takt hintereinandergeschaltet wären. Das mag etwas knapp sein.



Gruss

Jan Bruns
Jan Bruns
2014-12-10 09:49:36 UTC
Permalink
Halt, nee, so einfach geht's nicht ganz. Mit n-stufiger Pipeline ist ja
eigentlich gemeint, daß n Bauteile gleichzeitig arbeiten, aber jeweils
immer um einen Takt verzögert.
So ginge es aber natürlich, wenn die Stufen alle im gleichen Takt
hintereinandergeschaltet wären. Das mag etwas knapp sein.
Hm. Das ist hier zwar eigentlich keine Elektronikgruppe,
und ich Antworte mir erneut selbst, aber egal...

Was man da tatsächlich, real machen kann (ich kenne das Problem
von einer weit einfacheren, einzelinstruktions- CPU-Konstruktion...
das ist echt der Fluch, ständig irgendwo Cachelinegrenzen im
weg, über die Befehle sich aber erstecken können, und dann
gelichzeitig der Wunsch nach einer superkurzen Pipeline, damit
jumps nicht so teuer sind, und so):

Beim einladen einer Cacheline in einen "Befehlspuffer" in
diesem für jedes Byte zusätzlichen Platz vorsehen, für die
dekodierte Befehlslänge (mit der Annahme, ein Befehl starte
an diesem Byte), evtl. zus. die Entfernung zum übernächsten Befehl,
usw.

Also sowas

T_Instruktionpufferbyte = record
wert : byte;
nxt1,nxt2,nxt3,nxt4 : byte;
end


Direkt nach dem Einladen aus der Cacheline ist erst der Wert des Bytes
bekannt. Diese Datenstruktur ist dann aber in echt eine Schaltung,
also für jedes code-byte eine solche, die wieder über fette MUX auf den
Inhalt der anderen "bytes" zugreifen kann. Somit hat -abgesehen von
Detailfragen an Rändern von Cachelines, jedes code-"byte" die Möglichkeit,
die Länge des an seiner Position startenden Befehls auszurechnen:

Im Falle von x86 würde man vielleicht zunächst überall nxt1=0 setzen,
und das solange simultan inkrementieren lassen, bis die Befehlspräfixe
schonmal weggezählt sind. Dauert also 3 Zyklen, oder so, weiss grad
nicht, wieviele Präfixe auf x86 erlaubt bzw. häufig sind. Dann weiter
mit dem oder den Instruction Byte(s), und so fort bis endlich jedes
Code-Byte "weiss", wie lang sein Befehl ist bzw. wäre.

Sodann noch die Werte für nxt2,nxt3 und nxt4 austauschen, was wieder
3 Zyklen dauert.

Somit haben wir jetzt ganz gemächlich, sagen wir in 10-20 Zyklen
bei grossem Transistoraufwand (der heutzutage ja null interessiert)
einen Instruktions-Speicher erzeugt, der bereits vordekodierte Befehle
z.B. einer Cacheline enthält. Alternativ zu MUX könnte man die
code-bytes, bzw. nxt-Werte durchshiften.

Auf einem solchen Instruiktionspuffer funktioniert auch die anfangs
vorgeschlagene 4-stuufige Pipeline zur Befehlsdekodierung richtig,
weil nun die erste Stufe "weiss", wie sie 0-4 Befehle weiterspringen
kann.

So hat man unbedingte, kurze, relative Sprünge gleich höchst
effizient mit abgehakt.


Für besagte einzelinstruktions- CPU-Konstruktion war das aber alles
einfach viel zu "teuer" (und eine Beschränkung auf wenige
"Code-Bytes" macht das ganze ja auch nicht gerade attraktiv). Aber was
man sich in seiner Verzweiflung nicht alles noch gleich mit ausdenken
kann, ist schon interessant.


Gruss

Jan Bruns
Bernhard Schornak
2014-12-10 16:22:40 UTC
Permalink
Post by Jan Bruns
Was man da tatsächlich, real machen kann (ich kenne das Problem
von einer weit einfacheren, einzelinstruktions- CPU-Konstruktion...
das ist echt der Fluch, ständig irgendwo Cachelinegrenzen im
weg, über die Befehle sich aber erstecken können, und dann
gelichzeitig der Wunsch nach einer superkurzen Pipeline, damit
Beim einladen einer Cacheline in einen "Befehlspuffer" in
diesem für jedes Byte zusätzlichen Platz vorsehen, für die
dekodierte Befehlslänge (mit der Annahme, ein Befehl starte
an diesem Byte), evtl. zus. die Entfernung zum übernächsten Befehl,
usw.
Also sowas
T_Instruktionpufferbyte = record
wert : byte;
nxt1,nxt2,nxt3,nxt4 : byte;
end
Direkt nach dem Einladen aus der Cacheline ist erst der Wert des Bytes
bekannt. Diese Datenstruktur ist dann aber in echt eine Schaltung,
also für jedes code-byte eine solche, die wieder über fette MUX auf den
Inhalt der anderen "bytes" zugreifen kann. Somit hat -abgesehen von
Detailfragen an Rändern von Cachelines, jedes code-"byte" die Möglichkeit,
Im Falle von x86 würde man vielleicht zunächst überall nxt1=0 setzen,
und das solange simultan inkrementieren lassen, bis die Befehlspräfixe
schonmal weggezählt sind. Dauert also 3 Zyklen, oder so, weiss grad
nicht, wieviele Präfixe auf x86 erlaubt bzw. häufig sind. Dann weiter
mit dem oder den Instruction Byte(s), und so fort bis endlich jedes
Code-Byte "weiss", wie lang sein Befehl ist bzw. wäre.
Sodann noch die Werte für nxt2,nxt3 und nxt4 austauschen, was wieder
3 Zyklen dauert.
Somit haben wir jetzt ganz gemächlich, sagen wir in 10-20 Zyklen
bei grossem Transistoraufwand (der heutzutage ja null interessiert)
einen Instruktions-Speicher erzeugt, der bereits vordekodierte Befehle
z.B. einer Cacheline enthält. Alternativ zu MUX könnte man die
code-bytes, bzw. nxt-Werte durchshiften.
Auf einem solchen Instruiktionspuffer funktioniert auch die anfangs
vorgeschlagene 4-stuufige Pipeline zur Befehlsdekodierung richtig,
weil nun die erste Stufe "weiss", wie sie 0-4 Befehle weiterspringen
kann.
So hat man unbedingte, kurze, relative Sprünge gleich höchst
effizient mit abgehakt.
Für besagte einzelinstruktions- CPU-Konstruktion war das aber alles
einfach viel zu "teuer" (und eine Beschränkung auf wenige
"Code-Bytes" macht das ganze ja auch nicht gerade attraktiv). Aber was
man sich in seiner Verzweiflung nicht alles noch gleich mit ausdenken
kann, ist schon interessant.
Das mag ein wenig weiter helfen:

http://www.chip-architect.com/news/2002_06_24_hammers_two_extra_pipelinestages.html
http://mail.humber.ca/~paul.michaud/Pipeline.htm

Auch die von AMD veröffentlichten Handbücher gehen relativ
detailliert auf den Aufbau der Prozessoren ein.


Grüsse aus Augsburg

Bernhard Schornak
Bernhard Schornak
2014-12-10 16:22:32 UTC
Permalink
Post by Jan Bruns
Post by Jan Bruns
Post by Bernhard Schornak
Abgesehen davon müsste auch der Befehlsdecoder nicht nur eine, sondern
vier Einheiten pro Pipe mit Befehlen versorgen.
Äh, ja, natürlich.
Nehmen wir an, man hat ein Bauteil, das in einem Takt einen Befehl aus
einem Datenstrom herausfischen kann, und einer nachfolgenden Stufe noch
mitteilen kann, wo der nächste Befehl anfangen müsste. Dann liefern 4
solche Bauteile hintereinandergeschaltet, wenn der next_pointer der
letzten Stufe von der ersten Stufe aufgegriffen wird, pro Takt 4
Befehle.
Halt, nee, so einfach geht's nicht ganz.
Mit n-stufiger Pipeline ist ja eigentlich gemeint,
daß n Bauteile gleichzeitig arbeiten, aber jeweils
immer um einen Takt verzögert.
So ginge es aber natürlich, wenn die Stufen alle im gleichen
Takt hintereinandergeschaltet wären. Das mag etwas knapp sein.
Nicht hintereinander, sondern nebeneinander. Jede Stufe einer Pipe
kann pro Takt nur einen Datensatz bearbeiten. Bei zwei Datensätzen
müsste eine zweite Stufe vorhanden sein, um die zusätzlichen Daten
verarbeiten zu können. Theoretisch könnte man den Takt verdoppeln,
das scheitert aber schnell an physikalischen Problemen.


Grüsse aus Augsburg

Bernhard Schornak
Bernhard Schornak
2014-12-10 16:22:25 UTC
Permalink
Post by Jan Bruns
Post by Bernhard Schornak
Du hattest gewitzelt, daß man sich bei intel selbst möglicherweise nur
wenig Gedanken über die Vorteile von CAS gemacht haben könnte, da "die
Wissenschaft" das zuvor schon theoretisiert hatte.
Das ist mir neu. Wo genau soll das gewesen sein?
Wie sonst soll man das hier
| > Ich will nicht ausschließen, dass das theoretisch möglich ist, aber ich
| > glaube doch, dass sich die Intel-Leute was dabei gedacht haben, als sie
| > (mit dem 486er?) CMPXCHG eingeführt haben.
|
| http://en.wikipedia.org/wiki/Compare-and-swap
|
| Seit wann -denken- iNTEL-Mitarbeiter denn? ;)
denn deuten? Das hast Du geschrieben in
Date: Sat, 06 Dec 2014 12:14:12 +0100
Ich weiss, was ich geschrieben hatte. Interessant ist, was
Du daraus "abgeleitet" hast... ;)

(Zwischen meiner persönlichen Meinung zu iNTEL und dem zi-
tierten Wiki-Artikel besteht kein kausaler Zusammenhang.)
Post by Jan Bruns
Post by Bernhard Schornak
Das hört sich erst einmal so schlüssig an, dass ich mich etwas
gründlicher damit beschäftigen werde. Dagegen spricht, dass es seit
etlichen Prozessorgenerationen nicht mehr die 8 (oder 16) bekannten
Register rAX, rBX, et cetera gibt, sondern ein paar- hundert
Scratch-Register, denen je nach Bedarf einer der Namen rAX, rBX, et
cetera zugewiesen wird.
Ja, aber das spricht doch nicht dagegen. Zumindest
nicht so direkt.
Dann muss eben für jedes Bit der Leseports nicht
mehr ein MUX8, sondern ein entsprechend grösseres
MUX her. Bestimmt kann man die dennoch mit einer
effektiven Schaltungstiefe von 2 levels implementieren.
So ein Register-renaming kann sicherlich dabei
helfen, für eine bessere Auslastung zu sorgen.
So spontan fällt mir folgende Situation als
Beispiel ein (natürlich nicht auf irgendeine
l1: nop
l2: nop
l3: nop
l4: mov ebx,dword ptr[]
l5: add ebx,eax
l6: inc eax
l7: nop
l8: nop
l9: add ecx,eax
la: nop
lb: nop
lc: nop
Wenn die ersten 4 Befehle gleichzeitig ausgeführt
werden, stellt sich ja wohl heraus, daß einer
davon ein Speicherzugriff ist, der sicherlich
nicht im nächsten Takt schon fertig sein wird.
noch nicht ausgeführt werden, und muss wenigstens
noch einen Takt warten.
Genau aus diesem Grund wurde eine "Out of Order Execution"
erfunden, die eingehende Befehle bereits beim Einlesen und
Dekodieren analysiert, und so in der Instruktions-Pipeline
ablegt, dass während ihrer Abarbeitung möglichst keine Ab-
hängigkeiten der von Dir geschilderten Form entstehen.

http://de.wikipedia.org/wiki/Out-of-order_execution

Abgesehen davon ist der Takt ein serieller Vorgang, der in
der Datenverarbeitung nur durch Parallelisierung (mehr Bit
pro Takt) einen höheren Datendurchsatz bringen kann.

<schnipp>
Post by Jan Bruns
Post by Bernhard Schornak
Abgesehen davon müsste auch der Befehlsdecoder nicht nur eine, sondern
vier Einheiten pro Pipe mit Befehlen versorgen.
Äh, ja, natürlich.
Nehmen wir an, man hat ein Bauteil, das in einem
Takt einen Befehl aus einem Datenstrom herausfischen
kann, und einer nachfolgenden Stufe noch mitteilen
kann, wo der nächste Befehl anfangen müsste.
Dann liefern 4 solche Bauteile hintereinandergeschaltet,
wenn der next_pointer der letzten Stufe von
der ersten Stufe aufgegriffen wird, pro Takt 4 Befehle.
Seriell könnte das aber nur funktionieren, wenn solch eine
hypothetische Einheit mit dem vierfachen Takt (=> 16 GHz!)
betrieben wird. Der -bislang- schnellste Prozessor ist ein
mit Flüssiggas gekühlter Bulldozer bei 8,429 GHz:

http://tinyurl.com/6x4dqqx

Doppelt so viel ist mit der aktuellen Prozessortechnologie
rein physikalisch nicht realisierbar. Demnach könnte diese
Überlegung nur mit vier parallel arbeitenden Einheiten re-
alisiert werden, was aber sehr viel Silikon kostet. Ob man
dann noch einen L2-Cache auf das Die bringt, ist fraglich,
von einem L3-Cache bräuchten wir dann nicht einmal mehr zu
träumen...


Grüsse aus Augsburg

Bernhard Schornak
Peter J. Holzer
2014-12-13 11:19:25 UTC
Permalink
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Wer verwendet schon freiwillig CMPXCHG?
Leute, die Locking-Primitives schreiben?
Das hat zwar mit Assembler rein gar nix zu tun,
Letztendlich muss es in Assembler implemetiert werden. Entweder in einer
Library oder durch den Compiler.
Ja - mit der Kompetenz von HLL-Compilerbauern... ;)
Meiner Erfahrung nach ist es mit der Kompetenz von Leuten, die
routinemäßig alle anderen als inkompetent bezeichnen, meist nicht weit
her.
Post by Bernhard Schornak
Post by Peter J. Holzer
XCHG macht übrigens ein implizites LOCK, dürfte also nicht wesentlich
billiger sein als ein LOCK CMPXCHG.
AMD : 5 Takte FP-Double statt 6/7 Takte Complex
iNTEL: 1.5 (???) statt 5 Takte
1.5 Takte, wenn mit einer anderen CPU kommuniziert werden muss? Die
Zeitangabe bezieht sich wohl auf ein XCHG von zwei Registern im selben
Core, aber ganz sicher nicht auf einen Speicherzugriff.
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Wer viel will, muss viel dafür tun (oder an der Börse zocken) - ein
paar zusätzliche Befehle braucht es sicher, um das zu realisieren.
Mit "ein paar zusätzlichen Befehlen" werden Race-Conditions meistens
nicht besser.
Je mehr Code, desto grösser die Verzögerung. Reicht meist aus,
... damit der Code nicht mehr beim Testen crasht, sondern erst in
Produktion, unter hoher Last und genau dann, wenn man es am wenigsten
brauchen kann. Das ist natürlich genau die Qualität, die man haben will.
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
Ich will nicht ausschließen, dass das theoretisch möglich ist, aber ich
glaube doch, dass sich die Intel-Leute was dabei gedacht haben, als sie
(mit dem 486er?) CMPXCHG eingeführt haben.
http://en.wikipedia.org/wiki/Compare-and-swap
| In the x86 (since 80486) and Itanium architectures this is implemented
| as the compare and exchange (CMPXCHG) instruction, though here the
| LOCK prefix should be there to make it really atomic.
Wo ist da der Widerspruch?
Welcher Widerspruch in Relation zu was?
Der Widerspruch zu meiner Mutmaßung, dass die Intel-Leute einen guten
Grund hatten, CMPXCHG einzuführen. Schließlich hast Du diesen Link
unmittelbar nach dieser Vermutung eingeworfen, also kann man wohl
erwarten, dass Du Dich darauf beziehst.

Der Artikel müsste also aussagen, dass CMPXCHG unnötig oder gar
kontraproduktiv ist. Tut er aber nicht, ganz im Gegenteil.
Post by Bernhard Schornak
Wer daran glaubt, dass eine Ausführungseinheit (Execution Pipe) in
-einem- Taktzyklus -bis zu vier- Befehle ausgeführt werden können
Was hat denn das jetzt mit CMPXCHG zu tun?
Post by Bernhard Schornak
(das heisst: Es werden 4 Ergebnisse pro Takt geliefert!), der hat
Physik durch Religion ersetzt.
Solche Architekturen nennt man superskalar, und sie existieren seit
Jahrzehnten. Die x86-Architektur ist seit dem Pentium ebenfalls
superskalar. Wieviele Instruktionen tatsächlich parallel abgearbeitet
werden, ist eine Frage des Aufwands (beim Pentium waren es nur 2), aber
zumindest bei einigen aktuellen Intel-Prozessoren sind es 4.
Post by Bernhard Schornak
Religion fordert Glauben statt Denken - ergo können die iNTELianer
(wie alle guten Bewohner der USA!) nicht denken... ;)
Ich sehe den Smiley, aber hilft nicht.

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Bernhard Schornak
2014-12-13 15:09:47 UTC
Permalink
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
XCHG macht übrigens ein implizites LOCK, dürfte also nicht wesentlich
billiger sein als ein LOCK CMPXCHG.
AMD : 5 Takte FP-Double statt 6/7 Takte Complex
iNTEL: 1.5 (???) statt 5 Takte
1.5 Takte, wenn mit einer anderen CPU kommuniziert werden muss? Die
Zeitangabe bezieht sich wohl auf ein XCHG von zwei Registern im selben
Core, aber ganz sicher nicht auf einen Speicherzugriff.
Oder auf neuartige Logikgatter, die bei steigenden und fallenden
Flanken des Taktsignals schalten. Möglicherweise ging es aber um
die Unterschiede zwischen XCHG und LOCK CMPXCHG, und die Angaben
geben ganz einfach die in den Datenbüchern angegebenen Takte an?
Post by Peter J. Holzer
Post by Bernhard Schornak
Wer daran glaubt, dass eine Ausführungseinheit (Execution Pipe) in
-einem- Taktzyklus -bis zu vier- Befehle ausgeführt werden können
Was hat denn das jetzt mit CMPXCHG zu tun?
Das kann man oben nachlesen. Wenn das mit den Logikgattern keine
neue Erfindung von iNTEL ist, gibt es auch keine Befehle, die in
halben, drittel oder gar viertel Taktzyklen aus Prozessoren "ge-
pumpt" werden.
Post by Peter J. Holzer
Post by Bernhard Schornak
(das heisst: Es werden 4 Ergebnisse pro Takt geliefert!), der hat
Physik durch Religion ersetzt.
Solche Architekturen nennt man superskalar, und sie existieren seit
Jahrzehnten. Die x86-Architektur ist seit dem Pentium ebenfalls
superskalar. Wieviele Instruktionen tatsächlich parallel abgearbeitet
werden, ist eine Frage des Aufwands (beim Pentium waren es nur 2), aber
zumindest bei einigen aktuellen Intel-Prozessoren sind es 4.
Es ging hier um vier Befehle pro Takt -und- pro Execution-Pipe -
die Taktangaben in einem Datenbuch beziehen sich -immer- auf die
Verarbeitung in einer Pipe, nicht auf den Durchsatz des gesamten
Kerns oder Prozessors.


Schönes Wochenende

Bernhard Schornak
Peter J. Holzer
2014-12-13 18:14:56 UTC
Permalink
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
XCHG macht übrigens ein implizites LOCK, dürfte also nicht wesentlich
billiger sein als ein LOCK CMPXCHG.
AMD : 5 Takte FP-Double statt 6/7 Takte Complex
iNTEL: 1.5 (???) statt 5 Takte
1.5 Takte, wenn mit einer anderen CPU kommuniziert werden muss? Die
Zeitangabe bezieht sich wohl auf ein XCHG von zwei Registern im selben
Core, aber ganz sicher nicht auf einen Speicherzugriff.
Oder auf neuartige Logikgatter, die bei steigenden und fallenden
Flanken des Taktsignals schalten. Möglicherweise ging es aber um
die Unterschiede zwischen XCHG und LOCK CMPXCHG, und die Angaben
geben ganz einfach die in den Datenbüchern angegebenen Takte an?
Genau, es ging um den von Dir behaupteten und von mir bezweifelten
großen Performance-Unterschied zwischen XCHG und LOCK CMPXCHG. Dass Du
die 1.5 Takte einfach aus irgendeinem Datenblatt abgeschrieben hast,
glaube ich Dir sofort, aber nachgedacht hast Du dabei offensichtlich
nicht. Ein L1-Zugriff braucht bei einem Core i7 5500 4 Takte. Sowohl
XCHG als auch CMPXCHG brauchen zwei Zugriffe (einen Lese- und einen
Schreibzugriff), also geht unter 8 Takten gar nichts. Und da nehmen wir
schon großzügig an, dass die Cache-Invalidation auf den anderen
Prozessoren sich ebenfalls in der Zeit ausgeht, was ich (trotz QPI) eher
bezweifeln möchte. agner.org (die die ja auch schon zitiert hast),
listet für diese Instruktionen auf neueren Intel-Prozessoren Latenzen
von >= 20 Zyklen. Das scheint mir realistisch zu sein (im günstigsten
Fall: Wenn da wirklich auf RAM zugegriffen werden muss, womöglich noch
in einer anderen NUMA-Zone, wird das noch viel langsamer).
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Wer daran glaubt, dass eine Ausführungseinheit (Execution Pipe) in
-einem- Taktzyklus -bis zu vier- Befehle ausgeführt werden können
Was hat denn das jetzt mit CMPXCHG zu tun?
Das kann man oben nachlesen.
Ach, dich stört der halbe Takt in der Angabe. Da ich nicht weiß, wo Du
den her hast, kann ich dazu auch nichts Definitives sagen. Lies selber
nach, was es zu bedeuten hat. Ich vermute mal, das ist der
durchschnittliche CPI-Wert unter idealen Bedingungen: Also wenn Du 100
XCHG reg,reg Instruktionen hintereinander ausführst, dann dauert das 150
Takte.
Post by Bernhard Schornak
Wenn das mit den Logikgattern keine neue Erfindung von iNTEL ist, gibt
es auch keine Befehle, die in halben, drittel oder gar viertel
Taktzyklen aus Prozessoren "ge- pumpt" werden.
Das hat auch außer Dir niemand angenommen.

(Theoretisch wäre es natürlich möglich, dass innerhalb eines Prozessors
einfache Schaltungen mit höherer Taktfrequenz laufen - aber Du kannst
Gift darauf nehmen, dass in dem Fall die Marketing-Abteilung natürlich
die höchste Frequenz als "Prozessorgeschwindigkeit" angibt).
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
(das heisst: Es werden 4 Ergebnisse pro Takt geliefert!), der hat
Physik durch Religion ersetzt.
Solche Architekturen nennt man superskalar, und sie existieren seit
Jahrzehnten. Die x86-Architektur ist seit dem Pentium ebenfalls
superskalar. Wieviele Instruktionen tatsächlich parallel abgearbeitet
werden, ist eine Frage des Aufwands (beim Pentium waren es nur 2), aber
zumindest bei einigen aktuellen Intel-Prozessoren sind es 4.
Es ging hier um vier Befehle pro Takt -und- pro Execution-Pipe -
die Taktangaben in einem Datenbuch beziehen sich -immer- auf die
Verarbeitung in einer Pipe, nicht auf den Durchsatz des gesamten
Kerns oder Prozessors.
Die Taktangaben in einem Datenbuch sind generell mit Vorsicht zu
genießen und man sollte auch das Kleingedruckte lesen. Eine einzelne
Zahl wird auf keinem Prozessor, der in den letzten 20 Jahren erschienen
ist, das Zeitverhalten adäquat beschreiben.

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Bernhard Schornak
2014-12-13 23:54:46 UTC
Permalink
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
XCHG macht übrigens ein implizites LOCK, dürfte also nicht wesentlich
billiger sein als ein LOCK CMPXCHG.
AMD : 5 Takte FP-Double statt 6/7 Takte Complex
iNTEL: 1.5 (???) statt 5 Takte
1.5 Takte, wenn mit einer anderen CPU kommuniziert werden muss? Die
Zeitangabe bezieht sich wohl auf ein XCHG von zwei Registern im selben
Core, aber ganz sicher nicht auf einen Speicherzugriff.
Oder auf neuartige Logikgatter, die bei steigenden und fallenden
Flanken des Taktsignals schalten. Möglicherweise ging es aber um
die Unterschiede zwischen XCHG und LOCK CMPXCHG, und die Angaben
geben ganz einfach die in den Datenbüchern angegebenen Takte an?
Genau, es ging um den von Dir behaupteten und von mir bezweifelten
großen Performance-Unterschied zwischen XCHG und LOCK CMPXCHG. Dass Du
die 1.5 Takte einfach aus irgendeinem Datenblatt abgeschrieben hast,
glaube ich Dir sofort, aber nachgedacht hast Du dabei offensichtlich
nicht.
Da es ebenso müssig ist wie das Kontemplieren über das Pinout
eines TTL-ICs? Selbst wenn man es wollte, könnte man -beides-
physikalisch nicht mehr ändern.
Post by Peter J. Holzer
Ein L1-Zugriff braucht bei einem Core i7 5500 4 Takte. Sowohl
XCHG als auch CMPXCHG brauchen zwei Zugriffe (einen Lese- und einen
Schreibzugriff), also geht unter 8 Takten gar nichts.
Dann sei bitte so lieb und bitte AMD / iNTEL, ihre "falschen"
Angaben in allen von ihnen publizierten Datenbüchern umgehend
zu ändern - ich bin der falsche Ansprechpartner.
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Wer daran glaubt, dass eine Ausführungseinheit (Execution Pipe) in
-einem- Taktzyklus -bis zu vier- Befehle ausgeführt werden können
Was hat denn das jetzt mit CMPXCHG zu tun?
Das kann man oben nachlesen.
Ach, dich stört der halbe Takt in der Angabe. Da ich nicht weiß, wo Du
den her hast, kann ich dazu auch nichts Definitives sagen. Lies selber
nach, was es zu bedeuten hat. Ich vermute mal, das ist der
durchschnittliche CPI-Wert unter idealen Bedingungen: Also wenn Du 100
XCHG reg,reg Instruktionen hintereinander ausführst, dann dauert das 150
Takte.
Warum beschwerst Du Dich erst über falsche Angaben der Daten-
bücher, wenn Dir zwei Absätze später plötzlich (quer über den
Daumen geratene!) Angaben in "characters per inch" reichen?
Post by Peter J. Holzer
Post by Bernhard Schornak
Wenn das mit den Logikgattern keine neue Erfindung von iNTEL ist, gibt
es auch keine Befehle, die in halben, drittel oder gar viertel
Taktzyklen aus Prozessoren "ge- pumpt" werden.
Das hat auch außer Dir niemand angenommen.
Du solltest vielleicht doch einmal in das "Intel 64 and IA-32
Architectures Software Developer’s Manual" - das Standardwerk,
das man als Assemblerprogrammierer rezitieren können müsste -
schauen?
Post by Peter J. Holzer
(Theoretisch wäre es natürlich möglich, dass innerhalb eines Prozessors
einfache Schaltungen mit höherer Taktfrequenz laufen - aber Du kannst
Gift darauf nehmen, dass in dem Fall die Marketing-Abteilung natürlich
die höchste Frequenz als "Prozessorgeschwindigkeit" angibt).
Prozessoren, die bei Frequenzen jenseits 5 GHz laufen können,
sind mit der vorhandenen Lithographietechnik höchstens in La-
borstückzahlen produzierbar.
Post by Peter J. Holzer
Die Taktangaben in einem Datenbuch sind generell mit Vorsicht zu
genießen und man sollte auch das Kleingedruckte lesen. Eine einzelne
Zahl wird auf keinem Prozessor, der in den letzten 20 Jahren erschienen
ist, das Zeitverhalten adäquat beschreiben.
Mit Deinem Expertenwissen kann ich als Programmierer diverser
in reinem Assembler verfasster Lowlevel-Testprogramme für die
Latenzen von Einzelbefehlen, die übrigens (zumindest bei AMD)
relativ genau mit den in Datenbüchern veröffentlichten Zahlen
übereinstimmen, natürlich nicht mithalten...


Schönes Wochenende

Bernhard Schornak
Peter J. Holzer
2014-12-14 13:53:09 UTC
Permalink
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
XCHG macht übrigens ein implizites LOCK, dürfte also nicht wesentlich
billiger sein als ein LOCK CMPXCHG.
AMD : 5 Takte FP-Double statt 6/7 Takte Complex
iNTEL: 1.5 (???) statt 5 Takte
1.5 Takte, wenn mit einer anderen CPU kommuniziert werden muss? Die
Zeitangabe bezieht sich wohl auf ein XCHG von zwei Registern im selben
Core, aber ganz sicher nicht auf einen Speicherzugriff.
Oder auf neuartige Logikgatter, die bei steigenden und fallenden
Flanken des Taktsignals schalten. Möglicherweise ging es aber um
die Unterschiede zwischen XCHG und LOCK CMPXCHG, und die Angaben
geben ganz einfach die in den Datenbüchern angegebenen Takte an?
Genau, es ging um den von Dir behaupteten und von mir bezweifelten
großen Performance-Unterschied zwischen XCHG und LOCK CMPXCHG. Dass Du
die 1.5 Takte einfach aus irgendeinem Datenblatt abgeschrieben hast,
glaube ich Dir sofort, aber nachgedacht hast Du dabei offensichtlich
nicht.
Da es ebenso müssig ist wie das Kontemplieren über das Pinout
eines TTL-ICs? Selbst wenn man es wollte, könnte man -beides-
physikalisch nicht mehr ändern.
Vom Ändern redet ja auch niemand, nur vom Verstehen. Dass sich 1.5 Takte
bei zwei Memory-Zugriffen (selbst wenn es nur auf den L1-Cache ist)
nicht ausgehen können, sollte jedem klar sein, der auch nur ein bisschen
eine Ahnung von Prozessorarchitekturen hat.
Post by Bernhard Schornak
Post by Peter J. Holzer
Ein L1-Zugriff braucht bei einem Core i7 5500 4 Takte. Sowohl
XCHG als auch CMPXCHG brauchen zwei Zugriffe (einen Lese- und einen
Schreibzugriff), also geht unter 8 Takten gar nichts.
Dann sei bitte so lieb und bitte AMD / iNTEL, ihre "falschen"
Angaben in allen von ihnen publizierten Datenbüchern umgehend
zu ändern - ich bin der falsche Ansprechpartner.
Du hast ja keine Quellen angegeben, daher kann ich das nicht einmal
überprüfen. Vielleicht liegt das Problem ja eher beim Leser als beim
Buch?

Kleines Beispiel: In meinem 8086er-Buch (der 8086 ist ungefähr zu der
Zeit erschienen, als Du mit Assembler gegonnen hast, vielleicht liegt
Dir der mehr) stehen (über 4 Seiten verteil) drei verschiedene
Ausführungszeiten für XCHG:

3 Takte (für XCHG AX, reg)
4 Takte (für XCHG reg, reg)
17+EA Takte (für XCHG reg/mem, reg/mem)

Wenn ich da übersehe, dass die erste Angabe nur für die einfachste Form
von XCHG steht und nicht umblättere, dann glaube ich vielleicht, dass
der 8086 einen Wert in einem Register mit einem im Memory in 3 Takten
austauschen konnte. Konnte er natürlich nicht (auch das musste damals
jedem halbwegs kompetenten Programmierer klar sein), die richtige Angabe
für diesen Fall war 17+EA Takte (und wieviel EA war, hing natürlich vom
RAM ab).
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Wer daran glaubt, dass eine Ausführungseinheit (Execution Pipe) in
-einem- Taktzyklus -bis zu vier- Befehle ausgeführt werden können
Was hat denn das jetzt mit CMPXCHG zu tun?
Das kann man oben nachlesen.
Ach, dich stört der halbe Takt in der Angabe. Da ich nicht weiß, wo Du
den her hast, kann ich dazu auch nichts Definitives sagen. Lies selber
nach, was es zu bedeuten hat. Ich vermute mal, das ist der
durchschnittliche CPI-Wert unter idealen Bedingungen: Also wenn Du 100
XCHG reg,reg Instruktionen hintereinander ausführst, dann dauert das 150
Takte.
Warum beschwerst Du Dich erst über falsche Angaben der Daten-
bücher,
Ich beschwere mich gar nicht über falsche Angaben, ich bezweifle nur,
dass Deine Interpretation richtig ist. Die Angabe ist fast sicher
richtig, Du musst nur nachlesen, was sie bedeutet.
Post by Bernhard Schornak
wenn Dir zwei Absätze später plötzlich (quer über den
Daumen geratene!) Angaben in "characters per inch" reichen?
"Clock cycles per instruction" natürlich. Unter welchem Stein hast Du
Dich die letzten 35 Jahre verkrochen?
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Wenn das mit den Logikgattern keine neue Erfindung von iNTEL ist, gibt
es auch keine Befehle, die in halben, drittel oder gar viertel
Taktzyklen aus Prozessoren "ge- pumpt" werden.
Das hat auch außer Dir niemand angenommen.
Du solltest vielleicht doch einmal in das "Intel 64 and IA-32
Architectures Software Developer’s Manual" - das Standardwerk,
das man als Assemblerprogrammierer rezitieren können müsste -
schauen?
Wie gesagt, ich bezweifle, dass Du den Inhalt richtig interpretierst.
Post by Bernhard Schornak
Post by Peter J. Holzer
(Theoretisch wäre es natürlich möglich, dass innerhalb eines Prozessors
einfache Schaltungen mit höherer Taktfrequenz laufen - aber Du kannst
Gift darauf nehmen, dass in dem Fall die Marketing-Abteilung natürlich
die höchste Frequenz als "Prozessorgeschwindigkeit" angibt).
Prozessoren, die bei Frequenzen jenseits 5 GHz laufen können,
sind mit der vorhandenen Lithographietechnik höchstens in La-
borstückzahlen produzierbar.
Naja, einfache Schaltungen gehen durchaus schneller als ein ganzer
Prozessor. Aber wie gesagt, wenn Intel das machen würde, würde sich die
Marketingabteilung sofort darauf werfen. Also kann man mit 99%iger
Sicherheit davon ausgehen, dass sie es nicht machen.

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Bernhard Schornak
2014-12-14 19:12:14 UTC
Permalink
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
XCHG macht übrigens ein implizites LOCK, dürfte also nicht wesentlich
billiger sein als ein LOCK CMPXCHG.
AMD : 5 Takte FP-Double statt 6/7 Takte Complex
iNTEL: 1.5 (???) statt 5 Takte
1.5 Takte, wenn mit einer anderen CPU kommuniziert werden muss? Die
Zeitangabe bezieht sich wohl auf ein XCHG von zwei Registern im selben
Core, aber ganz sicher nicht auf einen Speicherzugriff.
Oder auf neuartige Logikgatter, die bei steigenden und fallenden
Flanken des Taktsignals schalten. Möglicherweise ging es aber um
die Unterschiede zwischen XCHG und LOCK CMPXCHG, und die Angaben
geben ganz einfach die in den Datenbüchern angegebenen Takte an?
Genau, es ging um den von Dir behaupteten und von mir bezweifelten
großen Performance-Unterschied zwischen XCHG und LOCK CMPXCHG. Dass Du
die 1.5 Takte einfach aus irgendeinem Datenblatt abgeschrieben hast,
glaube ich Dir sofort, aber nachgedacht hast Du dabei offensichtlich
nicht.
Da es ebenso müssig ist wie das Kontemplieren über das Pinout
eines TTL-ICs? Selbst wenn man es wollte, könnte man -beides-
physikalisch nicht mehr ändern.
Vom Ändern redet ja auch niemand, nur vom Verstehen. Dass sich 1.5 Takte
bei zwei Memory-Zugriffen (selbst wenn es nur auf den L1-Cache ist)
nicht ausgehen können, sollte jedem klar sein, der auch nur ein bisschen
eine Ahnung von Prozessorarchitekturen hat.
Irgendwie reden wir aneinander vorbei. Ich habe mit selbstgebauten
TTL-Schaltungen begonnen, als es noch keinen erschwinglichen Heim-
computer gab. Das erste, grundlegende Prinzip jeder Logikschaltung
ist der Takt (Schaltzyklus) als kleinstmögliche Einheit: Die Zeit,
die zwischen je zwei aufeinander folgenden Ein- oder Ausschaltvor-
gängen vergeht. Der Weitertransport von Signalen zwischen zwei wie
auch immer beschaffenen Einheiten erfolgt immer mit der steigenden
(oder fallenden bei Active-Low-Logik) Flanke. Während der entgegen
gesetzten Flanke (fallend oder steigend) passiert hingegen nichts,
da die Elektronik nur auf eine Flanke reagieren kann.

Prozessoren basieren auf den gleichen Grundlagen. Es gibt - meines
Wissens - kein einziges Prozessordesign, das auf beide Flanken re-
agiert, um zwei Signale pro Takt generieren zu können.

Von dieser Warte her sind mir iNTELs Angaben suspekt - und wesent-
lich mehr als das hatte ich bislang auch nicht geäussert.
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
Ein L1-Zugriff braucht bei einem Core i7 5500 4 Takte. Sowohl
XCHG als auch CMPXCHG brauchen zwei Zugriffe (einen Lese- und einen
Schreibzugriff), also geht unter 8 Takten gar nichts.
Dann sei bitte so lieb und bitte AMD / iNTEL, ihre "falschen"
Angaben in allen von ihnen publizierten Datenbüchern umgehend
zu ändern - ich bin der falsche Ansprechpartner.
Du hast ja keine Quellen angegeben, daher kann ich das nicht einmal
überprüfen. Vielleicht liegt das Problem ja eher beim Leser als beim
Buch?
Zum "Handwerkszeug" jedes Assemblerprogrammierers gehören aktuelle
"Optimisation Guides" der Prozessorhersteller, in denen in der Re-
gel auch Abarbeitungszeiten (Latencies) der einzelnen Befehle ent-
halten sind. Da ich in einer Newsgruppe für Assemblerprogrammierer
poste, darf ich davon ausgehen, dass die Grundlagen bekannt sind.
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Wer daran glaubt, dass eine Ausführungseinheit (Execution Pipe) in
-einem- Taktzyklus -bis zu vier- Befehle ausgeführt werden können
Was hat denn das jetzt mit CMPXCHG zu tun?
Das kann man oben nachlesen.
Ach, dich stört der halbe Takt in der Angabe. Da ich nicht weiß, wo Du
den her hast, kann ich dazu auch nichts Definitives sagen. Lies selber
nach, was es zu bedeuten hat. Ich vermute mal, das ist der
durchschnittliche CPI-Wert unter idealen Bedingungen: Also wenn Du 100
XCHG reg,reg Instruktionen hintereinander ausführst, dann dauert das 150
Takte.
Warum beschwerst Du Dich erst über falsche Angaben der Daten-
bücher,
Ich beschwere mich gar nicht über falsche Angaben, ich bezweifle nur,
dass Deine Interpretation richtig ist. Die Angabe ist fast sicher
richtig, Du musst nur nachlesen, was sie bedeutet.
Wie bereits gesagt: Es ist müssig, sich über veröffentlichte Daten
den Kopf zu zerbrechen. Wenn ich mit meinen eigenen Testprogrammen
die Latenzen von zwanzig oder dreissig Befehlen bestätigen konnte,
dürften die restlichen Angaben mit grosser Wahrscheinlichkeit auch
korrekt sein. Andererseits hatte ich (überzeugter "iNTEL OUTSIDE"-
Fan) noch keinen PC, in dem ein iNTEL-Prozessor arbeitete. Deshalb
habe ich von iNTEL-Produkten keine Vergleichsdaten, und kann daher
keine Angaben zu deren Ausführungszeiten machen. Als Elektronikfan
lassen Angaben mit Null-Komma-Irgendwas Taktzyklen bei mir besten-
falls die Alarmglocken läuten...

Deinen Vorwurf bezüglich des Nicht-Verstehens von Datenbüchern ig-
noriere ich ganz einfach...
Post by Peter J. Holzer
Post by Bernhard Schornak
wenn Dir zwei Absätze später plötzlich (quer über den
Daumen geratene!) Angaben in "characters per inch" reichen?
"Clock cycles per instruction" natürlich. Unter welchem Stein hast Du
Dich die letzten 35 Jahre verkrochen?
Gegenfrage: In welcher Wortdesign-Werkstätte arbeitest Du?

Beim Gurgeln stosse ich auf

- Characters Per Inch
- Consumer Price Index
- Corruption Perception Index
- California Psychological Inventory
- Crane Payment Innovations

und viele andere, aber kein "Clock cycles per instruction" (was in
korrekter Form auch zu CCPI abgekürzt würde)...

Wenn Du schon neue Begriffe erfindest, würde eine Erklärung sicher
zum Verständnis Deiner Antworten beitragen.
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Bernhard Schornak
Wenn das mit den Logikgattern keine neue Erfindung von iNTEL ist, gibt
es auch keine Befehle, die in halben, drittel oder gar viertel
Taktzyklen aus Prozessoren "ge- pumpt" werden.
Das hat auch außer Dir niemand angenommen.
Du solltest vielleicht doch einmal in das "Intel 64 and IA-32
Architectures Software Developer’s Manual" - das Standardwerk,
das man als Assemblerprogrammierer rezitieren können müsste -
schauen?
Wie gesagt, ich bezweifle, dass Du den Inhalt richtig interpretierst.
Was - mit Verlaub - Dein Problem ist.
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
(Theoretisch wäre es natürlich möglich, dass innerhalb eines Prozessors
einfache Schaltungen mit höherer Taktfrequenz laufen - aber Du kannst
Gift darauf nehmen, dass in dem Fall die Marketing-Abteilung natürlich
die höchste Frequenz als "Prozessorgeschwindigkeit" angibt).
Prozessoren, die bei Frequenzen jenseits 5 GHz laufen können,
sind mit der vorhandenen Lithographietechnik höchstens in La-
borstückzahlen produzierbar.
Naja, einfache Schaltungen gehen durchaus schneller als ein ganzer
Prozessor.
Es geht hier um Prozessoren, nicht um die in Satelliten und Radar-
geräte eingesetzte Elektronik, die /hochfrequenzseitig/ immer noch
auf analoger Basis arbeitet - ein mit 60 GHz betriebener Prozessor
ist auf absehbare Zeit nicht realisierbar.
Post by Peter J. Holzer
Aber wie gesagt, wenn Intel das machen würde, würde sich die
Marketingabteilung sofort darauf werfen. Also kann man mit 99%iger
Sicherheit davon ausgehen, dass sie es nicht machen.
Wie bereits angesprochen könnte man den Datendurchsatz verdoppeln,
wenn man die Möglichkeit fände, sowohl bei steigenden als auch bei
fallenden Taktflanken eine Aktion zu triggern. Das muss eine Firma
nicht zwangsläufig an die grosse Glocke hängen, wenn sie möglichst
lange die zwangsläufig auftretenden "Nachahmer" auf Distanz halten
möchte...


Grüsse aus Augsburg

Bernhard Schornak
Peter J. Holzer
2014-12-14 20:17:22 UTC
Permalink
Post by Bernhard Schornak
Post by Peter J. Holzer
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
XCHG macht übrigens ein implizites LOCK, dürfte also nicht wesentlich
billiger sein als ein LOCK CMPXCHG.
AMD : 5 Takte FP-Double statt 6/7 Takte Complex
iNTEL: 1.5 (???) statt 5 Takte
1.5 Takte, wenn mit einer anderen CPU kommuniziert werden muss? Die
Zeitangabe bezieht sich wohl auf ein XCHG von zwei Registern im selben
Core, aber ganz sicher nicht auf einen Speicherzugriff.
[...]
Post by Bernhard Schornak
Post by Peter J. Holzer
Vom Ändern redet ja auch niemand, nur vom Verstehen. Dass sich 1.5 Takte
bei zwei Memory-Zugriffen (selbst wenn es nur auf den L1-Cache ist)
nicht ausgehen können, sollte jedem klar sein, der auch nur ein bisschen
eine Ahnung von Prozessorarchitekturen hat.
Irgendwie reden wir aneinander vorbei.
Ja, ich merke es. Du hängst Dich daran auf, dass da keine ganze Zahl
steht. Mir ist das hingegen ziemlich egal, erstens weil es ein
Durchschnitt sein könnte, und zweitens weil Du mit fast 100%-iger
Sicherheit die falsche Zahl zitiert hast. Ob da 1, 1.5 oder 2 Takte
steht - es ist garantiert falsch für einen Memory-Zugriff. Eine
Abweichung von 0.5 ist vollkommen belanglos, wenn der wahre Fehler
wahrscheinlich eher bei 20 liegt.

Damit bleibt mir nur noch "386" zu sagen, und damit meine ich auch nicht
den Intel-Prozessor :-).

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Bernhard Schornak
2014-12-15 14:55:03 UTC
Permalink
Post by Peter J. Holzer
Ja, ich merke es. Du hängst Dich daran auf, dass da keine ganze Zahl
steht. Mir ist das hingegen ziemlich egal, erstens weil es ein
Durchschnitt sein könnte, und zweitens weil Du mit fast 100%-iger
Sicherheit die falsche Zahl zitiert hast. Ob da 1, 1.5 oder 2 Takte
steht - es ist garantiert falsch für einen Memory-Zugriff.
Post by Bernhard Schornak
AMD : 5 Takte FP-Double statt 6/7 Takte Complex
iNTEL: 1.5 (???) statt 5 Takte
Bulldozer benötigt lesenderweise 4 Takte für L1-Hits. Die meisten
Schreibzugriffe werden durch Write-Combining "versteckt", so dass
sich das Schreiben auf einen Takt reduziert, die restlichen Takte
"schluckt" das Speicherinterface. Die Angaben von AMD sind durch-
aus realistisch angesetzt und daher glaubhaft. (Complex blockiert
die vier Execution Pipes des Kerns, ist also ein kostenintensiver
Befehl - man könnte in der gegebenen Zeit im günstigsten Fall bis
zu 24/28 einfache FastPath-Befehle ausführen!)

Was (nicht nur wegen der "krummen" Angaben!) nicht glaubhaft ist,
sind die Angaben von iNTEL, die aus dem

"Intel® 64 and IA-32 Architectures Optimization Reference Manual,
Order Number: 248966-020" (veröffentlicht 2009)

stammten. Im Gegensatz zu AMD informiert uns iNTEL nicht darüber,
ob sich diese Angaben auf einen Register-Register- oder einen Re-
gister-Speicher-Zugriff beziehen (AMD listet jede Zugriffsform in
einer gesonderten Zeile).

Addendum: In der neuesten 248966-Version von 2011 wird inzwischen
angegeben, dass die 1.5 Takte für XCHG einer Register-Register-Op
entsprechen. Wie der CMPXCHG-Wert zustande kommt, muss man weiter
raten, da weiterführende Angaben nach wie vor fehlen.


Generell: Taktangaben sind keine Durchschnittswerte, sondern eine
-exakt- messbare Anzahl von Taktzyklen, die zur Abarbeitung eines
Befehls benötigt werden. Die Abarbeitungszeit jedes Befehls hängt
vom Prozessordesign ab - sie kann vom Hersteller für jeden Befehl
mittels Prozessorsimulation auf den Takt genau bestimmt werden.

Da ein Taktzyklus physikalisch die -kleinste- vorkommende Einheit
ist, kann das Ergebnis eines Befehls niemals nach einem Bruchteil
eines Taktes ausgegeben werden, wie uns iNTELs Angabe suggerieren
möchte - das ist physikalisch unmöglich!

Irgendwo in c.l.a.x86 oder a.l.a gab es schon einmal eine diesbe-
zügliche Diskussion, in der es ebenfalls um halbe Taktzyklen ging
- ich kann den entsprechenden Thread leider nicht mehr finden, da
mir inzwischen der Titel entfallen ist (war 2012 oder 2013).

BTW: Für mystische Zahlenspiele dürften sich in de.alt.astrologie
oder de.alt.paranormal sicher recht interessante Gesprächspartner
finden... ;)


Grüsse aus Augsburg

Bernhard Schornak
Peter J. Holzer
2014-12-20 13:39:52 UTC
Permalink
Post by Bernhard Schornak
"Intel® 64 and IA-32 Architectures Optimization Reference Manual,
Order Number: 248966-020" (veröffentlicht 2009)
Ah, eine Quellenangabe. Danke.
Post by Bernhard Schornak
stammten. Im Gegensatz zu AMD informiert uns iNTEL nicht darüber,
ob sich diese Angaben auf einen Register-Register- oder einen Re-
gister-Speicher-Zugriff beziehen (AMD listet jede Zugriffsform in
einer gesonderten Zeile).
Addendum: In der neuesten 248966-Version von 2011 wird inzwischen
angegeben, dass die 1.5 Takte für XCHG einer Register-Register-Op
entsprechen. Wie der CMPXCHG-Wert zustande kommt, muss man weiter
raten, da weiterführende Angaben nach wie vor fehlen.
In der allerneuesten (248966-30, September 2014) steht auch das drin.
(Soweit ich sehe, stehen dort nur Befehle mit Register- und
Immediate-Operanden. Die mit Memory-Operanden haben sie sich wohl
wegen der Abhängigkeit von externen Faktoren gespart.)
Post by Bernhard Schornak
Generell: Taktangaben sind keine Durchschnittswerte, sondern eine
-exakt- messbare Anzahl von Taktzyklen, die zur Abarbeitung eines
Befehls benötigt werden.
Die aber nicht konstant ist. Hängt teilweise von den Operanden ab (z.B.
bei DIV) und bei superskalaren out-of-order Architekturen natürlich auch
davon, was da sonst so in der Pipeline hängt.
Post by Bernhard Schornak
Die Abarbeitungszeit jedes Befehls hängt
vom Prozessordesign ab - sie kann vom Hersteller für jeden Befehl
mittels Prozessorsimulation auf den Takt genau bestimmt werden.
Da ein Taktzyklus physikalisch die -kleinste- vorkommende Einheit
ist, kann das Ergebnis eines Befehls niemals nach einem Bruchteil
eines Taktes ausgegeben werden, wie uns iNTELs Angabe suggerieren
möchte - das ist physikalisch unmöglich!
In 248966-30, Kapitel 15.4 gibt es eine Spalte "Throughput" und eine
Spalte "Latency". Die "krummen" Taktzahlen kommen ausschließlich in der
Spalte Throughput vor. Darüber steht die Erklärung:

| Throughput value listed as “n/m”, where ‘m’ ops can be dispatched
| every ‘n’ cycle.

Wenn dort also 0.5 steht, dann heißt das, dass der Prozessor 2 dieser
Instruktionen pro Zyklus absetzen kann (oder 4 alle 2 Takte, 6 alle 3
Takte, ...). 1.5 (was in der Silvermont-Architektur nicht vorkommt)
hieße dann wohl 2 parallele Instruktionen alle 3 Takte.

(Also genau das, was ich vermutet hatte)
Post by Bernhard Schornak
Irgendwo in c.l.a.x86 oder a.l.a gab es schon einmal eine diesbe-
zügliche Diskussion, in der es ebenfalls um halbe Taktzyklen ging
- ich kann den entsprechenden Thread leider nicht mehr finden, da
mir inzwischen der Titel entfallen ist (war 2012 oder 2013).
BTW: Für mystische Zahlenspiele dürften sich in de.alt.astrologie
oder de.alt.paranormal sicher recht interessante Gesprächspartner
finden... ;)
Das hat nichts mit Mystik zu tun. Man muss nur lesen und dabei das Hirn
einschalten, Natürlich hilft es beim Lesen, wenn man davon ausgeht, dass
sich die Autoren des Handbuchs etwas dabei gedacht haben und nicht mit
der Einstellung "Intel-Mitarbeiter sind alle Volltrottel" herangeht.

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Bernhard Schornak
2014-12-20 18:03:02 UTC
Permalink
Post by Peter J. Holzer
Post by Bernhard Schornak
"Intel® 64 and IA-32 Architectures Optimization Reference Manual,
Order Number: 248966-020" (veröffentlicht 2009)
Ah, eine Quellenangabe. Danke.
Post by Bernhard Schornak
stammten. Im Gegensatz zu AMD informiert uns iNTEL nicht darüber,
ob sich diese Angaben auf einen Register-Register- oder einen Re-
gister-Speicher-Zugriff beziehen (AMD listet jede Zugriffsform in
einer gesonderten Zeile).
Addendum: In der neuesten 248966-Version von 2011 wird inzwischen
angegeben, dass die 1.5 Takte für XCHG einer Register-Register-Op
entsprechen. Wie der CMPXCHG-Wert zustande kommt, muss man weiter
raten, da weiterführende Angaben nach wie vor fehlen.
In der allerneuesten (248966-30, September 2014) steht auch das drin.
Ja. Das 2011 war aus einem anderen iNTEL-Handbuch, da habe ich
wohl etwas durcheinander gebracht.
Post by Peter J. Holzer
Post by Bernhard Schornak
Generell: Taktangaben sind keine Durchschnittswerte, sondern eine
-exakt- messbare Anzahl von Taktzyklen, die zur Abarbeitung eines
Befehls benötigt werden.
Die aber nicht konstant ist. Hängt teilweise von den Operanden ab (z.B.
bei DIV) und bei superskalaren out-of-order Architekturen natürlich auch
davon, was da sonst so in der Pipeline hängt.
AMD gibt für DIV eine Formel zur Berechnung der tatsächlich zu
veranschlagenden Latenz an. Bei iNTEL sucht man derlei Angaben
vergeblich. Möglicherweise sind sie ja nur sehr gut versteckt,
und man findet sie auf einer nirgendwo angegebenen Seite...
Post by Peter J. Holzer
Post by Bernhard Schornak
Die Abarbeitungszeit jedes Befehls hängt
vom Prozessordesign ab - sie kann vom Hersteller für jeden Befehl
mittels Prozessorsimulation auf den Takt genau bestimmt werden.
Da ein Taktzyklus physikalisch die -kleinste- vorkommende Einheit
ist, kann das Ergebnis eines Befehls niemals nach einem Bruchteil
eines Taktes ausgegeben werden, wie uns iNTELs Angabe suggerieren
möchte - das ist physikalisch unmöglich!
In 248966-30, Kapitel 15.4 gibt es eine Spalte "Throughput" und eine
Spalte "Latency". Die "krummen" Taktzahlen kommen ausschließlich in der
| Throughput value listed as “n/m”, where ‘m’ ops can be dispatched
| every ‘n’ cycle.
Wenn dort also 0.5 steht, dann heißt das, dass der Prozessor 2 dieser
Instruktionen pro Zyklus absetzen kann (oder 4 alle 2 Takte, 6 alle 3
Takte, ...). 1.5 (was in der Silvermont-Architektur nicht vorkommt)
hieße dann wohl 2 parallele Instruktionen alle 3 Takte.
"Der Prozessor" könnte mit Sicherheit auch 2*n solcher Befehle
pro Takt abarbeiten, wenn seine n Kernen zufällig simultan den
selben Befehl ausführen. Unsere Diskussion bezog sich aber auf
eine einzige Executionpipe eines einzigen Kerns, nicht auf die
Gesamtheit aller Kerne/Prozessoren eines komplexen Systems. Es
ist also müssig, plötzlich den ganzen Kern zu bemühen, da eine
einzelne Executionpipe den angegebenen Durchsatz nicht bringen
kann.
Post by Peter J. Holzer
(Also genau das, was ich vermutet hatte)
Ditto.
Post by Peter J. Holzer
Post by Bernhard Schornak
BTW: Für mystische Zahlenspiele dürften sich in de.alt.astrologie
oder de.alt.paranormal sicher recht interessante Gesprächspartner
finden... ;)
Das hat nichts mit Mystik zu tun. Man muss nur lesen und dabei das Hirn
einschalten, Natürlich hilft es beim Lesen, wenn man davon ausgeht, dass
sich die Autoren des Handbuchs etwas dabei gedacht haben und nicht mit
der Einstellung "Intel-Mitarbeiter sind alle Volltrottel" herangeht.
Für mich war dieses (von Dir ja geschickt herausgeschnippte)
Zitat Deines vorhergehenden Beitrags
Post by Peter J. Holzer
Post by Bernhard Schornak
Damit bleibt mir nur noch "386" zu sagen, und damit meine
ich auch nicht den Intel-Prozessor.
ein Musterbeispiel für Zahlenmystik. Die - ganz nebenbei be-
merkt - weder mit Handbücher schreibenden iNTEL-Mitarbeitern
noch mit mir etwas zu tun hat. Als CB-Funker sind mir sicher
die üblichen Zahlenkürzel aus der Funkersprache bekannt, die
sind aber ebenso aus einem - dem Rest der Welt unbekannten -
Fachjargon entnommen wie Dein "386". Ich könnte jetzt ja mal
wild zu spekulieren anfangen und Dein 386 (analog zu den von
Neonazis verwendeten Zahlenspielereien) zu CHF umdeuten. Das
lasse ich aber tunlichst bleiben, da es 1. unerquicklich ist
und 2. wertvolle Zeit vergeudet.


Schönes Wochenende

Bernhard Schornak
Peter J. Holzer
2014-12-20 22:30:04 UTC
Permalink
Post by Bernhard Schornak
Post by Peter J. Holzer
Die Abarbeitungszeit jedes Befehls hängt vom Prozessordesign ab -
sie kann vom Hersteller für jeden Befehl mittels Prozessorsimulation
auf den Takt genau bestimmt werden.
Da ein Taktzyklus physikalisch die -kleinste- vorkommende Einheit
ist, kann das Ergebnis eines Befehls niemals nach einem Bruchteil
eines Taktes ausgegeben werden, wie uns iNTELs Angabe suggerieren
möchte - das ist physikalisch unmöglich!
In 248966-30, Kapitel 15.4 gibt es eine Spalte "Throughput" und eine
Spalte "Latency". Die "krummen" Taktzahlen kommen ausschließlich in der
| Throughput value listed as “n/m”, where ‘m’ ops can be dispatched
| every ‘n’ cycle.
Wenn dort also 0.5 steht, dann heißt das, dass der Prozessor 2 dieser
Instruktionen pro Zyklus absetzen kann (oder 4 alle 2 Takte, 6 alle 3
Takte, ...). 1.5 (was in der Silvermont-Architektur nicht vorkommt)
hieße dann wohl 2 parallele Instruktionen alle 3 Takte.
"Der Prozessor" könnte mit Sicherheit auch 2*n solcher Befehle
pro Takt abarbeiten, wenn seine n Kernen zufällig simultan den
selben Befehl ausführen. Unsere Diskussion bezog sich aber auf
eine einzige Executionpipe eines einzigen Kerns, nicht auf die
Gesamtheit aller Kerne/Prozessoren eines komplexen Systems.
Ach deswegen erwähnst Du dauernd "mehrere Pipelines". Etwas gewundert
hat mich das schon, aber ich dachte, Du stellst Dir eine superskalare
Architektur so vor, dass da ein Kern mehrere Pipelines hat, die er
parallel abarbeitet.

Nein, wir reden von einem Kern mit einer Pipeline. In jedem Takt liest
der Kern (bis zu) 4 Instruktionen und schiebt die in die Pipeline. Die
werden dann dekodiert und in jedem Takt können (bis zu) 8
Mikroinstruktionen weitergereicht werden. Die werden dann abgearbeitet,
wobei manches parallel geht (zwei Additionen z.B.) manches umsortiert
werden kann (z.B. können "spätere" Register-Operationen vorgezogen
werden, während eine Lese-Operation auf das Memory wartet), manches
spekulativ ausgeführt wird (Operationen hinter einem bedingten Sprung)
und manches muss halt seriell ausgeführt werden.

Und ja, das heißt, dass ein Kern zwei der Instruktionen, bei denen im
Manual 0.5 steht, im gleichen Takt abarbeiten kann (und noch zwei
andere). Generell kann man diese Zahlen (weder Throughput noch Latency)
nicht einfach addieren, um herauszufinden, wie lange eine
Instruktionssequenz dauert, weil da eben viel parallel abgearbeitet
wird.

(Bei Hyperthreading wird es noch ein bisschen komplizierter, aber das
können wir ignorieren)
Post by Bernhard Schornak
Es ist also müssig, plötzlich den ganzen Kern zu bemühen, da eine
einzelne Executionpipe den angegebenen Durchsatz nicht bringen kann.
Mir ist unklar, was Du hier mit "ganzem Kern" meinst.
Post by Bernhard Schornak
Post by Peter J. Holzer
(Also genau das, was ich vermutet hatte)
Ditto.
Sehr seltsam.
Post by Bernhard Schornak
Post by Peter J. Holzer
BTW: Für mystische Zahlenspiele dürften sich in de.alt.astrologie
oder de.alt.paranormal sicher recht interessante Gesprächspartner
finden... ;)
Das hat nichts mit Mystik zu tun. Man muss nur lesen und dabei das Hirn
einschalten, Natürlich hilft es beim Lesen, wenn man davon ausgeht, dass
sich die Autoren des Handbuchs etwas dabei gedacht haben und nicht mit
der Einstellung "Intel-Mitarbeiter sind alle Volltrottel" herangeht.
Für mich war dieses (von Dir ja geschickt herausgeschnippte)
Zitat Deines vorhergehenden Beitrags
Post by Peter J. Holzer
Damit bleibt mir nur noch "386" zu sagen, und damit meine
ich auch nicht den Intel-Prozessor.
ein Musterbeispiel für Zahlenmystik.
Du verstehst offensichtlich unter Zahlenmystik etwas anderes als ich.

Aber darauf hatte ich Deine Anmerkung nicht bezogen, sondern auf die
Angaben in den Intel-Manuals (da Du Intel ja schon vorher mit Glauben in
Verbindung gebracht hast).
Post by Bernhard Schornak
Die - ganz nebenbei be- merkt - weder mit Handbücher schreibenden
iNTEL-Mitarbeitern noch mit mir etwas zu tun hat. Als CB-Funker sind
mir sicher die üblichen Zahlenkürzel aus der Funkersprache bekannt,
die sind aber ebenso aus einem - dem Rest der Welt unbekannten -
Fachjargon entnommen wie Dein "386".
Fein erkannt. Nach Deinem Vorwurf, ich würde Abkürzungen in vollkommen
unüblicher und unverständlicher Weise gebrauchen, und nachdem ich
bemerkt hatte, dass http://xkcd.com/386/ eine Nummer hat, die hier jeder
(inklusive mir selbst) mit etwas anderem in Verbindung bringen würde,
konnte ich der Versuchung nicht widerstehen, deinen Vorwurf wahr zu
machen, indem ich "386" ohne Erklärung erwähne.

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Bernhard Schornak
2014-12-21 12:03:47 UTC
Permalink
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
Die Abarbeitungszeit jedes Befehls hängt vom Prozessordesign ab -
sie kann vom Hersteller für jeden Befehl mittels Prozessorsimulation
auf den Takt genau bestimmt werden.
Da ein Taktzyklus physikalisch die -kleinste- vorkommende Einheit
ist, kann das Ergebnis eines Befehls niemals nach einem Bruchteil
eines Taktes ausgegeben werden, wie uns iNTELs Angabe suggerieren
möchte - das ist physikalisch unmöglich!
In 248966-30, Kapitel 15.4 gibt es eine Spalte "Throughput" und eine
Spalte "Latency". Die "krummen" Taktzahlen kommen ausschließlich in der
| Throughput value listed as “n/m”, where ‘m’ ops can be dispatched
| every ‘n’ cycle.
Wenn dort also 0.5 steht, dann heißt das, dass der Prozessor 2 dieser
Instruktionen pro Zyklus absetzen kann (oder 4 alle 2 Takte, 6 alle 3
Takte, ...). 1.5 (was in der Silvermont-Architektur nicht vorkommt)
hieße dann wohl 2 parallele Instruktionen alle 3 Takte.
"Der Prozessor" könnte mit Sicherheit auch 2*n solcher Befehle
pro Takt abarbeiten, wenn seine n Kernen zufällig simultan den
selben Befehl ausführen. Unsere Diskussion bezog sich aber auf
eine einzige Executionpipe eines einzigen Kerns, nicht auf die
Gesamtheit aller Kerne/Prozessoren eines komplexen Systems.
Ach deswegen erwähnst Du dauernd "mehrere Pipelines". Etwas gewundert
hat mich das schon, aber ich dachte, Du stellst Dir eine superskalare
Architektur so vor, dass da ein Kern mehrere Pipelines hat, die er
parallel abarbeitet.
Was sowohl bei AMD als auch bei iNTEL seit Ewigkeiten der Fall
ist. Bulldozer hat 4 Integer- und 4 Fliesskommapipes pro Kern,
wobei letztere bei AVX-Befehlen mit den 4 Fliesskommapipes des
zweiten Kerns der Einheit (Unit) zusammengeschaltet werden, in
den aktuellen iNTEL-Prozessoren werkeln mindestens drei (Sandy
Bridge) Integer- und sechs Fliesskommapipes pro Kern. Jede der
Pipes ist zwar für spezifische Aufgaben reserviert, simple OPs
können aber (zumindest beim Bulldozer) auf allen Pipes abgear-
beitet werden, z.B. MOV reg,reg und ähnliche.
Post by Peter J. Holzer
Nein, wir reden von einem Kern mit einer Pipeline.
Ach? Ausser Dir tut das eigentlich niemand, da seit mindestens
fünfzehn Jahren alle auf dem Markt angebotenen x86-Prozessoren
mindestens zwei Integer- und eine Fliesskommapipe haben:

http://arstechnica.com/features/2001/05/p4andg4e/
http://archive.arstechnica.com/cpu/3q99/k7_theory/k7-one-1.html
Post by Peter J. Holzer
In jedem Takt liest
der Kern (bis zu) 4 Instruktionen und schiebt die in die Pipeline. Die
werden dann dekodiert und in jedem Takt können (bis zu) 8
Mikroinstruktionen weitergereicht werden. Die werden dann abgearbeitet,
wobei manches parallel geht (zwei Additionen z.B.) manches umsortiert
werden kann (z.B. können "spätere" Register-Operationen vorgezogen
werden, während eine Lese-Operation auf das Memory wartet), manches
spekulativ ausgeführt wird (Operationen hinter einem bedingten Sprung)
und manches muss halt seriell ausgeführt werden.
Und ja, das heißt, dass ein Kern zwei der Instruktionen, bei denen im
Manual 0.5 steht, im gleichen Takt abarbeiten kann (und noch zwei
andere). Generell kann man diese Zahlen (weder Throughput noch Latency)
nicht einfach addieren, um herauszufinden, wie lange eine
Instruktionssequenz dauert, weil da eben viel parallel abgearbeitet
wird.
(Bei Hyperthreading wird es noch ein bisschen komplizierter, aber das
können wir ignorieren)
http://www.anandtech.com/show/4955/the-bulldozer-review-amd-fx8150-tested/2
http://www.realworldtech.com/haswell-cpu/4/

Jeglicher Kommentar erübrigt sich damit im Prinzip.

NUR: Kein Mensch addiert Durchsätze und Latenzzeiten eines und
des selben Befehls - es sei denn, er steht in zwei aufeinander
folgenden Zeilen des Quellcodes (z.B. zwei NOPs, die intern in
XCHG rAX,rAX umgewandelt werden).

UND: Aus einem Durchsatz von angeblich "0,5 Takten" lässt sich
ganz bestimmt nicht ableiten, dass neben diesem nach angeblich
0,5 Takten ausgegebenen Ergebnis simultan zusätzlich noch zwei
weitere Befehle im selben Takt und der selben Pipe verarbeitet
werden. Wie soll das physikalisch funktionieren?
Post by Peter J. Holzer
Post by Bernhard Schornak
Post by Peter J. Holzer
BTW: Für mystische Zahlenspiele dürften sich in de.alt.astrologie
oder de.alt.paranormal sicher recht interessante Gesprächspartner
finden... ;)
Das hat nichts mit Mystik zu tun. Man muss nur lesen und dabei das Hirn
einschalten, Natürlich hilft es beim Lesen, wenn man davon ausgeht, dass
sich die Autoren des Handbuchs etwas dabei gedacht haben und nicht mit
der Einstellung "Intel-Mitarbeiter sind alle Volltrottel" herangeht.
Für mich war dieses (von Dir ja geschickt herausgeschnippte)
Zitat Deines vorhergehenden Beitrags
Post by Peter J. Holzer
Damit bleibt mir nur noch "386" zu sagen, und damit meine
ich auch nicht den Intel-Prozessor.
ein Musterbeispiel für Zahlenmystik.
Du verstehst offensichtlich unter Zahlenmystik etwas anderes als ich.
Man könnte anhand der Sachlage durchaus darauf schliessen.
Post by Peter J. Holzer
Aber darauf hatte ich Deine Anmerkung nicht bezogen, sondern auf die
Angaben in den Intel-Manuals (da Du Intel ja schon vorher mit Glauben in
Verbindung gebracht hast).
Bitte bezieh Dich auf das, was ich geschrieben habe, und nicht
auf das, von dem Du glaubst, dass ich es unter Umständen hätte
gemeint haben könnte...


Grüsse aus Augsburg

Bernhard Schornak
Peter J. Holzer
2014-12-21 12:14:37 UTC
Permalink
nach angeblich 0,5 Takten ausgegebenen Ergebnis
Du hast es noch immer nicht kapiert. Ich gebe es auf.

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Bernhard Schornak
2014-12-21 13:21:51 UTC
Permalink
Post by Peter J. Holzer
nach angeblich 0,5 Takten ausgegebenen Ergebnis
Du hast es noch immer nicht kapiert. Ich gebe es auf.
Mag daran liegen, dass ich nicht an Magie glaube, und Deine
bisherigen Ausführungen nicht angetan waren, zur Lösung der
diskutierten Streitpunkte beizutragen. Abgesehen davon kann
man nichts aufgeben, das man nie begonnen hat...


Grüsse aus Augsburg

Bernhard Schornak

Jan Bruns
2014-12-18 04:21:01 UTC
Permalink
Post by Peter J. Holzer
1.5 Takte, wenn mit einer anderen CPU kommuniziert werden muss? Die
Zeitangabe bezieht sich wohl auf ein XCHG von zwei Registern im selben
Core, aber ganz sicher nicht auf einen Speicherzugriff.
Oder auf neuartige Logikgatter, die bei steigenden und fallenden Flanken
des Taktsignals schalten.
Logikgatter schalten für gewöhnlich bei beliebigen Änderungen an
den Eingängen, völlig unabhängig von irgendwelchen Takten.

Deshalb nennt man allein aus Logikbausteinen aufgebaute Schaltungen
auch "rein kombinatorisch".

Taktsignale werden verwendet, um für Speicherelemente (FlipFlops)
ein Zeitfenster zu schaffen, in dem sie von ihrer eigentlichen
SpeicherfFunktion abweichend mit neuen Werten geladen werden können.

Dabei spricht (soweit ich weiss) prinzipiell rein gar nichts
dagegen, diese Zeitfenster an beiden Flanken eines Taktsignals
auszurichten.

Wenn man das erreichen will, jedoch aus irgendwelchen Gründen nur
auf Einzelflanken reagierende Speicherlemente verwenden kann (z.B.
weil das einfach eine so selten benötigte Funktionalität ist, daß
das DDR-Teil nicht in der Bauteilbibliothek verfügbar ist), dann
kann man so ein DDR-FlipFlop aufbauen, indem man zwei der verfüg-
baren Speicherelemente verwendet, und entsprechend beschaltet (in
die nachfolgende kombinatorische Schaltung absorbiert).

Gruss

Jan Bruns
Bernhard Schornak
2014-12-18 16:20:18 UTC
Permalink
Post by Jan Bruns
Post by Peter J. Holzer
1.5 Takte, wenn mit einer anderen CPU kommuniziert werden muss? Die
Zeitangabe bezieht sich wohl auf ein XCHG von zwei Registern im selben
Core, aber ganz sicher nicht auf einen Speicherzugriff.
Oder auf neuartige Logikgatter, die bei steigenden und fallenden Flanken
des Taktsignals schalten.
Logikgatter schalten für gewöhnlich bei beliebigen Änderungen an
den Eingängen, völlig unabhängig von irgendwelchen Takten.
Richtig. Wieviele Prozessoren bestehen ausschliesslich aus
Invertern, AND-, NAND-, OR-, NOR- und XOR-Gattern, die un-
abhängig von einem Takt arbeiten? Welcher Speicherbaustein
auf einem IC funktioniert ohne Takt? Wenn ich mich richtig
erinnere, benötigten auch die analogen Eimerkettenspeicher
einen Takt, mit dem die Kondensatorladungen weitergereicht
werden mussten, da sie sonst verloren gingen.
Post by Jan Bruns
Deshalb nennt man allein aus Logikbausteinen aufgebaute Schaltungen
auch "rein kombinatorisch".
http://tinyurl.com/qd27ql7
Post by Jan Bruns
Taktsignale werden verwendet, um für Speicherelemente (FlipFlops)
ein Zeitfenster zu schaffen, in dem sie von ihrer eigentlichen
SpeicherfFunktion abweichend mit neuen Werten geladen werden können.
Dabei spricht (soweit ich weiss) prinzipiell rein gar nichts
dagegen, diese Zeitfenster an beiden Flanken eines Taktsignals
auszurichten.
http://tinyurl.com/p4ynptr
(=> zweiflankengesteuerte Flipflops)
Post by Jan Bruns
Wenn man das erreichen will, jedoch aus irgendwelchen Gründen nur
auf Einzelflanken reagierende Speicherlemente verwenden kann (z.B.
weil das einfach eine so selten benötigte Funktionalität ist, daß
das DDR-Teil nicht in der Bauteilbibliothek verfügbar ist), dann
kann man so ein DDR-FlipFlop aufbauen, indem man zwei der verfüg-
baren Speicherelemente verwendet, und entsprechend beschaltet (in
die nachfolgende kombinatorische Schaltung absorbiert).
http://tinyurl.com/komp56x

Das scheint 1. noch nicht ganz augereift und 2. noch nicht
besonders schnell (100 - 400 MHz) zu sein. Wie die Ausgabe
von zwei Ergebnissen pro Taktzyklus funktioniert, wenn nur
je ein Ausgang und ein Eingang der nächsten Stufe der Pipe
zur Verfügung stehen, wäre damit allerdings nicht geklärt.
Welche aktuellen Desktop-Prozessoren verwenden diese Tech-
nologie tatsächlich?


Grüsse aus Augsburg

Bernhard Schornak
Jan Bruns
2014-12-05 03:18:11 UTC
Permalink
Hallo.

Übrigens, der Code scheint zu funktionieren (soweit
ich das testen konnte), wenn ich den wie unten gezeigt
so abändere, daß lockObj() nur von einem Kern
ausgeführt wird (unlockObj() unverändert).

Ein Zusammenhang mit meinen Datenstrukturen zum
Handling der "waitchain" scheint unwahrscheinlich,
weil der Fehler wieder auftaucht, wenn ich die
critical section auf den Bereich "another AP
has the lock" beschränke.

Anscheinend müssen eher die Interlocked*
Operationen single-core sein. Warum wohl?

Gruss

Jan Bruns




procedure TparlocCol.lockObj(o : Toid; ap : TparlocAP);
var ap2 : TparlocAP; a, wc, old : longint; lv : Plongint;
begin
RTLeventResetEvent(ap.locksig);
lv := locate_locvar(o);
enter_cs;
repeat
// assume there currently is no lock
a := (ap.id shl lsb_lock_holder) + 1;
old := InterlockedCompareExchange(lv^,a,0);
if (old=0) then break
else begin
a := (old shr lsb_lock_holder) and apidmask;
if (a = ap.id) then begin
{ we already have the lock. just inc. }
a := old and lockcountmask;
if (a>=lockcountlimit) then begin
raise parlocAPexcpt.Create('Too many locks on object.');
end else begin
a := InterlockedCompareExchange(lv^,old+1,old);
if (a=old) then break;
end;
end else begin
{ another AP has the lock. try linking into
the chain of waiters. }
wc := (old shr lsb_lock_waiter) and apidmask;
if (wc=0) then begin
wc := start_new_waitchain(o,ap);
a := old or (wc shl lsb_lock_waiter);
a := InterlockedCompareExchange(lv^,a,old);
if (a=old) then begin
unlock_waitchain(wc);
leave_cs;
wait_waitchain(wc,o,ap);
exit;
end else discard_waitchain(wc); // and retry
end else begin
if try_append_waitchain(wc,o,ap) then begin
leave_cs;
wait_waitchain(wc,o,ap);
exit;
end; // else retry
end;
end;
end;
until false;
leave_cs;
end;
Peter J. Holzer
2014-12-06 07:40:17 UTC
Permalink
Post by Jan Bruns
Übrigens, der Code scheint zu funktionieren (soweit
ich das testen konnte), wenn ich den wie unten gezeigt
so abändere, daß lockObj() nur von einem Kern
ausgeführt wird (unlockObj() unverändert).
Ein Zusammenhang mit meinen Datenstrukturen zum
Handling der "waitchain" scheint unwahrscheinlich,
weil der Fehler wieder auftaucht, wenn ich die
critical section auf den Bereich "another AP
has the lock" beschränke.
Anscheinend müssen eher die Interlocked*
Operationen single-core sein. Warum wohl?
Ich habe eher den Verdacht, dass Du irgendwo im waitchain-Handling einen
Fehler hast. Den Code verstehe ich nämlich nicht, soweit Du ihn gezeigt
hast (ein paar Kommentare im Code würden wirklich nicht schaden), und
den Inhalt der Funktionen hast Du nicht gezeigt.

Dadurch, dass Du lockObj auf eine CPU zwingst, läuft auch das ganze
waitchain-Handling nur mehr auf einer CPU und damit seriell.

Das cmpxchng auf Deinem System (CPU+Memory-Controller) buggy ist, kann
man zwar nicht 100% ausschließen, ist aber doch ziemlich
unterschiedlich. Das würde nämlich jedes Betriebssystem und jede
Multithreading-Library (und jedes Programm, das sie verwendet),
ebenfalls betreffen.

hp
--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | | Man feilt solange an seinen Text um, bis
| | | ***@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
Jan Bruns
2014-12-07 01:22:40 UTC
Permalink
Post by Peter J. Holzer
Anschinend müssen eher die Interlocked* Operationen single-core sein.
Warum wohl?
Ich habe eher den Verdacht, dass Du irgendwo im waitchain-Handling einen
Fehler hast. Den Code verstehe ich nämlich nicht, soweit Du ihn gezeigt
hast (ein paar Kommentare im Code würden wirklich nicht schaden), und
den Inhalt der Funktionen hast Du nicht gezeigt.
Danke. Sowas hatte ich gehofft hier zu lesen. Im offenbar ziemlich
gleiczeitig versandtem "Auflösungbeitrag" hat sich ja inzwischen schon
herausgestellt, daß Du mit deiner Vermutung recht hattest.
Post by Peter J. Holzer
Dadurch, dass Du lockObj auf eine CPU zwingst, läuft auch das ganze
waitchain-Handling nur mehr auf einer CPU und damit seriell.
Das cmpxchng auf Deinem System (CPU+Memory-Controller) buggy ist, kann
man zwar nicht 100% ausschließen, ist aber doch ziemlich
unterschiedlich. Das würde nämlich jedes Betriebssystem und jede
Multithreading-Library (und jedes Programm, das sie verwendet),
ebenfalls betreffen.
Das ist ja der Fall: In den letzten Jahren hatten derart viele
Anwendungen daerart häufig irgendwelche von den Anwendungsentwicklern
so sicherlich nicht geplante Verhaltensweisen, daß sich wahrlich nicht
der Eindruck einstellt, es würde alles bestens zusammenspielen.

Weiter wäre unter der Annahme, daß derart offensichtliche
Kohärenzfehler bei "lock cmpxchg" bei CPUs mit signifikantem
Verbreitungsgrad vorhanden sind, diese Information sicherlich
auch zu den Entwicklern von multithreading libraries durchgedrungen
(das habe ich ja ich so schnell nicht überblick, wann dort dort was
für workarounds wurde). Aus der Ecke hatte ich eher so die vage
Hintergrundinformaion, daß bei nackten lowlevel Synchronisations-
Elementen allgemein mit Unzuverlässigem Verhalten zu rechnen ist
(da überzeugt dann auch eine breite Masse an Meldungen erfolgreicher
Anwendungen nicht wirklich).

Ich dachte mir ferner, zu Zeiten, als dieses Lock-Präfix erdacht wurde,
hatte man auch allgemein andere Sorgen, als die Multibusmaster Kohärenz
speziell von adressierten Datenelementen. Allenfalls wird man an, so
dachte ich, an halbfertige, mehrzyklige Schreiboperationen gedacht
haben. Das stimmt aber so nicht, im 8086 Benutzerhandbuch wird bereits
die Verwendung des LOCK-Preäfixes in Verbindung mit dem XCHG-Befehl
zur Implementation von Semaphores/Locks beschrieben.

Gruss

Jan Bruns
Jan Bruns
2014-12-06 07:44:58 UTC
Permalink
Post by Jan Bruns
if try_append_waitchain(wc,o,ap) then begin
Ah! Das Ding hat nicht beachtet, daß diese waitchains nicht nur schon
längst abgearbeitet sein können, sondern auch bereits recycelt.

Die Welt braucht dringend mehr Überrundungszähler.

Also kann ich jetzt über Optimierungen nachdenken.
Momentan sehe ich so bestenfalls ca. 4 Mio. Lock Operationen pro
Sekunde (auf AMD-350, lowcost Laptop CPU). Das ist eigentlich auch
schon, was ich mir ursprünglich auch ausgemalt hatte, kann ja
so nur nur noch besser gehen.

Jedenfalls sieht es so aus, als würde die CPU so funktionieren,
wie anfangs gedacht, ohne irgendwelche derart leicht zu findende
Kohärenz-Fehler. Wunderbar.

Gruss

Jan Bruns
Loading...