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.

Antworten auf die Frage(6)

Ihre Antwort auf die Frage