Welche Funktion ist schneller: strcmp oder strlen?



  • knivil schrieb:

    Trollor?!
    Ich kann nur Stoustrup wiederholen. Beispiel qsort: Wenn alle Typinformationen weggeworfen werden und mit void* gearbeitet wird, dann kann der Optimierer/Compiler diese Information nur schwer benutzen.

    ob der compiler das schwer hat oder nicht interessiert doch niemanden.
    und wegen einer eventuell möglichen optimierung, wegen eines features gleich auf allgemeine eigenschaften zu schließen ist ein wenig albern, findest du nicht?

    volkard schrieb:

    Aber wenn man sich nur ein wenig Mühe gibt, baut man bei vergleichbarem Aufwand mit C++ immer schnellere Programme als mit C.

    die begründung täte mich doch interessieren sehr.


  • Mod

    fairy tell believer schrieb:

    ob der compiler das schwer hat oder nicht interessiert doch niemanden.

    Doch, das ist sogar ganz entscheidend, denn hier ist Schwer = Unmöglich.

    und wegen einer eventuell möglichen optimierung, wegen eines features gleich auf allgemeine eigenschaften zu schließen ist ein wenig albern, findest du nicht?

    Wenn es ein entscheidendes Feature ist, das andauernd benutzt wird?

    volkard schrieb:

    Aber wenn man sich nur ein wenig Mühe gibt, baut man bei vergleichbarem Aufwand mit C++ immer schnellere Programme als mit C.

    die begründung täte mich doch interessieren sehr.

    Siehe oben. Die Anpassung von allgemeinen Algorithmen auf spezielle Gegebenheiten geht in C++ so einfach, dass man es nicht einmal bemerkt. Dadurch steht eine große Vorauswahl fertiger Algorithmen bereit, die trotzdem auf das konkrete Problem bezogen optimal umgesetzt werden. Dies verringert den Entwicklungsaufwand erheblich, trotzdem wird optimaler Code erzeugt. Um den gleichen optimalen Code zu erzeugen müsste man in C selber Hand anlegen (->großer Aufwand). Für vergleichbar geringen Aufwand müsste man sich hingegen mit suboptimalen Mitteln beim Benutzen von typenunabhängigem Code zufrieden geben (->langsam).

    Das war nur ein Feature. Allgemein hat man natürlich noch ganz andere Features, die den Entwicklungsaufwand erheblich verringern, dabei aber zu dem üblichen Vorgehen in C gleichwertigen (oder manchmal sogar besseren: Exceptions) Code erzeugen, so dass man bei gleichem Aufwand mehr Zeit für Optimierungen hat, wohingegen der C-Programmierer noch Zeit verschwenden muss, zu prüfen, ob seine Speicherfreigabestrategie auch wirklich idiotensicher ist.

    P.S.: Bitte lerne Englisch!



  • fairy tell believer schrieb:

    volkard schrieb:

    Aber wenn man sich nur ein wenig Mühe gibt, baut man bei vergleichbarem Aufwand mit C++ immer schnellere Programme als mit C.

    die begründung täte mich doch interessieren sehr.

    Weil es so schnelle Sachen wie std::sort gibt. Oder Strings, die ihre Länge kennen. Die kann man einfach mal nehmen. Und wenn sie nicht passen, nimmt man sie nicht, allerschlimmstenfalls geht man wie in C vor. Und weil man mit Klassen und Templates weiter abstrahieren kann, ganz ohne Ovberhead, da spart man Zeit, macht weniger Fehler, also hat man mehr Zeit und Möglichkeiten, an Performance zu denken. RAII und Exceptions sorgen dafür, daß man nicht mehr 50% des Codes mit Fehlerbehandlung vollballern muss (und Exceptions sind schneller).



  • Na dann ist doch alles klar.
    C++ und geringerer Entwicklungsaufwand: dem stimme ich voll und ganz zu.
    C++ Programme performanter als C: no way, weil C++ keinen Maschinencode erzeugt, der performanter ist.

    Btw. kann ich mir in C einen Sortieralgo auch selber schreiben, wenn mir qsort zu lahm sein sollte.



  • fairy story schrieb:

    Btw. kann ich mir in C einen Sortieralgo auch selber schreiben, wenn mir qsort zu lahm sein sollte.

    Das ruft nach einem Vergleich.
    Sagen wir mal, einen um 1G großen Eingabestrom wortweise lesen (whitspace als trenner). Stoppuhr starten. Sortieren. Stoppuhr stoppen. Doppeleinträge löschen. Anzahl der ubrigen Einträge anzeigen. Sortierzeit anzeigen.



  • fairy story schrieb:

    Btw. kann ich mir in C einen Sortieralgo auch selber schreiben, wenn mir qsort zu lahm sein sollte.

    Schwachsinn, das offensichtliche Gegenbeispiel qsort vs. std::sort wurde ja schon genannt...



  • volkard schrieb:

    Das ruft nach einem Vergleich.

    Ok.

    // wird dynamisch dazugelinkt
    void g(int *);
    
    void f(int i) {
      int v1[i];
      g(v1);
      int v2[i];
      g(v2);
      {
        int v3[i];
        g(v3);
      }
      g(v2);
    }
    
    int main() {
      register int i;
      for (i=0; i<LOOPS; ++i)
        f(i&0xFF);
    }
    

    vs

    #include <vector>
    
    // wird dynamisch dazugelinkt
    void g(int *);
    
    void f(int i) {
      std::vector<int> v1(i); // Echte C++-Programmierer verwenden Vektor
      g(v1.data());
      std::vector<int> v2(i); // manchmal auch zwei
      g(v2.data());
      {
        std::vector<int> v3(i); // oder drei
        g(v3.data());
      }
      g(v2.data());
    }
    
    int main() {
      for (int i=0; i<LOOPS; ++i)
        try {f(i&0xFF);}catch(...){}
    }
    
    void g(int* x) { }
    

    Dann

    gcc -Ofast -c g.c
    gcc -DLOOPS=10000000 -Ofast -c c.c
    gcc g.o c.o -o c
    
    g++ -Ofast -c g.c
    g++ -DLOOPS=10000000 -Ofast -c cc.cc
    g++ g.o cc.o -o cc
    
    time ./c  
    time ./cc
    stat -c%s c cc
    

    Ergibt

    0.13user 0.00system 0:00.13elapsed 100%CPU (0avgtext+0avgdata 312maxresident)k
    0inputs+0outputs (0major+117minor)pagefaults 0swaps
    5.29user 0.00system 0:05.30elapsed 99%CPU (0avgtext+0avgdata 728maxresident)k
    0inputs+0outputs (0major+239minor)pagefaults 0swaps
    5145
    6874

    Mit -flto (und -Ofast beim Linken) komme ich sogar auf

    0.00user 0.00system 0:00.00elapsed 80%CPU (0avgtext+0avgdata 340maxresident)k
    0inputs+0outputs (0major+128minor)pagefaults 0swaps
    5.12user 0.00system 0:05.17elapsed 99%CPU (0avgtext+0avgdata 724maxresident)k
    0inputs+0outputs (0major+239minor)pagefaults 0swaps
    7668
    9112

    Die letzten zwei Zahlen zeigen übrigens die Dateigrösse an.

    An dem Beispiel sieht man mehrere Fakten

    • Vektor für alles (diese Aussage wird einem in diesem Forum eingetrichtert) ist eine ziemlich schlechte Idee. Der Ansatz statische Arrays wo möglich ist in C++ leider verpönt.
    • RAII und Exceptions sorgen dafür, daß der Compiler 50% des Codes mit Fehlerbehandlung vollballern muss (was zu viel mehr Anweisungen und dadurch Cache-Problemen führt)
    • Der C++-Compiler kann viel weniger optimieren, weil alles Seiteneffekte hat.

  • Mod

    dot schrieb:

    fairy story schrieb:

    Btw. kann ich mir in C einen Sortieralgo auch selber schreiben, wenn mir qsort zu lahm sein sollte.

    Schwachsinn, das offensichtliche Gegenbeispiel qsort vs. std::sort wurde ja schon genannt...

    Recht hat er schon, aber er widerlegt sich damit auch selber. Ein selbst geschriebenes, spezialisiertes qsort kann so schnell sein wie std::sort. Das ist doch gerade das Problem, dass der C++-Programmierer bloß eine Zeile schnell hinkritzeln braucht, während in C an dieser Stelle eine nicht unwesentliche Entwicklungsarbeit nötig ist. Ein paar Stunden gehen da gewiss drauf. Mehr, wenn man nicht irgendwo abschreibt sondern noch selber recherchiert, welcher Algorithmus der beste wäre und wie er optimal implementiert wird.



  • @objdump: Nun, ich hoffe das Beispiel ist nicht ganz ernst gemeint.



  • objdump schrieb:

    volkard schrieb:

    Das ruft nach einem Vergleich.

    Ok.

    // wird dynamisch dazugelinkt
    void g(int *);
    
    void f(int i) {
      int v1[i];
      g(v1);
      int v2[i];
      g(v2);
      {
        int v3[i];
        g(v3);
      }
      g(v2);
    }
    
    int main() {
      register int i;
      for (i=0; i<LOOPS; ++i)
        f(i&0xFF);
    }
    

    vs

    #include <vector>
    
    // wird dynamisch dazugelinkt
    void g(int *);
    
    void f(int i) {
      std::vector<int> v1(i); // Echte C++-Programmierer verwenden Vektor
      g(v1.data());
      std::vector<int> v2(i); // manchmal auch zwei
      g(v2.data());
      {
        std::vector<int> v3(i); // oder drei
        g(v3.data());
      }
      g(v2.data());
    }
    
    int main() {
      for (int i=0; i<LOOPS; ++i)
        try {f(i&0xFF);}catch(...){}
    }
    
    void g(int* x) { }
    

    Dann

    gcc -Ofast -c g.c
    gcc -DLOOPS=10000000 -Ofast -c c.c
    gcc g.o c.o -o c
    
    g++ -Ofast -c g.c
    g++ -DLOOPS=10000000 -Ofast -c cc.cc
    g++ g.o cc.o -o cc
    
    time ./c  
    time ./cc
    stat -c%s c cc
    

    Ergibt

    0.13user 0.00system 0:00.13elapsed 100%CPU (0avgtext+0avgdata 312maxresident)k
    0inputs+0outputs (0major+117minor)pagefaults 0swaps
    5.29user 0.00system 0:05.30elapsed 99%CPU (0avgtext+0avgdata 728maxresident)k
    0inputs+0outputs (0major+239minor)pagefaults 0swaps
    5145
    6874

    Mit -flto (und -Ofast beim Linken) komme ich sogar auf

    0.00user 0.00system 0:00.00elapsed 80%CPU (0avgtext+0avgdata 340maxresident)k
    0inputs+0outputs (0major+128minor)pagefaults 0swaps
    5.12user 0.00system 0:05.17elapsed 99%CPU (0avgtext+0avgdata 724maxresident)k
    0inputs+0outputs (0major+239minor)pagefaults 0swaps
    7668
    9112

    Die letzten zwei Zahlen zeigen übrigens die Dateigrösse an.

    An dem Beispiel sieht man mehrere Fakten

    • Vektor für alles (diese Aussage wird einem in diesem Forum eingetrichtert) ist eine ziemlich schlechte Idee. Der Ansatz statische Arrays wo möglich ist in C++ leider verpönt.
    • RAII und Exceptions sorgen dafür, daß der Compiler 50% des Codes mit Fehlerbehandlung vollballern muss (was zu viel mehr Anweisungen und dadurch Cache-Problemen führt)
    • Der C++-Compiler kann viel weniger optimieren, weil alles Seiteneffekte hat.

    Das ist ein Test, der gar nichts tut. Eine tunichts.exe ist in C schneller und kleiner. *applause*
    Normalerweise wird ein Array der Größe i auch i Nutzdaten halten und irgendwas mit ihnen machen. Kann schon sein, daß manche extrem ungeschickte Implemetierung in C schneller ist, wenn man sie mit Gewalt genauso ungeschickt in C++ schreibt. *hihi*



  • SeppJ schrieb:

    dot schrieb:

    fairy story schrieb:

    Btw. kann ich mir in C einen Sortieralgo auch selber schreiben, wenn mir qsort zu lahm sein sollte.

    Schwachsinn, das offensichtliche Gegenbeispiel qsort vs. std::sort wurde ja schon genannt...

    Recht hat er schon, aber er widerlegt sich damit auch selber. Ein selbst geschriebenes, spezialisiertes qsort kann so schnell sein wie std::sort. Das ist doch gerade das Problem, dass der C++-Programmierer bloß eine Zeile schnell hinkritzeln braucht, während in C an dieser Stelle eine nicht unwesentliche Entwicklungsarbeit nötig ist. Ein paar Stunden gehen da gewiss drauf. Mehr, wenn man nicht irgendwo abschreibt sondern noch selber recherchiert, welcher Algorithmus der beste wäre und wie er optimal implementiert wird.

    Richtig, da hab ich die falsche Stelle zitiert, ich wollte eigentlich die Zeile drüber zitieren:

    fairy story schrieb:

    C++ Programme performanter als C: no way, weil C++ keinen Maschinencode erzeugt, der performanter ist.

    Das ist absoluter Schwachsinn; die Probleme mit der Aussage von wegen selbst schreiben hast du ja schon aufgezeigt...



  • SeppJ schrieb:

    Ein selbst geschriebenes, spezialisiertes qsort kann so schnell sein wie std::sort.

    Es gibt doch genau 3 Fälle:
    a) Performance egal: qsort völlig ausreichend, sogar besser als std::sort, weil das Binary viel viel viel kleiner wird.
    b) Performance wichtig: std::sort ist ungeeignet, weil viel zu allgemein. Eine Liste von Integern sortiert man am besten mit Radix-Sort. Kann C++ auch nicht. Für Strings nimmt man tries. Kann C++ genauso wenig.
    c) Kurze Entwicklungszeit wichtig, Code soll möglichst schnell sein: Hier nimmt man die 80-20-Regel zu Hilfe. Erstmal qsort nehmen, da entwickelt es sich in C genauso schnell wie C++. Über Wochen hinweg sammeln sich mehrere Stunden an, die der C-Compiler weniger benötigt als C++-Compiler. Diese investiert man dann in die 20% ausgeführten Code => C-Programm schneller.



  • Troll.



  • objdump schrieb:

    a) Performance egal: qsort völlig ausreichend, sogar besser als std::sort, weil das Binary viel viel viel kleiner wird.

    Stimmt nur bedingt.

    objdump schrieb:

    Eine Liste von Integern sortiert man am besten mit Radix-Sort.

    Blödsinn

    objdump schrieb:

    Für Strings nimmt man tries.

    Blödsinn

    objdump schrieb:

    Über Wochen hinweg sammeln sich mehrere Stunden an, die der C-Compiler weniger benötigt als C++-Compiler. Diese investiert man dann in die 20% ausgeführten Code => C-Programm schneller.

    Und was ist mit den vielen Stunden debuggen, die C++ einem dank Typsicherheit und so gespart hat?



  • volkard schrieb:

    Das ist ein Test, der gar nichts tut. Eine tunichts.exe ist in C schneller und kleiner. *applause*

    Also willst du etwas sinnvolles?

    #include <vector>
    #include <iostream>
    
    int f(int n) {
      std::vector<bool> nonprime(n);
      for (int i=2; i<n; ++i)
        if (!nonprime[i])
          for (int j=2; i*j<n; ++j)
            nonprime[i*j]=true;
    
      int cnt = 0;
      for (int i=2; i<n; ++i)
        cnt += !nonprime[i];
      return cnt;
    }
    
    int main() {
      int sum=0;
      for (int i=0; i<LOOPS; ++i)
        sum += f(i&0xFF);
      std::cout << sum << '\n';
      return 0;
    }
    
    #include <stdio.h>
    #include <stdbool.h>
    #include <string.h>
    
    int f(int n) {
      bool nonprime[n];
      memset(nonprime, 0, n);
      register int i, j, cnt;
    
      for (i=2; i<n; ++i)
        if (!nonprime[i])
          for (j=2; i*j<n; ++j)
            nonprime[i*j]=true;
    
      cnt = 0;
      for (i=2; i<n; ++i)
        cnt += !nonprime[i];
      return cnt;
    }
    
    int main() {
      register int i, sum=0;
      for (i=0; i<LOOPS; ++i)
        sum += f(i&0xFF);
      printf("%d\n", sum);
      return 0;
    }
    
    gcc -DLOOPS=1000000 -Ofast -std=c11 c.c -o c
    stat -c%s c
    time ./c
    time ./c
    
    g++ -DLOOPS=1000000 -Ofast cc.cc -o cc
    stat -c%s cc
    time ./cc
    time ./cc
    

    8171
    30033867
    1.17user 0.00system 0:01.17elapsed 99%CPU (0avgtext+0avgdata 392maxresident)k
    0inputs+0outputs (0major+137minor)pagefaults 0swaps
    30033867
    1.17user 0.00system 0:01.17elapsed 99%CPU (0avgtext+0avgdata 388maxresident)k
    0inputs+0outputs (0major+136minor)pagefaults 0swaps
    9277
    30033867
    1.60user 0.00system 0:01.60elapsed 99%CPU (0avgtext+0avgdata 944maxresident)k
    0inputs+0outputs (0major+294minor)pagefaults 0swaps
    30033867
    1.60user 0.00system 0:01.60elapsed 99%CPU (0avgtext+0avgdata 944maxresident)k
    0inputs+0outputs (0major+294minor)pagefaults 0swaps

    Der Fairness halber nochmal mit vector<char> :

    9479
    30033867
    1.20user 0.00system 0:01.20elapsed 99%CPU (0avgtext+0avgdata 956maxresident)k
    0inputs+0outputs (0major+297minor)pagefaults 0swaps
    30033867
    1.20user 0.00system 0:01.20elapsed 99%CPU (0avgtext+0avgdata 952maxresident)k
    0inputs+0outputs (0major+296minor)pagefaults 0swaps



  • Ich weiss nicht worüber hier gestritten wird. Klar braucht dynamische Speicherverwaltung Zeit.

    Deswegen ist std::vector aber nicht schlecht. Nur ist std::vector natürlich auch keine Silver-Bullet (zwar knapp dran, aber halt doch nicht ganz).

    Es hat schon nen guten Grund dass über die Standardisierung einer VLA Alternative für C++ diskutiert wird.

    @objdump
    Woo-hoo, heisse 3% schneller.
    Wenns auf die 3% ankommt: toll.
    Wenn nicht: blöd dass dein C Programm bei grösseren n einfach abkackt. Das 3% langsamere C++ Programm hat das Problem nicht (bzw. erst bei viel grösseren n ).



  • hustbaer schrieb:

    @objdump
    Woo-hoo, heisse 3% schneller.
    Wenns auf die 3% ankommt: toll.
    Wenn nicht: blöd dass dein C Programm bei grösseren n einfach abkackt. Das 3% langsamere C++ Programm hat das Problem nicht (bzw. erst bei viel grösseren n ).

    Wenns mal 3% wären.
    Ich wollte es gerade mal testen, wie viele Zeichen man ändern muss, um kein Performanceproblem mehr zu haben. Vielleicht den vector in der main anlegen und der f leihen? Oder ob es nicht viel einfacheren/schnelleren Code mit der selben Ausgabe gibt. Aber das hat sich erledigt, da auf meinem Rechner C++ eh schneller war.

    Gemessen mit vector<char> und

    #!/bin/bash
    set -x
    
    gcc -DLOOPS=1000000 -Ofast -std=c11 c.c -o c
    stat -c%s c
    time ./c
    time ./c
    
    g++ -DLOOPS=1000000 -Ofast cc.cc -o cc
    stat -c%s cc
    time ./cc
    time ./cc
    

    Ausgabe:

    + gcc -DLOOPS=1000000 -Ofast -std=c11 c.c -o c
    + stat -c%s c
    8088
    + ./c
    30033867
    
    real	0m0.516s
    user	0m0.513s
    sys	0m0.001s
    + ./c
    30033867
    
    real	0m0.513s
    user	0m0.510s
    sys	0m0.001s
    + g++ -DLOOPS=1000000 -Ofast cc.cc -o cc
    + stat -c%s cc
    12716
    + ./cc
    30033867
    
    real	0m0.507s
    user	0m0.505s
    sys	0m0.001s
    + ./cc
    30033867
    
    real	0m0.506s
    user	0m0.503s
    sys	0m0.001s
    

    Komisch.



  • volkard schrieb:

    Komisch.

    Verständlich, wenn dein System bool in long long speichert.

    #include <stdio.h> 
    #include <string.h> 
    
    int f(int n) { 
      register int i, j, cnt; 
      char nonprime[n];
      memset(nonprime, 0, n); 
    
      for (i=2; i<n; ++i) 
        if (!nonprime[i]) 
          for (j=2; i*j<n; ++j) 
            nonprime[i*j]=1; 
    
      cnt = 0; 
      for (i=2; i<n; ++i) 
        cnt += !nonprime[i]; 
      return cnt; 
    } 
    
    int main() { 
      register int i, sum=0; 
      for (i=0; i<LOOPS; ++i) 
        sum += f(i&0xFF); 
      printf("%d\n", sum); 
      return 0; 
    }
    

    Auf einem anderen Rechner erhalte ich dann 0.821s für C gegen 0.870s C++.



  • reinfall schrieb:

    Beides scheisse. strlen ist sogar noch scheissiger, selbst wenn strlen(suchbegriff) nur einmal berechnet wird (ausser in speziellen Umständen). Besser wird das, wenn du für jeden String auch noch die Länge mitspeicherst, aber selbst das ist dann immer noch eine verkappte Hashfunktion.

    Wenn es dir wirklich um Geschwindigkeit geht bekommst du diese nicht durch Feintunen der Implementierung sondern durch Verbesserung des Algorithmus. qsort + bsearch wäre ein erster Schritt, der nächste wäre ein Upgrade auf C++11 und unordered_set.

    In dem Fall hat er Recht. Das Problem ist hier nicht, ob strcmp oder strlen schneller sind, sondern dass evtl. dein Container nicht optimal ist.

    Eine HashMap kannst du in C auch selber schreiben. Eben nicht als Template sondern spezialisert für C-Strings. Ist eigentlich keine große Sache. Auch wenn deine HashMap vielleicht anfangs noch nicht so perfekt ist ( Stichwort HashKey-Genenerierung ), so ist es auf jeden Fall schon mal besser als ein simples Array aus Strings, besonders dann wenn man suchen muss.

    Ersatzweise könntest du auch, wie schon erwähnt, die Strings erstmal nach Länge sortieren, oder gar alle Strings der gleichen Länge in einer Struktur / Liste sammeln.

    In jedem Fall muss ein besserer Container her.



  • SeppJ schrieb:

    dot schrieb:

    fairy story schrieb:

    Btw. kann ich mir in C einen Sortieralgo auch selber schreiben, wenn mir qsort zu lahm sein sollte.

    Schwachsinn, das offensichtliche Gegenbeispiel qsort vs. std::sort wurde ja schon genannt...

    Recht hat er schon, aber er widerlegt sich damit auch selber. Ein selbst geschriebenes, spezialisiertes qsort kann so schnell sein wie std::sort. Das ist doch gerade das Problem, dass der C++-Programmierer bloß eine Zeile schnell hinkritzeln braucht, während in C an dieser Stelle eine nicht unwesentliche Entwicklungsarbeit nötig ist. Ein paar Stunden gehen da gewiss drauf. Mehr, wenn man nicht irgendwo abschreibt sondern noch selber recherchiert, welcher Algorithmus der beste wäre und wie er optimal implementiert wird.

    Wenn aber genau die Performance eines Sortieralgorithmus der Knackpunkt ist, lohnt sich die Arbeit schon. Der größte Fehler, den man machen kann, ist die STL standardmäßig als "das schnellste" hinzunehmen. Denn das ist nicht (immer) der Fall.

    Und ja: Die Aufwände für einen Performancevergleich kann man nicht immer akzeptieren.


Anmelden zum Antworten