memcpy schneller als Schleife?
-
memcpy, strlen, strcpy, memcmp,... das sind alles magische funktionen - die können alles.
eine schleife wird nie schneller sein als ein memcpy - höchstens gleich schnell (es sei denn die library ist wirklich extremer mist)
der compiler kann nämlich zaubern - der macht mal ein memcpy so rum und woanders macht ers andersrum, also der weiß schon wie er zu optimieren hat.
und da memcpy ja nur plain data zum rumschaufeln hat, gibts auch keine speziellen tricks algorithmen tricks - alles auf assembler ebene -> je nachdem was die CPU an daten will, wird sie perfekt ausgelastet
nunja, aber eine schleife kann genauso schnell sein, da der compiler ja erkennen kann was du willst und er die schleife einfach durch sein memcpy ersetzt.
-
/*** *memcpy - Copy source buffer to destination buffer * *Purpose: * memcpy() copies a source memory buffer to a destination memory buffer. * This routine does NOT recognize overlapping buffers, and thus can lead * to propogation. * * For cases where propogation must be avoided, memmove() must be used. * *Entry: * void *dst = pointer to destination buffer * const void *src = pointer to source buffer * size_t count = number of bytes to copy * *Exit: * Returns a pointer to the destination buffer * *Exceptions: *******************************************************************************/ void * __cdecl memcpy ( void * dst, const void * src, size_t count ) { void * ret = dst; #if defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) || defined (_M_IA64) { extern void RtlMoveMemory( void *, const void *, size_t count ); RtlMoveMemory( dst, src, count ); } #else /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) || defined (_M_IA64) */ /* * copy from lower addresses to higher addresses */ while (count--) { *(char *)dst = *(char *)src; dst = (char *)dst + 1; src = (char *)src + 1; } #endif /* defined (_M_MRX000) || defined (_M_ALPHA) || defined (_M_PPC) || defined (_M_IA64) */ return(ret); }
-
Original erstellt von ChrisM:
Aber vielleicht optimieren manche guten Compiler die Schleife schon zu memcpy(), würd ich mich aber nicht drauf verlassen!Also ich würd mir dann nen neuen Compiler kaufen
.
Zum Thema: Ich glaube nicht, dass es einen großen Unterschied macht ob Schleife oder memcpy. Der Compiler kann nicht wirklich viel an der Stelle optimieren. Ich würde meinen Blick eher auf andere Codestellen lenken. Was mir so spontan zum Optimieren bei zeitkritischen Anwendungen einfällt:
- PreIncrement verwenden wenn PostIncrement unnötig ist.
- Initialisierungslisten von Klassen verwenden anstatt im Kontruktor drin zu initialisieren.
- Objekt sofort nach dem erstellen initialisieren anstatt ne Zeile später.
- Wenn möglich Parameter über Referenzen übergeben.
- Variablen so spät wie möglich deklarieren und so lokal wie möglich halten.
- Beim rechnen mit Ganzzahlen immer int anstatt short (auch wenn short reicht) bevorzugen. (Weil beim rechnen immer erst umwandlung in int geschieht falls eine Zahl short ist)
- Inline-Funktionen kurz halten.
- Rückgabewerte nur wenn sie gebraucht werden.
- Lokale Variablen minimieren.
- Shiften anstatt pow bei Zweierpotenzen.
- Bei Strukturen in großen Arrays sollte die Strukturgröße eine Zweierpotenz sein, weil beim Berechnen des Indizes dann geshiftet werden kann.EDIT: Naja, der letzte Punkt ist nicht immer sinnvoll!
Vielleicht fällt ja noch jemandem was ein...?
[ Dieser Beitrag wurde am 13.05.2003 um 18:21 Uhr von MaSTaH editiert. ]
-
Naja, der vorletzte Punkt ist nicht sinnvoll!
-
Original erstellt von <-1>:
Naja, der vorletzte Punkt ist nicht sinnvoll!Natürlich.
[ Dieser Beitrag wurde am 13.05.2003 um 18:45 Uhr von MaSTaH editiert. ]
-
Gibt auch noch die Möglichkeit von sogenannten Templates... schau mal unter http://www.oonumerics.org/blitz/ . Habe es zwar noch nicht so ganz verstanden, scheint aber schneller zu sein, als ne simple (!?) For Schleife.
Gruß Winn
-
@Winn
Hä, templates haben mit Schleifen doch nicht das geringste zu tun.
-
template metaprogrammierung
-
Original erstellt von MaSTaH:
@Winn
Hä, templates haben mit Schleifen doch nicht das geringste zu tun.doch, doch.
man kann nen TinyVector<typename T,size_t SIZE>{T data[SIZE]... so implementieren, daß der Copy-Konstruktor ne normale for-Schleife nimmt, daß er memcpy nimmt, daß er duff's device nimmt, oder daß er per templates ne Schleife komplett unrolled. Und letzteres ist für Blitz++ typisch.
-
@Mastah
Wenn ich das wußte, dann würd ich Dir mehr dazu posten, mich hatte ein Kumpel auf die Blitz++ Library gebracht, weil ich Performance brauchte, dann laß ich von den Templates und rekursiven Handlings... da gingen bei mir erstmal die Nackenhaare hoch, weil Rekusionen sind ja vielleicht fein, aber sau lahm, einfache Iterationen bieten sich dort besser an, aber diese Templates scheinen Dampf zumachen... der Kernpunkt der damit ausgestochen wird ist, daß der Compiler nur Pointer und Adressen sieht, also keine Ahnung vom eigentlichen Ablauf hat oder sagen wir von einem sinnigen Ablauf. Compiler die auf die Semantik achten und entsprechend der Programmlogik compilieren sind wohl gescheitert. Der Kai C++ Compiler wurde von Intel aufgekauft, er war das beste Stück in diesem Bereich. Mit den Templates läßt sich aber wohl diese Semantische Lücke schließen...
Schau dir die Blitz++ Library mal an, sie ist Open Source und steht unter GNU. Wollte jetzt demnächst mal ein Test Programm schreiben, werde mich dann wieder zurückmelden...
Winn
-
@volkard
Rekursion mit Templates kann ich mir vorstellen. Oder meinst du was anderes? Werd mir die Blitz-Library mal angucken.
-
Original erstellt von MaSTaH:
@volkard
Rekursion mit Templates kann ich mir vorstellen. Oder meinst du was anderes? Werd mir die Blitz-Library mal angucken.doch, genau das meine ich.
-
Original erstellt von Shade Of Mine:
**
der compiler kann nämlich zaubern - der macht mal ein memcpy so rum und woanders macht ers andersrum, also der weiß schon wie er zu optimieren hat.
**Das mit dem mal so und mal so rum hat nen andren Grund, je nachdem ob man:
char array[500]; char* dest = &array[110]; char* src = &array[100]; memcpy(dest, src, 100); // oder char* dest = &array[100]; char* src = &array[110]; memcpy(dest, src, 100);
macht würde, wenn memcpy nur von links nach rechts bzw von rechts nach links kopieren könnte, ein falsches Ergebnis kommen, weil er das bereits kopierte nochmal kopiert wird.
[ Dieser Beitrag wurde am 14.05.2003 um 11:42 Uhr von dreaddy editiert. ]
-
dafür gibts memmove.
mit sorum&andersrum war wohl eher gemeint, daß er aus
(ich nehme int*a an)memcpy(a,b,0) ein {} macht, aus
memcpy(a,b,4} ein MOV, aus
memcpy(a,b,40) ein REPNE MOV und aus
memcpy(a,b,n) ein CALL _memcpy (oder doch nur ein REPNE MOV, wenn er weiß, daß n klein ist?) und aus
{int* a=new int[100];memcpy(a,a,400);delete a;} ein {}.
-
Hey nochmal,
also die Blitz Lib ist schon eine feine Sache, allerdings für meine Ansprüche war sie zu langsam. Leider
Anbei der Quellcode für eine Template For Schleife und If Abfrage, gefunden unter [url] http://home.t-online.de/home/Ulrich.Eisenecker/meta.htm [/url]...
Gruß Winn
HEADER
#ifndef _METACTRL #define _METACTRL namespace metactrl { // IF<> namespace intimate { struct SelectThen { template<class Then, class Else> struct Result { typedef Then RET; }; }; // end SelectThen struct SelectElse { template<class Then, class Else> struct Result { typedef Else RET; }; }; // end SelectElse template<bool Condition> struct Selector { typedef SelectThen RET; }; // end Selector template<> struct Selector<false> { typedef SelectElse RET; }; // end Selector<false> } // end namespace private template<bool Condition, class Then, class Else> struct IF { typedef intimate::Selector<Condition>::RET select; typedef select::Result<Then,Else>::RET RET; }; // IF // FOR<>, comparators // for convenience struct Equal { template <int lval, int rval> struct Test { enum {evaluate = lval == rval}; }; }; // end Equal struct NotEqual { template <int lval, int rval> struct Test { enum {evaluate = lval != rval}; }; }; // end NotEqual struct Less { template <int lval, int rval> struct Test { enum {evaluate = lval < rval}; }; }; // end Less struct LessEqual { template <int lval, int rval> struct Test { enum {evaluate = lval <= rval}; }; }; // end LessEqual struct Greater { template <int lval, int rval> struct Test { enum {evaluate = lval > rval}; }; }; // end Greater struct GreaterEqual { template <int lval, int rval> struct Test { enum {evaluate = lval >= rval}; }; }; // end GreaterEqual template <int From,class Compare,int To,int By,class Statement> struct FOR { static void EXEC() { IF <Compare::Test<From,To>::evaluate, Statement::Code<From>, intimate::Stop> ::RET::execute(); IF <Compare::Test<From,To>::evaluate, FOR<From+By,Compare,To,By,Statement>, intimate::Stop> ::RET::EXEC(); }; }; // end FOR } // end namespace metactrl #endif _METACTRL
USING
// METAXMPL.CPP - Copyright (C) 1998 by // Ulrich W. Eisenecker and // Krzysztof Czarnecki // This file demonstrates the usage of the template-metaprogramming // control-structures of METACTRL #include <iostream> #include "metactrl" using namespace std; using namespace metactrl; // all meta-controlstructures are in namespace "metactrl" // stuff for testing IF<> struct DemoThen { DemoThen() { cout << "DemoThen" << endl; } }; struct DemoElse { static void execute() { cout << "DemoElse" << endl; } }; // stuff for testing SWITCH<> struct A { static void execute() { cout << "A" << endl; } }; struct B { static void execute() { cout << "B" << endl; } }; struct C { C() { cout << "C" << endl; } }; // stuff for testing FOR<> struct DemoFor { template <int i> // "i" is the loop variable struct Code { static void execute() { cout << i << endl; } }; }; struct DemoNestedFor { template <int i> // "i" is the first loop variable struct Code { struct NestedStatement { template <int j> // "j" is the second loop variable struct Code { static void execute() { cout << i << '|' << j; if (i == j) cout << endl; else cout << '\t'; } }; }; static void execute() { FOR<i+1,Less,5,+1,NestedStatement>::EXEC(); cout << endl; }; }; }; int main() { // Testing IF<> cout << "Testing IF<>" << endl; IF<true,DemoThen,DemoElse>::RET if_result; // declare variable IF<false,DemoThen,DemoElse>::RET::execute(); // call class function // Testing FOR<> cout << "Testing FOR<>" << endl; FOR<10,Greater,1,-2,DemoFor>::EXEC(); // define it and use it immediately // How to nest loops? Here is the answer: typedef FOR<0,Less,5,+1,DemoNestedFor> for_loop; // define it for_loop::EXEC(); // and use it later return 0; }
-
Also ich kann mir nicht helfen. Irgendwie gefällt mir diese Art der Programmierung nicht. Bringt das rein performancetechnisch eigentlich viel?
-
Herkömmliche Methode Du startest das programm und etwas wird berechnet. Templatemetaprogrammierung: Wärend des Compilierens wird bereits einiges berechnet und beim ausführen nurnoch ausgegeben.
-
Herkömmliche Methode: Compilierzeit 2s, Berechnung 10 µs, Ausgabe 100µs
Template-Meta-Methode: Compilierzeit 2min, Berechnung 0,1 µs, Ausgabe 100µs
-
Also bringts quasi nur was wenn man viel berechnet und wenig ausgibt. Dann dauert das kompilieren aber so lange wie ein Kind zu gebären. Frohes Debuggen
-
@Bashar
Welche Art von Berechnung hast Du ausgeführt ? Bisher hab ich nur die Blitz++ Lib genutzt, die Template Technik hab ich noch nicht genutzt... zeig mal deinen Testrahmen ?Gruß Winn