MMC Treiber Optimierung mittel Bit Bang Optimierung

Sklaventreiber
Günther
Developer
Beiträge: 587
Registriert: Freitag 9. September 2005, 21:48

Beitrag von Günther »

Nachtrag zum Assembler-Code:

Code: Alles auswählen

     51c:   91 4b 01 04    stw     r10,260(r11) 
     520:   a0 07 00 06    lhz     r0,6(r7) 
     524:   54 00 d0 3e    rotlwi  r0,r0,26 
     528:   50 09 36 72    rlwimi  r9,r0,6,25,25 
     52c:   91 0b 01 04    stw     r8,260(r11) 
Das das lwz länger dauert als das lhz scheint darauf hinzudeuten, daß der Speicher nicht auf ein 4faches 'alligned' ist.
Wenn ein vielfaches von 4 dauert lwz (32bit) lhz (16bit) und lbz (8bit) gleich lang = 1Clock (Vergleiche PPC Manual Table 8-1 + Kapitel 6.6.6 )
Keine Ahnung ob wir auf das allignment Einfluss haben (Kernel).

Das die beiden Assembler-Versionen gleich schnell sind liegt wohl daran das ein stw direkt hintereinander folgt (PPC Manual Table 8-1.):
Although a store (as well as mtspr for special registers external to the core) issued to the load/store unit buffer frees the core pipeline, the next load or store will not actually be performed on the bus until the bus is free.

Deshalb scheint das zusätzliche 'or' sozusagen zeitlich umsonst ausgefhrt werden.

Eventuell läßt sich also mit einem stb und lhb noch Zeit einsparen.
Ausserdem müße das rlwimi nach dem stw ausgefhrt werden. Vielleicht hat just_me ja noch einen genialen Einfall :)

Code: Alles auswählen

     51c:   91 4b 01 04    stw     r10,260(r11) 
     520:   a0 07 00 06    lhz     r0,6(r7) 
     524:   54 00 d0 3e    rotlwi  r0,r0,26 
     52c:   91 0b 01 04    stw     r8,260(r11) 
     528:   50 09 36 72    rlwimi  r9,r0,6,25,25 

     51c:   91 4b 01 04    stw     r10,260(r11) 
     520:   a0 07 00 06    lhz     r0,6(r7) 
     524:   54 00 d0 3e    rotlwi  r0,r0,26 
     52c:   91 0b 01 04    stw     r8,260(r11) 
     528:   50 09 36 72    rlwimi  r9,r0,6,25,25 
Allerdings, die PORT-Register müßten doch im interen Register liegen, da sollte doch kein externer Speicherzugriff erfolgen, oder? Das sollte doch in nullkommanix erledigt sein??? (aber beim PPC ist wahrscheinlich wieder alles anders :()

Also, da scheint doch noch was drin zu sein 8)
Carjay
Developer
Beiträge: 122
Registriert: Sonntag 23. April 2006, 12:37

Beitrag von Carjay »

Moin,

schön, daß du dich da so engagierst. :)

Der Code läßt sich eigentlich auch gut modularisieren zwischen Low und High-Level. Beim 2.6er hatte ich das so aufgeteilt, daß die Bitbanging-Routinen in einer eigenen Datei sind und man den Code so schnell an andere Plattformen anpassen könnte.

Achso, noch etwas: könntest du bitte darauf achten, daß die Source-Dateien nicht das executable-Bit gesetzt haben wenn du sie eincheckst?
Günther
Developer
Beiträge: 587
Registriert: Freitag 9. September 2005, 21:48

Beitrag von Günther »

Carjay hat geschrieben:Achso, noch etwas: könntest du bitte darauf achten, daß die Source-Dateien nicht das executable-Bit gesetzt haben wenn du sie eincheckst?
Jepp, kein Problem.
Carjay hat geschrieben:Der Code läßt sich eigentlich auch gut modularisieren zwischen Low und High-Level. Beim 2.6er hatte ich das so aufgeteilt, daß die Bitbanging-Routinen in einer eigenen Datei sind und man den Code so schnell an andere Plattformen anpassen könnte.
Ja, daran habe ich auch schon gedacht, dann könnte man auch zwischen den unterschiedlichen Pin-Belegung einfacher umgeschalten. Das werde ich ev. mal nach der Optimierungphase machen ;)

Apropos Optimierung - ich hatte keinen Erfolg mit weiteren Optimierungsversuchen (Byte lesen und Byte schreiben).

Code: Alles auswählen

#define SD_CLK_BYTE 0x40
#define SD_DO_BYTE  0x40
void mmc_read_block_low_level(unsigned char *dest)
{
    unsigned char result=0;
    unsigned int i=0;

    volatile iop8xx_t *cpi = (iop8xx_t *) &immap->im_ioport;
    cpi->iop_padat |= SD_DI;

     volatile unsigned char* sd_do =  ((unsigned char*) &immap->im_ioport.iop_padat)+1;
     volatile unsigned char* clk =    ((unsigned char *) &immap->im_cpm.cp_pbdat)+2;
     unsigned char clk_high =  (*clk) | SD_CLK_BYTE;
     unsigned char clk_low =   (*clk) & ~SD_CLK_BYTE;

    for (i = 0; i < 512; i++)
    {
        *clk = clk_high; //1
             result <<= 1;result |= ((*sd_do & SD_DO_BYTE)?0x01:0x00);
        *clk = clk_low;
 ...
        *clk = clk_high; //8
             result <<= 1;result |= ((*sd_do & SD_DO_BYTE)?0x01:0x00);
        *clk = clk_low;

        *dest++ = result;
        result = 0;
    }
}
ergibe zwar

Code: Alles auswählen

        *clk = clk_high; //7
     2c4:	98 ca 00 00 	stb     r6,0(r10)
             result <<= 1;result |= ((*sd_do & SD_DO_BYTE)?0x01:0x00);
     2c8:	89 68 00 00 	lbz     r11,0(r8)
     2cc:	55 29 d7 fe 	rlwinm  r9,r9,26,31,31
     2d0:	54 00 08 3c 	rlwinm  r0,r0,1,0,30
        *clk = clk_low;
     2d4:	98 ea 00 00 	stb     r7,0(r10)
     2d8:	7d 20 03 78 	or      r0,r9,r0
aber keine Zeitverbesserung (immer noch 31 Sekunden für 10 MB)

Da läßt sich wohl nichts mehr machen. Deshalb meine derzeitige Empfehlung die Leseoptimierung 3 bzw. 10 zu verwenden. Die sind noch in C und besser wartbar.



Günther
Günther
Developer
Beiträge: 587
Registriert: Freitag 9. September 2005, 21:48

Beitrag von Günther »

Ich bin jetzt der ganzen Sache mal mit einem Oszi auf den Grund gegangen. Es sieht so aus, als ob die Buszugriffzeiten verhinden, daß es ev. schneller geht. Lesen oder schreiben (stb, ldb) 'verbraucht' 5 Takte wenn direkt dahinter wieder ein Buszugriff erfolgt. Nachfolgende Register-Befehle können allerdings direkt ausgeführt werden.
Müßte das denn nicht schneller als 5 Takt gehen :gruebel: - vielleicht kann da ein Busexperte etwas zu sagen (ev. lassen sich die allgemeinen Timingeinstellungen noch optimieren :gruebel: ). Falls da nichts zu machen ist, wäre die Bit-Bangoptimierung hiermit nämlich abgeschlossen - ausser jemanden kommt noch ein ganz anderer genialer Gedanke ...

Hier die Messung - vielleicht hilft es bei anderen Optimierungen (liest überhaupt noch jemand mit :lol: ?). Treiber mmc2test.c mit Leseoptimierung 12. Über bzw. unter jeden Taktzyklus habe ich die Zeitdauer bzw. die ausgeführten Assemblerbefehler geschrieben.

Code: Alles auswählen

          Bit
   |1.     |2.     |3.     |4.     |5.     |6.     |7.     |8.              |next byte
 
    150ns   150ns    ...            150    150ns           270ns
    ___     ___     ___     ___     ___     ___     ___     ___              ___             
___|   |___|   |___|   |___|   |___|   |___|   |___|   |___|   |____________|   |___|  
        75ns    75ns    ...             75      75ns                 600ns

    stb stb stb stb ...             stb stb stb stb         stb      stb
    ldb     ldb     ...             ldb or  ldb or          lbz      stb
                                    rlw     rlw             rlw      addi
                                    rlw     rlw             rlw      bdnz+
                                                            or       
                                                            rlw
                                                            rlw
                                                            or
Gesamt: 2475ns = 400kB/s
Core clock: 15ns  (66Mhz)
DBoxBaer
Senior Member
Beiträge: 255
Registriert: Donnerstag 25. August 2005, 11:34

Beitrag von DBoxBaer »

Moin!

Ich habe mal wieder überhaupt keine Zeit, aber....

Über Memory Zugriffe hatte ich ja schon mal referiert: Daher nochmal
ein wenig zu dem Thema:
Wie ist ein PowerPC basierter Prozessor aufgebaut:
Da gibt es nicht nur einen Bus, da sind gleich mehrere. Diese sind
über Bridges miteinander verbunden. Eine Bridge transportiert dabei
Zugriffe von dem einen Bus auf den anderen und gleicht so z.B.
verschiedene Geschwindigkeiten aus.
Der Bus am Core selbst ist dabei am schnellsten, meistens sind
alle anderen dann (deutlich) langsamer.

Ein Blick auf das Blockschaltbild des 823 zeigt diese dann auch
schön:
Der Core hängt an einem Bus zusammen mit Cache, SIU und
einem Slave und einen Master Interface.
Das Slave Interface ist eine Bridge zum "CPM Local Bus", und an
diesem hängt auch der Block "Parallel IO".

Leider habe ich auf die schnelle nicht herausgefunden, wie dieser
CPM Local Bus getaktet ist, aber ich kann mir gut vorstellen, das
es deutlich langsamer ist: Zugriffe zum Pin-Wackeln wird man
aber nicht schneller bekommen, als eben dieser interne Bus
hergibt.Selbst wenn er mit 66MHz getaktet ist, kann es sein, das
dort z.B. Edit: 5 Takte pro Zugriff benötigt werden, weil es eben auch
ein einfacherer Bus ist... Das wären dann 75ns, die ich mir mal
daher so erkläre...

Immerhin wäre das schneller als ein Lesezugriff auf meinen
CPLD, der kostet mindestens 90ns. (der liefert dabei aber
auch gleich 32 Bit, wobei die Information mir vielleicht für
eine Optimierungsvariante trotzdem hilft...)

Ich habe mir das jetzt nicht im Detail angeschaut, aber die
Verzögrerungen "drumherum" lassen sich evtl. ganz gut
durch die RAM Zugriffe erklären: Ein Byte (oder Wort, bzw.
sogar bis zu vier Worte, das ist egal) ins gecachte RAM schreiben
kostet: 4 Worte lesen (Burst, 135ns) + 4 Worte schreiben (Burst,
120ns). Das Lesen kann man leider nicht vernünftig verhindern
(siehe #ifdefs um "dbcz" im Kernel-Code), fällt in der Summe
aber kaum ins Gewicht weil das nur 32 mal für 512 Bytes
stattfinden müsste.

Der theoretisch ideale Ablauf wäre wohl dieser:
225ns pro Bit * 8 * 512 -> 921.600ns (Bits reintakten)
255ns für 4 Worte * 32 -> 8.160ns (Ergebniss rausschreiben)
=> ~1ms insgesamt

Um nen Faktor besser zu werden müsste man dann wohl die
Zugriffe pro Bit reduzieren. Und beim Schreiben kann das sogar
klappen, wenn man das Datenbit zusammen mit dem Takt ausgibt,
also nur 150ns pro Bit. Kommt dann auf Setup-Zeiten usw. an, ob
das erlaubt ist... (Mit einer externen Hardware kann man da
natürlich auch was machen, aber dann wird der Anschluss ja
wieder kompliziert)

Was mir jetzt dann noch zu den Optimierungen einfällt, um den
Ablauf in die Nähe des idealen Ergebniss zu bringen:

-> Es gibt eine Anweisung, die gleich mehrere Register am Stück
ausgeben kann.
Wenn man also z.B. ohne Loop z.B. gleich vier 32-Bit Register per
Bit-Takten füllt, und die dann auf einmal ins RAM schreibt?

Ciao,

DboxBaer
Zuletzt geändert von DBoxBaer am Dienstag 1. August 2006, 18:49, insgesamt 1-mal geändert.
... und der Rest ist dann Software (TM)
just_me
Einsteiger
Einsteiger
Beiträge: 123
Registriert: Montag 28. November 2005, 11:31

Beitrag von just_me »

Günther hat geschrieben:Müßte das denn nicht schneller als 5 Takt gehen :gruebel: - vielleicht kann da ein Busexperte etwas zu sagen (ev. lassen sich die allgemeinen Timingeinstellungen noch optimieren :gruebel: ). Falls da nichts zu machen ist, wäre die Bit-Bangoptimierung hiermit nämlich abgeschlossen
Nach Tabelle 6-12 von MPC823UM.pdf sieht es tatsächlich so aus, als ob jeweils 5 Takte das Mininimum für einen einzelnen externen Lese- oder Schreibzugriff darstellt...

Der dort ebenfalls aufgeführte Load/Store Multiple (6 Zyklen für zwei Writes) lässt sich wohl leider nicht für das Schreiben von ClockLow ClockHigh verwenden weil alle (?) Multiple Store Kommandos auch jeweils die Zieladresse erhöhen (und das IO-Register wohl nicht mehr unter einer um 4 höheren Adresse erreichbar ist). - Schade!
Günther
Developer
Beiträge: 587
Registriert: Freitag 9. September 2005, 21:48

Beitrag von Günther »

just_me hat geschrieben:"- Schade!
:cry: Ja, sehr schade, hat gerade so viel spaß gemacht -schnief :cry: :cry:
Aber immerhin wissen wir jetzt das es definitiv nicht schneller geht...
DBoxBaer
Senior Member
Beiträge: 255
Registriert: Donnerstag 25. August 2005, 11:34

Beitrag von DBoxBaer »

Günther hat geschrieben:
just_me hat geschrieben:"- Schade!
:cry: Ja, sehr schade, hat gerade so viel spaß gemacht -schnief :cry: :cry:
Aber immerhin wissen wir jetzt das es definitiv nicht schneller geht...
Naja, auf 500kB/s kann man das vielleicht noch hochdrücken, wenn
man den "Rest" drumherum noch optimiert?! Alignment z.B. kann man
ja vorher abchecken...

Und: Beim Schreiben: Darf man wirklich nicht das Datenbit mit einer
der beiden Clock-Flanken gleichzeitig setzen? Dann geht die Rate dort
ein gutes Stück rauf.

Leider bringt das wohl für MP3 Player nix :-)
... und der Rest ist dann Software (TM)
Günther
Developer
Beiträge: 587
Registriert: Freitag 9. September 2005, 21:48

Beitrag von Günther »

Ich tippe mal eher auf 10% - also so 350 Kbyte lassen sich beim lesen ev. noch erreichen. Dafür lohnt aber eigentlich der Aufwand nicht, zumal der Code dann deutlich schlechter lesbar und portierbar wird. Beim Schreiben ist vielleicht noch mehr drin, ich schätze mal so um die 25%. Aber auch hier gilt es das Kosten-Nutzen-Verhältnis abzuschätzen. Eventuell sind die knappen Resourcen ja doch besser bei der SMC Optimierung bzw. beim IDMA aufgehoben?
DBoxBaer
Senior Member
Beiträge: 255
Registriert: Donnerstag 25. August 2005, 11:34

Beitrag von DBoxBaer »

Günther hat geschrieben:Ich tippe mal eher auf 10% - also so 350 Kbyte lassen sich beim lesen ev. noch erreichen. Dafür lohnt aber eigentlich der Aufwand nicht, zumal der Code dann deutlich schlechter lesbar und portierbar wird. Beim Schreiben ist vielleicht noch mehr drin, ich schätze mal so um die 25%. Aber auch hier gilt es das Kosten-Nutzen-Verhältnis abzuschätzen. Eventuell sind die knappen Resourcen ja doch besser bei der SMC Optimierung bzw. beim IDMA aufgehoben?
Full Ack ;-)
SMC und IDMA geht ja beides in die gleiche Richtung: Wenns der Core
nicht bringt, dann vielleicht jemand anders im System :-)
Interessant sind diese Messungen und überlegungen allemal, weil sie
recht harte Grenzen der Dbox aufzeigen.
... und der Rest ist dann Software (TM)
just_me
Einsteiger
Einsteiger
Beiträge: 123
Registriert: Montag 28. November 2005, 11:31

Beitrag von just_me »

Etwas das man noch testen könnte, nicht um das Bit-Banging als solches sondern um das System als ganzes schneller zu machen, wäre, das Cachen der gelesenen Daten ganz oder teilweise zu unterbinden.

Warum in aller Welt sollte es denn schneller werden, wenn der Cache nicht genutzt wird?

Der PowerPC hat mit 1 kByte einen relativ kleinen Daten-Cache. Wenn das Betriebssystem nun beim Lesen einen angefordeten 512 Byte Block und auf Verdacht einen weiteren einliest und danach noch zur Userapplikation zurückkehrt, ist der komplette Cache kalt: die Daten der Userapplikation (und der Libraries) sind komplett nicht mehr drin & die ersten Bytes des soeben angeforderten Blocks sind auch schon wieder draussen. :-?

Dies liesse sich vermeiden, wenn beim Lesen jeweils eines 512 Byte Blocks nur die ersten x Byte gepuffert würden (x=16 würden bei einem MP3 Stream mit 128kBit/s schon für eine Millisekunde vorhalten) :)

Beim Schreiben eines Blocks sollten die geschriebenen Daten erst recht keine anderen Daten aus dem Daten-Cache rausschmeissen (-> D-Cache inhibit).
DBoxBaer
Senior Member
Beiträge: 255
Registriert: Donnerstag 25. August 2005, 11:34

Beitrag von DBoxBaer »

Bedenke dabei, das ohne Caching das RAM nur über Einzel-Wort
Zugriffe gelesen/geschrieben wird, also ohne Bursts. Statt 120ns
für vier Worte sinds dann 90ns für jedes Wort.

Eine Frage wäre, ob die Daten nicht sowieso den Cache schon
zerstört haben, weil sie gerade vorher kopiert wurden?
... und der Rest ist dann Software (TM)
Günther
Developer
Beiträge: 587
Registriert: Freitag 9. September 2005, 21:48

Beitrag von Günther »

Habe mal gerade einen MP3 Test mit der aktuellen Optimierung gemacht.

Bei 192kbit/s VBC gibt es ca. alle 1-2 Minute einen kurzen Aussetzer. Ist zwar schon viel besser als vorher, aber leider (zumindest für mich) immer noch unbrauchbar für Musik. Ein bisschen läßte sich zwar beim MMC Treiber noch rausholen, aber ob die max. 10% das Abspielen verbessern glaub ich auch nicht wirklich.

Der Ansatz von just_me scheint mir auch vielversprechender - irgendwo anders läßt sich doch bestimmt noch leichter etwas optimieren (weil bei 300kbyte/s machen 192kbit/s 'nur' noch 5-10% aus). Ev. könnte der ganze MP3 Kram auf die 512 Byte Blöcke optimiert werden.

Kennt sich den jemand mit dem MP3 Pfad aus und kann da ein paar Tips geben?

So oder so werde ich mal den bisherigen Stand in den MMC2 Treiber einpflegen. Besser als vorher ist es allemal. Den MMC Treiber laß ich erstmal so wie er ist, da ich den z.Z nicht testen kann.

Günther
Günther
Developer
Beiträge: 587
Registriert: Freitag 9. September 2005, 21:48

Beitrag von Günther »

So, der Treiber ist schonmal eingescheckt. Weiter Optimierung sind noch möglich.

optimised mmc2 driver, now approx. 300KBytes/s (before 150 KBytes)

Bitte tested mal ob noch alles funktioniert, bei mir klappt es bestens...

Günther
geko37
Einsteiger
Einsteiger
Beiträge: 133
Registriert: Sonntag 6. April 2003, 18:26

Beitrag von geko37 »

Günther hat geschrieben:So, der Treiber ist schonmal eingescheckt. Weiter Optimierung sind noch möglich.

optimised mmc2 driver, now approx. 300KBytes/s (before 150 KBytes)

Bitte tested mal ob noch alles funktioniert, bei mir klappt es bestens...

Günther
Kommt der mmc.o noch nach ?? Oder wird diese optimierung nur für den mmc2 angeboten ?
Nico 77
Semiprofi
Semiprofi
Beiträge: 1383
Registriert: Freitag 18. April 2003, 15:12

Beitrag von Nico 77 »

Könnte man den mmc und den mmc2 nicht zusammen legen und über einen Modulparameter die jeweilige Version starten?
Günther
Developer
Beiträge: 587
Registriert: Freitag 9. September 2005, 21:48

Beitrag von Günther »

ja. könnte man schon (ist auch die einzig sinnvolle Sache). Carjay hat das ja schon für den 2.6-Treiber gemacht. Das müßte halt jetzt noch jemand für den 2.4-Treiber machen 8). Noch sinvoller wäre ein Treiber für 2.4 UND 2.6 (mit #ifdefs oder so), weil so groß schienen mir die Unterschiede nicht zu sein.
Z80
Erleuchteter
Erleuchteter
Beiträge: 710
Registriert: Dienstag 3. September 2002, 12:54

Beitrag von Z80 »

Günther hat geschrieben:ja. könnte man schon (ist auch die einzig sinnvolle Sache). Carjay hat das ja schon für den 2.6-Treiber gemacht. Das müßte halt jetzt noch jemand für den 2.4-Treiber machen 8).
*nach oben hol*
@Günther
8)
sagemol
Einsteiger
Einsteiger
Beiträge: 193
Registriert: Donnerstag 11. Mai 2006, 09:26

Beitrag von sagemol »

Z80 hat geschrieben:
Günther hat geschrieben:ja. könnte man schon (ist auch die einzig sinnvolle Sache). Carjay hat das ja schon für den 2.6-Treiber gemacht. Das müßte halt jetzt noch jemand für den 2.4-Treiber machen 8).
*nach oben hol*
@Günther
8)
Ist ja schon steinalt, der Thread, mal wieder hochholen...
Kommt da noch was, Günther ? :-)

Greez !