Informationen zur Codedichte und ihrer Definition

9

Ich habe eine konzeptionelle Frage: Was bedeutet "hohe" Codedichte? und warum ist es so wichtig?

Quaremz
quelle

Antworten:

23

Die Codedichte bezieht sich lose darauf, wie viele Mikroprozessorbefehle erforderlich sind, um eine angeforderte Aktion auszuführen, und wie viel Platz jeder Befehl einnimmt. Im Allgemeinen ist sein Code umso dichter, je weniger Platz ein Befehl benötigt und je mehr Arbeit pro Befehl ein Mikroprozessor ausführen kann.

Ich stelle fest, dass Sie Ihre Frage mit dem Tag "Arm" versehen haben. Ich kann die Codedichte mithilfe von ARM-Anweisungen veranschaulichen.

Angenommen, Sie möchten einen Datenblock von einer Stelle im Speicher an eine andere kopieren. Konzeptionell würde Ihr High-Level-Code ungefähr so ​​aussehen:

void memcpy(void *dest, void *source, int count_bytes)
{
    char *s, *d;

    s = source; d = dest;
    while(count_bytes--) { *d++ = *s++; }
}

Jetzt kann ein einfacher Compiler für einen einfachen Mikroprozessor dies in etwa Folgendes konvertieren:

movl r0, count_bytes
movl r1, s
movl r2, d
loop: ldrb r3, [r1]
strb [r2], r3
movl r3, 1
add r1, r3
add r2, r3
sub r0, r3
cmp r0, 0
bne loop

(Mein ARM ist etwas rostig, aber Sie haben die Idee)

Dies wäre ein sehr einfacher Compiler und ein sehr einfacher Mikroprozessor, aber Sie können dem Beispiel entnehmen, dass wir 8 Anweisungen pro Iteration der Schleife betrachten (7, wenn wir die '1' in ein anderes Register verschieben und die Last verschieben außerhalb der Schleife). Das ist überhaupt nicht wirklich dicht. Die Codedichte wirkt sich auch auf die Leistung aus. Wenn Ihre Schleifen länger sind, weil der Code nicht dicht ist, benötigen Sie möglicherweise mehr Anweisungscache, um die Schleife zu halten. Mehr Cache bedeutet einen teureren Prozessor, aber andererseits bedeutet komplexe Befehlsdecodierung mehr Transistoren, um den angeforderten Befehl zu entschlüsseln, so dass es sich um ein klassisches technisches Problem handelt.

ARM ist in dieser Hinsicht ziemlich nett. Jeder Befehl kann bedingt sein, die meisten Befehle können den Wert von Registern erhöhen oder verringern, und die meisten Befehle können optional die Prozessorflags aktualisieren. Auf ARM und mit einem mäßig nützlichen Compiler kann dieselbe Schleife ungefähr so ​​aussehen:

movl r0, count_bytes
movl r1, s
movl r2, d
loop: ldrb r3, [r1++]
strb [r2++], r3
subs r0, r0, 1
bne loop

Wie Sie sehen können, besteht die Hauptschleife jetzt aus 4 Anweisungen. Der Code ist dichter, weil jeder Befehl in der Hauptschleife mehr bewirkt. Dies bedeutet im Allgemeinen, dass Sie mit einer bestimmten Speichermenge mehr erreichen können, da weniger davon zur Beschreibung der Ausführung der Arbeit verwendet wird.

Jetzt hatte nativer ARM-Code oft die Beschwerde, dass er nicht sehr dicht sei; Dies hat zwei Hauptgründe: Erstens sind 32 Bit ein schrecklich "langer" Befehl, so dass viele Bits für einfachere Befehle verschwendet zu werden scheinen, und zweitens wurde der Code aufgrund der Natur von ARM aufgebläht: Jeder Befehl ist 32 Bits lang, ohne Ausnahme. Dies bedeutet, dass es eine große Anzahl von 32-Bit-Literalwerten gibt, die Sie nicht einfach in ein Register laden können. Wenn ich "0x12345678" in r0 laden wollte, wie codiere ich eine Anweisung, die nicht nur 0x12345678 enthält, sondern auch "Literal in r0 laden" beschreibt? Es sind keine Bits mehr übrig, um die eigentliche Operation zu codieren. Die ARM-Ladeliteralanweisung ist ein interessantes kleines Biest, und der ARM-Assembler muss auch ein bisschen schlauer sein als normale Assembler, weil er "fangen" muss.

Um diese Beschwerden zu beantworten, hat ARM den Daumenmodus entwickelt. Anstelle von 32 Bit pro Befehl beträgt die Befehlslänge jetzt 16 Bit für fast alle Befehle und 32 Bit für Zweige. Es gab einige Opfer im Thumb-Modus, aber im Großen und Ganzen waren diese Opfer einfach zu bringen, da Thumb Ihnen eine 40% ige Verbesserung der Codedichte brachte, indem Sie nur die Befehlslänge reduzierten.

Akohlsmith
quelle
Hervorragende Antwort. Wirklich ausgezeichnet.
pingswept
Vergessen Sie nicht, Thumb2 zu erwähnen, was für die meisten Anwendungen eine noch größere Verbesserung darstellt.
Yann Ramin
Sehr interessante Lektüre. Ich lerne viel, indem ich nur Fragen und Antworten auf dieser Seite lese.
Onaclov2000
Vielen Dank Andrew, ausgezeichnete Antwort, es hat mir sehr mit meinem Zweifel geholfen :)
Quaremz
Dies könnte auch mit einer kurzen Erwähnung darüber zusammenhängen, wie die Codedichte von RISC im Vergleich zu CISC beeinflusst wird (wobei RISC im Allgemeinen niedriger als CISC ist, da CISC-Architekturen tendenziell mehr Anweisungen enthalten, die mehr können, aber zu längeren / komplexeren Pipelines während RISC führen können konzentriert sich auf einfachere Anweisungen, die einfachere Pipelines ermöglichen, daher ist die RISC-Codedichte geringer.
JAB
1

Die "Codedichte" eines Befehlssatzes ist ein Maß dafür, wie viel Material Sie in eine bestimmte Menge an Programmspeicher aufnehmen können oder wie viele Bytes Programmspeicher Sie benötigen, um eine bestimmte Menge an Funktionalität zu speichern.

Wie Andrew Kohlsmith betonte, können verschiedene Compiler selbst auf derselben MCU unterschiedliche Codedichten erhalten.

Vielleicht lesen Sie gerne "Insekten der Computerwelt" von Miro Samek, in dem verschiedene MCUs verglichen werden.

Davidcary
quelle