Grundlegende Frage: Wenn ich ein Array anlege, das aus later Nullen bestehen soll, muss die CPU nach der Speicherzuweisung jedes einzelne Arrayelement abfahren und auf Null setzen? Oder gibt es für diesen Spezialfall eine Abkürzung? Oder hängt das einfach nur von der Hardware ab und wird vom Compiler geregelt? PS: Mir geht es eigentlich um GPUs, aber ich würde gerne wissen, wie es allgemein aussieht.
Maxim S. schrieb: > Wenn ich ein Array anlege, das aus later Nullen > bestehen soll, muss die CPU nach der Speicherzuweisung jedes einzelne > Arrayelement abfahren und auf Null setzen? Ja. Wobei "Arrayelement" hier nichts mit den von Deinem Programm genutzten Elementen zu tun hat, sondern einzelne Bytes bzw. bei Prozessoren mit größerer Datenbusbreite die korrespondierende Datengröße beschreibt. Ein 32-Bit-Prozessor wird also ein Array mit 32-Bit-Zugriffen beschreiben, auch wenn das Array im Programm aus einzelnen Bytes besteht.
Joachim Drechsel schrieb: > Hängt vom Rechenknecht ab. x86 kann das (glaube ich). da eine CPU nicht mal arrays kennt, denke ich nicht das es dafür befehle gibt. Es wird maximal eine möglichkeit haben einen Speicherbereich mit 0 zu überschreiben, aber auch das muss vom Programieren umgesetzt werden.
Peter II schrieb: > da eine CPU nicht mal arrays kennt, denke ich nicht das es dafür befehle > gibt. Es wird maximal eine möglichkeit haben einen Speicherbereich mit 0 > zu überschreiben, aber auch das muss vom Programieren umgesetzt werden. Die x86er haben so etwas wie "Stringbefehle". Ob da ein hardcodiertes memset dabei ist weiß ich jetzt gerade nicht.
Joachim Drechsel schrieb: > Die x86er haben so etwas wie "Stringbefehle". Ob da ein > hardcodiertes memset dabei ist weiß ich jetzt gerade nicht. ja aber diesen Befehl muss man expliziert für einen Speicherbereich ausführen. die CPU kennt keine Variablen. Sie kann also auch nicht wissen wann eine Array angelegt wird.
Such nach memset efficiency mit google. Ja, es geht "effizienter". Die CPU muss nicht wissen, ob das ein Array o.ae. ist. Der Compiler ist an dieser Steller gefragt.
avion23 schrieb: > Der Compiler ist an dieser Steller gefragt. ich würde denke hier ist mehr der Entwickler der glibc gefragt. Er muss dann memset anders implemtieren. Die Stringbefehle der CPU werden kaum von einem compiler umgesetzt.
Peter II schrieb: > Die Stringbefehle der CPU werden kaum > von einem compiler umgesetzt. Warum nicht? Hängt vom Compiler und Target ab. AVR-GCC beispiels- weise expandiert memset() inline:
1 | ldi r24,lo8(256) |
2 | ldi r25,hi8(256) |
3 | ldi r30,lo8(array) |
4 | ldi r31,hi8(array) |
5 | mov r26,r30 |
6 | mov r27,r31 |
7 | mov r18,r24 |
8 | mov r19,r25 |
9 | st X+,__zero_reg__ |
10 | subi r18,1 |
11 | sbci r19,0 |
12 | brne .-8 |
GCC 4.6 auf FreeBSD/i386 ebenfalls:
1 | movl $array, %edx |
2 | movl $64, %ecx |
3 | movl $0, %eax |
4 | movl %edx, %edi |
5 | rep stosl |
GCC 4.1 auf Linux/x86_64 dagegen nicht:
1 | movl $256, %edx |
2 | xorl %esi, %esi |
3 | movl $array, %edi |
4 | jmp memset |
Jörg Wunsch schrieb: > AVR-GCC beispiels- > weise expandiert memset() inline: optimiert er den code oder "kennt" er memset und setzt es anders um? Ich hätte jetzt gedacht das es in der libc einfach als asm umgesetzt ist.
Peter II schrieb: > optimiert er den code oder "kennt" er memset und setzt es anders um? Was soll das "oder"? Er kennt memset() und setzt es auf seine Weise optimal um. Das ist ihm in einem `hosted environment' durch den Standard gestattet.
Jörg Wunsch schrieb: > Was soll das "oder"? es könnte ja sein das er die funktion erkennt das ein speicherberich genullt werden soll und dieses mit hilfe der STringfunktionen umsetzt. for( ... ) { x[y] = 0; } oder er weiss was memset macht und ersetzt es durch eine eigene implementierung. Was aber nicht mehr geht wenn ich mir die memset funtion umbenenne.
Peter II schrieb: > es könnte ja sein das er die funktion erkennt das ein speicherberich > genullt werden soll und dieses mit hilfe der STringfunktionen umsetzt. > > for( ... ) { > x[y] = 0; > } Auch das könnte er erkennen, aber in meinem Falle war es ein memset(). (Gerade probiert, eine explizite Schleife optimiert er auch mit GCC 4.6 nicht, nur memset()).
Peter II schrieb: > avion23 schrieb: >> Der Compiler ist an dieser Steller gefragt. > > ich würde denke hier ist mehr der Entwickler der glibc gefragt. Er muss > dann memset anders implemtieren. memset ist im Falle von gcc im Compiler implementiert, wie ein Großteil der Standard-Blibliothek. Siehe http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/Other-Builtins.html#Other-Builtins > Die Stringbefehle der CPU werden kaum von einem compiler umgesetzt. Warum sollten sie nicht? Bei mir tut er genau das, wenn ich einen memset-Aufruf mache. Allerdings hängt das davon ab, für welchen Prozessor man optimiert und wie groß der zu kopierende Block ist. Wenn ich z.B. die SIMD-Instruktionen freischalte (-march=core2), nutzt er die, aber nicht bei allen Blockgrößen. Und wenn die Blockgröße keine Konstante ist, sieht's dann nochmal ganz anders aus. Jörg Wunsch schrieb: > (Gerade probiert, eine explizite Schleife optimiert er auch mit > GCC 4.6 nicht, nur memset()). Sie sehen bei mir unterschiedlich aus, aber optimieren tut er die Schleife auch. Er erkent zumindest, daß er nicht jedes Byte einzeln schreiben muß, sondern das auch in 32-Bit-Blöcken tun kann.
Rolf Magnus schrieb: >> Die Stringbefehle der CPU werden kaum von einem compiler umgesetzt. > Warum sollten sie nicht? ich hatte mal gelesen das sie zu "kompliziert" für dien Compiler sind. Sie sollen auch nicht wirklich geschwindigkeitsvorteile bringen. Die Befehle waren zu einer Zeit eingaut wurden wo man noch von Hand optimiert hat. Und wenn gcc hier diese befehle bei memeset verwendet, dann vermute ich ganz stark das jemand dieses expliziert von hand codiert hat. Der normale Optimizer wird also nicht auf die Idee kommen diese befehle zu verwenden. Sonst hätte er es auch bei einer schleife gemacht.
Peter II schrieb: > Und wenn gcc hier diese befehle bei memeset verwendet, dann vermute ich > ganz stark das jemand dieses expliziert von hand codiert hat. Alles im GCC hat jemand explizit von Hand codiert. ;-) Oder was dachtest du, wie der Compiler seinen Code generiert? > Der > normale Optimizer wird also nicht auf die Idee kommen diese befehle zu > verwenden. Deine Vorstellungen über die Art und Weise, wie ein Compiler optimiert, dürften aus dem letzten Viertel des vorherigen Jahrhunderts stammen. Heutzutage gibt's einfach nicht mehr "den Optimizer", erst recht nicht einen "normalen". ;-)
Jörg Wunsch schrieb: > Oder was > dachtest du, wie der Compiler seinen Code generiert? es ist doch wohl ein unterschied ob man eine complete funktion in ASM codiert wird (von hand) oder ob der optimierer anhand des C codes erkennen soll was gemeint ist und damit selber auf die Idee kommt die string befehle zu verwenden. >> Der >> normale Optimizer wird also nicht auf die Idee kommen diese befehle zu >> verwenden. > Deine Vorstellungen über die Art und Weise, wie ein Compiler optimiert, > dürften aus dem letzten Viertel des vorherigen Jahrhunderts stammen. du könntest mich davon überzeugen das es nicht stimmt, in dem du mir mal code zeigst wo der compiler die string-upcodes verwendet.
Peter II schrieb: > du könntest mich davon überzeugen das es nicht stimmt, in dem du mir mal > code zeigst wo der compiler die string-upcodes verwendet. Dazu müsstest du dir schon mal den Compiler-Sourcecode selbst auspacken und in der Datei i386.md nach beispielsweise stosq suchen.
Jörg Wunsch schrieb: > Peter II schrieb: >> du könntest mich davon überzeugen das es nicht stimmt, in dem du mir mal >> code zeigst wo der compiler die string-upcodes verwendet. > > Dazu müsstest du dir schon mal den Compiler-Sourcecode selbst > auspacken und in der Datei i386.md nach beispielsweise stosq > suchen. ich meinte zwar eine beispiel C datei wo mit hilfe des compilers am ende ein stosq verwendet wird. Das der compiler grunsätzlich den upcode kennt, ist ja noch kein hinweis darauf das er ihn auch in der praxis irgenwie verwendet. Außer man schreibt gleich ASM code. Werde mir aber mal die quellen saugen.
Peter II schrieb: > upcode Mach dich erstmal schlau, wie man Opcode überhaupt schreibt. Mist, jetzt hab ich es verraten...
Peter II schrieb: > ich meinte zwar eine beispiel C datei wo mit hilfe des compilers am ende > ein stosq verwendet wird.
1 | $ cat foo.c |
2 | char array[256]; |
3 | |
4 | #include <string.h> |
5 | |
6 | void |
7 | init_array(void) |
8 | { |
9 | int i; |
10 | for (i = 0; i < 256; i++) |
11 | array[i] = 0; |
12 | } |
13 | $ /junk/testroot/bin/gcc -O3 -S foo.c |
14 | $ cat foo.s |
15 | .file "foo.c" |
16 | .text |
17 | .p2align 4,,15 |
18 | .globl init_array |
19 | .type init_array, @function |
20 | init_array: |
21 | .LFB0: |
22 | .cfi_startproc |
23 | movl $array, %edx |
24 | movl $64, %ecx |
25 | pushl %edi |
26 | .cfi_def_cfa_offset 8 |
27 | .cfi_offset 7, -8 |
28 | xorl %eax, %eax |
29 | movl %edx, %edi |
30 | rep stosl |
31 | popl %edi |
32 | .cfi_restore 7 |
33 | .cfi_def_cfa_offset 4 |
34 | ret |
35 | .cfi_endproc |
36 | .LFE0: |
37 | .size init_array, .-init_array |
38 | .comm array,256,32 |
39 | .ident "GCC: (GNU) 4.8.0 20120530 (experimental)" |
40 | .section .note.GNU-stack,"",@progbits |
Es wird stosl (und nicht stosq) benutzt, weil der Compiler im 32-bit-Modus arbeitet. > Das der compiler grunsätzlich den upcode kennt, ist ja noch kein hinweis > darauf das er ihn auch in der praxis irgenwie verwendet. Außer man > schreibt gleich ASM code. Dafür müsste der Compiler den Opcode nicht kennen, denn inline asm reicht er ja nur an den Assembler durch.
@Jörg Wunsch danke für die Mühe. Ist das etwas neu in GCC: (GNU) 4.8.0 20120530 (experimental) ?. Weil mit GCC 4.6 scheint es ja nicht zu passieren > Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite > Datum: 05.07.2012 15:32 > > (Gerade probiert, eine explizite Schleife optimiert er auch mit > GCC 4.6 nicht, nur memset()). oder liegt das am experimental?
es scheint zumindest noch nicht lange so zu sein. Mein 4.6 macht es nicht- .file "test.c" .text .p2align 4,,15 .globl init_array .type init_array, @function init_array: .LFB12: .cfi_startproc movl $array, %eax .p2align 4,,7 .p2align 3 .L2: movl $0, (%eax) addl $4, %eax cmpl $array+256, %eax jne .L2 rep ret .cfi_endproc .LFE12: .size init_array, .-init_array .comm array,256,32 .ident "GCC: (Debian 4.6.3-1) 4.6.3" .section .note.GNU-stack,"",@progbits
Peter II schrieb: > Mein 4.6 macht es > nicht- Aber du siehst, dass er auch jeweils 4 Bytes zu einem Schreibzugriff zusammenfasst. Ab welcher Version das konkret drin ist, kann ich dir auch nicht sagen. Sollte ja vor allem als Beispiel dienen, dass die Optimierung moderner Compiler tatsächlich so feingliedrig ist, dass sie da unwahrscheinlich viel aufdröseln kann. Letztlich muss ihr das natürlich ein Mensch beigebracht haben, welche Muster im Maschinencode durch welche Befehle optimal abarbeitbar sind.
Jörg Wunsch schrieb: > Aber du siehst, dass er auch jeweils 4 Bytes zu einem Schreibzugriff > zusammenfasst. ja das ist auch gut so. Mir ging es aber extra um die String Opcodes. Da hatte ich mal gelesen das sie vom compiler nicht genutzt werden. Dies schein bis jetzt auch so zu sein. .ident "GCC: (Debian 4.7.1-2) 4.7.1" macht es auch nicht. Etweder ist das ganze experimental oder es ist nach 20Jahren wirklich mal einer auf die Idee gekommen es umzusetzen.
MS macht es sich einfach: _init_array PROC ; File c:\test.c ; Line 10 push 256 ; 00000100H push 0 push OFFSET _array call _memset add esp, 12 ; 0000000cH ; Line 11 ret 0 _init_array ENDP _TEXT ENDS END
Peter II schrieb: > oder es ist nach > 20Jahren wirklich mal einer auf die Idee gekommen es umzusetzen Es hilft nichts, nur auf die Idee zu kommen. ;-) Es muss auch die Infrastruktur (im Compiler) da sein, die entsprechenden Codemuster zu isolieren, auf die man das dann anwenden kann.
Wenn bei Intel genau nachliest, dann findet man, daß es verschiede Arten von Opcodes gibt. Manche laufen optimal durch die Pipelines, andere, wie z.B. die Repeated Stringbefehle, passen nicht auf jeder CPU dazu und laufen dann effektiv langsamer als äquivalente Sequenzen "flinker" Befehle. Durchsatz und Latenz sind die Stichworte.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.