2013-05-11 5 views
6

In meiner Klasse für eingebettete Systeme wurden wir gebeten, die gegebene C-Funktion AbsVal in ARM Assembly umzucodieren. Uns wurde gesagt, dass das Beste, was wir tun konnten, 3 Zeilen war. Ich war entschlossen, eine 2-Linien-Lösung zu finden und schließlich tat, aber die Frage, die ich jetzt habe, ist, ob ich tatsächlich die Leistung verringert oder erhöht es.ARM Assembly: Absoluter Wert Funktion: Sind zwei oder drei Zeilen schneller?

Der C-Code:

unsigned long absval(signed long x){ 
    unsigned long int signext; 
    signext = (x >= 0) ? 0 : -1; //This can be done with an ASR instruction 
    return (x + signet)^signext; 
} 

Die 3-line-Lösung von TA/Professor

ASR R1, R0, #31   ; R1 <- (x >= 0) ? 0 : -1 
ADD R0, R0, R1   ; R0 <- R0 + R1 
EOR R0, R0, R1   ; R0 <- R0^R1 

Meine 2-Line-Lösung

ADD R1, R0, R0, ASR #31 ; R1 <- x + (x >= 0) ? 0 : -1 
EOR R0, R1, R0, ASR #31 ; R0 <- R1^(x >= 0) ? 0 : -1 

Es gibt ein paar Orte, die ich mögliche Leistungsunterschiede sehen:

  1. Die Zugabe eines zusätzlichen Arithmetic Rechts Anruf

So holen

  • Die Entfernung eines Speicher verschieben, was man eigentlich ist schneller? Kommt es auf die Prozessor- oder Speicherzugriffsgeschwindigkeit an?

  • +1

    Warum nicht Benchmarks? Das ist der sicherste Weg, den Leistungsunterschied zu kennen. – jpaugh

    +0

    Ich würde das total machen, aber ich werde nur in diese Konzepte eingeführt. Ich kann den Prof bitten, mir bei einem Benchmark zu helfen, aber vor allem zu wissen, warum es schneller oder langsamer sein soll, ist mein Ziel. Nicht sicher, ob Benchmarking die Phasenzeit abrufen/ausführen zeigt oder Register/ALU-Zugriffe –

    +2

    Es hängt von den Implementierungen ab. Kerne vor A8 werden Ihren Code wahrscheinlich schneller ausführen, die Verschiebung ist normalerweise kostenlos, es sei denn, Ihr Verschiebewert befindet sich in einem Register. A8 und neuere Kerne haben mehrere Pipelines, die eine parallele Ausführung erlauben könnten, die beide sogar in Zyklen machen könnten, Sie könnten http://pulsar.webshaker.net/ccc/result.php?lng=us ausprobieren. –

    Antwort

    4

    Tauchen Sie zu ARM.com und greifen Sie auf die Cortex-M3 datasheet. Abschnitt 3.3.1 auf Seite 3-4 enthält die Instruktionszeiten. Glücklicherweise sind sie auf dem Cortex-M3 recht einfach.

    Wir von diesen Zeitpunkt sehen, dass in einem perfekten ‚keinen Staat warten‘ -System Beispiel Ihres Professors 3 Zyklen dauert:

    ASR R1, R0, #31   ; 1 cycle 
    ADD R0, R0, R1   ; 1 cycle 
    EOR R0, R0, R1   ; 1 cycle 
             ; total: 3 cycles 
    

    und Ihre Version dauert zwei Zyklen:

    ADD R1, R0, R0, ASR #31 ; 1 cycle 
    EOR R0, R1, R0, ASR #31 ; 1 cycle 
             ; total: 2 cycles 
    

    So Ihre ist theoretisch schneller.

    Sie erwähnen "Die Entfernung von einem Speicher holen", aber ist das wahr? Wie groß sind die jeweiligen Routinen? Da es sich um Thumb-2 handelt, steht eine Mischung aus 16-Bit- und 32-Bit-Anweisungen zur Verfügung. Mal sehen, wie sie zusammenzubauen:

    Ihre Version (bereinigt um die UAL-Syntax):

    .syntax unified 
        .text 
        .thumb 
    abs: 
        asrs r1, r0, #31 
        adds r0, r0, r1 
        eors r0, r0, r1 
    

    Baut auf:

    00000000  17c1 asrs r1, r0, #31 
    00000002  1840 adds r0, r0, r1 
    00000004  4048 eors r0, r1 
    

    Das 3x2 = 6 Bytes ist.

    Ihre Version (wieder bereinigt um UAL-Syntax):

    .syntax unified 
        .text 
        .thumb 
    abs: 
        add.w r1, r0, r0, asr #31 
        eor.w r0, r1, r0, asr #31 
    

    Baut auf:

    00000000 eb0071e0 add.w r1, r0, r0, asr #31 
    00000004 ea8170e0 eor.w r0, r1, r0, asr #31 
    

    Das 2x4 = 8 Bytes ist.

    Anstatt einen Speicherabruf zu entfernen, haben Sie die Größe des Codes tatsächlich erhöht.

    Beeinträchtigt dies jedoch die Leistung? Mein Tipp wäre Benchmark.

    +0

    genial! Vielen Dank! –

    5

    ist hier eine nother zwei Befehlsausführung:

    cmp  r0, #0 
        rsblt r0, r0, #0 
    

    , die zu dem einfachen Code übersetzen:

    if (r0 < 0) 
        { 
        r0 = 0-r0; 
        } 
    

    Dieser Code soll ziemlich schnell, auch auf modernem ARM-CPU-Kern wie der Cortex sein -A8 und A9.

    +0

    Ich werde das im Labor testen, wenn ich als nächstes gehe, und Benchmarks gegen meinen. Wenn es schneller ist, dann werde ich die Antwort akzeptieren :) –

    +0

    stellt sich heraus, dass dies leider nicht auf Thumb-2 zusammenbaut, aber für Arm würde es funktionieren –

    +0

    Nun, ich glaube, die Syntax hat sich geändert, sollte es so aussehen (wow Code in Kommentaren funktioniert nicht wirklich?): '2800 cmp r0, # 0; BFB8 it lt; 4240 rsblt r0, r0, # 0' – Aksel

    Verwandte Themen