C ++ iostream vs. C stdio Leistung / Overhead
Ich versuche zu verstehen, wie die Leistung dieses C ++ - Codes verbessert werden kann, um ihn mit dem C-Code gleichzusetzen, auf dem er basiert. Der C-Code sieht folgendermaßen aus:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct point {
double x, y;
} point_t;
int read_point(FILE *fp, point_t *p) {
char buf[1024];
if (fgets(buf, 1024, fp)) {
char *s = strtok(buf, " ");
if (s) p->x = atof(s); else return 0;
s = strtok(buf, " ");
if (s) p->y = atof(s); else return 0;
}
else
return 0;
return 1;
}
int main() {
point_t p;
FILE *fp = fopen("biginput.txt", "r");
int i = 0;
while (read_point(fp, &p))
i++;
printf("read %d points\n", i);
return 0;
}
Der C ++ - Code sieht folgendermaßen aus:
#include <iostream>
#include <fstream>
using namespace std;
struct point {
double x, y;
};
istream &operator>>(istream &in, point &p) {
return in >> p.x >> p.y;
}
int main() {
point p;
ifstream input("biginput.txt");
int i = 0;
while (input >> p)
i++;
cout << "read " << i << " points" << endl;
return 0;
}
Ich mag, dass der C ++ - Code kürzer und direkter ist, aber wenn ich beide auf meinem Computer ausführe, erhalte ich eine sehr unterschiedliche Leistung (beide werden auf demselben Computer mit einer 138-MB-Testdatei ausgeführt):
$ time ./test-c
read 10523988 points
1.73 real 1.68 user 0.04 sys
# subsequent runs:
1.69 real 1.64 user 0.04 sys
1.72 real 1.67 user 0.04 sys
1.69 real 1.65 user 0.04 sys
$ time ./test-cpp
read 10523988 points
14.50 real 14.36 user 0.07 sys
# subsequent runs
14.79 real 14.43 user 0.12 sys
14.76 real 14.40 user 0.11 sys
14.58 real 14.36 user 0.09 sys
14.67 real 14.40 user 0.10 sys
enn Sie eines der beiden Programme mehrmals hintereinander ausführen, ändert dies nichts an dem Ergebnis, dass die C ++ - Version etwa 10x langsamer is
Das Dateiformat besteht nur aus durch Leerzeichen getrennten Doppelzeilen, z. B .:
587.96 600.12
430.44 628.09
848.77 468.48
854.61 76.18
240.64 409.32
428.23 643.30
839.62 568.58
Gibt es einen Trick, um den Overhead zu reduzieren, den ich vermisse?
Edit 1: Das Inline-Schalten des Operators scheint einen sehr geringen, aber möglicherweise erkennbaren Effekt gehabt zu haben:
14.62 real 14.47 user 0.07 sys
14.54 real 14.39 user 0.07 sys
14.58 real 14.43 user 0.07 sys
14.63 real 14.45 user 0.08 sys
14.54 real 14.32 user 0.09 sys
Dies löst das Problem nicht wirklich.
Edit 2: Ich benutze clang:
$ clang --version
Apple LLVM version 7.0.0 (clang-700.0.72)
Target: x86_64-apple-darwin15.5.0
Thread model: posix
Ich verwende weder in C noch in C ++ eine Optimierungsstufe und beide werden mit der gleichen Version von Clang auf meinem Mac kompiliert. Wahrscheinlich die Version, die mit Xcode (/ usr / bin / clang) unter OS X 10.11 geliefert wird. Ich dachte, es würde das Problem trüben, wenn ich Optimierungen auf der einen, aber nicht auf der anderen Seite aktiviere oder andere Compiler verwende.
Edit 3: Ersetzen vonistream &operator>>
mit etwas anderem
Ich habe den istream-Operator so umgeschrieben, dass er näher an der C-Version liegt, und er wurde verbessert, aber ich sehe immer noch eine ~ 5-fache Leistungslücke.
inline istream &operator>>(istream &in, point &p) {
string line;
getline(in, line);
if (line.empty())
return in;
size_t next = 0;
p.x = stod(line, &next);
p.y = stod(line.substr(next));
return in;
}
Runs:
$ time ./test-cpp
read 10523988 points
6.85 real 6.74 user 0.05 sys
# subsequently
6.70 real 6.62 user 0.05 sys
7.16 real 6.86 user 0.12 sys
6.80 real 6.59 user 0.09 sys
6.79 real 6.59 user 0.08 sys
Interessanterweise kompiliert dies mit-O3
ist eine wesentliche Verbesserung:
$ time ./test-cpp
read 10523988 points
2.44 real 2.38 user 0.04 sys
2.43 real 2.38 user 0.04 sys
2.49 real 2.41 user 0.04 sys
2.51 real 2.42 user 0.05 sys
2.47 real 2.40 user 0.05 sys
Edit 4: Ersetzen des Körpers von istream operator >> durch C stuff
Diese Version kommt der Leistung von C: @ sehr na
inline istream &operator>>(istream &in, point &p) {
char buf[1024];
in.getline(buf, 1024);
char *s = strtok(buf, " ");
if (s)
p.x = atof(s);
else
return in;
s = strtok(NULL, " ");
if (s)
p.y = atof(s);
return in;
}
Unoptimiertes Timing bringt uns in das 2-Sekunden-Gebiet, wo die Optimierung es über das nicht optimierte C stellt (optimiertes C gewinnt jedoch immer noch). Um genau zu sein, ohne Optimierungen:
2.13 real 2.08 user 0.04 sys
2.14 real 2.07 user 0.04 sys
2.33 real 2.15 user 0.05 sys
2.16 real 2.10 user 0.04 sys
2.18 real 2.12 user 0.04 sys
2.33 real 2.17 user 0.06 sys
Mit
1.16 real 1.10 user 0.04 sys
1.19 real 1.13 user 0.04 sys
1.11 real 1.06 user 0.03 sys
1.15 real 1.09 user 0.04 sys
1.14 real 1.09 user 0.04 sys
The C mit Optimierungen, nur um Äpfel zu Äpfeln zu tun:
0.81 real 0.77 user 0.03 sys
0.82 real 0.78 user 0.04 sys
0.87 real 0.80 user 0.04 sys
0.84 real 0.77 user 0.04 sys
0.83 real 0.78 user 0.04 sys
0.83 real 0.77 user 0.04 sys
Ich nehme an, ich könnte damit leben, aber als Anfänger in C ++ frage ich mich jetzt, ob:
Lohnt es sich, dies anders zu machen? Ich bin nicht sicher, ob es darauf ankommt, was im istream-Operator >> passiert. Gibt es eine andere Möglichkeit, den C ++ - Code zu erstellen, der neben diesen drei Möglichkeiten möglicherweise eine bessere Leistung erbringt?Ist das idiomatisch? Wenn nicht, akzeptieren die meisten Leute die Aufführung nur für das, was sie ist?Edit 5: Diese Frage unterscheidet sich grundlegend von der Antwort zu printf. Ich verstehe nicht, wie die verknüpfte Frage, die angeblich ein Duplikat von Adressen ist, einen der drei Punkte direkt darüber enthält.