Erklären Änderung auf GNU C ++ filebuf :: Unterlauf () Interagieren mit filebuf :: seekoff ()

StackOverflow https://stackoverflow.com/questions/3678010

  •  01-10-2019
  •  | 
  •  

Frage

laufen Unsere Produkte über eine Reihe von qualifizierten Linux Hardware / Software-Konfigurationen. Historisch gesehen, verwendet der Compiler hat C gewesen GNU ++. Für die Zwecke dieser Post, lassen Sie uns betrachten Version 3.2.3 die Basislinie, da unsere Software ‚arbeitete als erwartet‘ durch diese Version.

Mit der Einführung einer neueren qualifizierten Plattform, mit GNU C ++ Version 3.4.4 haben wir begonnen, einige Performance-Probleme zu beobachten, die wir vorher nicht gesehen hatten. Nach einigem Graben, kam einer unserer Ingenieure mit diesem Testprogramm auf:

#include <fstream>
#include <iostream>

using namespace std;

class my_filebuf : public filebuf
{
public:

   my_filebuf() : filebuf(), d_underflows(0) {};
   virtual ~my_filebuf() {};

   virtual pos_type seekoff(off_type, ios_base::seekdir,
                            ios_base::openmode mode = ios_base::in | ios_base::out);

   virtual int_type underflow();

public:
   unsigned int d_underflows;
};

filebuf::pos_type my_filebuf::seekoff(
   off_type           off,
   ios_base::seekdir  way,
   ios_base::openmode mode
)
{
   return filebuf::seekoff(off, way, mode);
}

filebuf::int_type my_filebuf::underflow()
{
   d_underflows++;

   return filebuf::underflow();
}

int main()
{
   my_filebuf fb;
   fb.open("log", ios_base::in);
   if (!fb.is_open())
   {
      cerr << "need log file" << endl;
      return 1;
   }

   int count = 0;
   streampos pos = EOF;
   while (fb.sbumpc() != EOF)
   {
      count++;

      // calling pubseekoff(0, ios::cur) *forces* underflow
      pos = fb.pubseekoff(0, ios::cur);
   }

   cerr << "pos=" << pos << endl;
   cerr << "read chars=" << count << endl;
   cerr << "underflows=" << fb.d_underflows << endl;

   return 0;
}

Wir liefen sie gegen eine Log-Datei von ca. 751KB Zeichen. In den bisherigen Konfigurationen haben wir das Ergebnis:

$ buftest
pos=768058
read chars=768058
underflows=0

In der neueren Version ist das Ergebnis:

$ buftest
pos=768058
read chars=768058
underflows=768059

Kommentar aus dem pubseekoff (0, ios :: Aktuell) Anruf und die übermäßige Unterschreitung () Anrufe gehen weg. So klar, in neueren Versionen von g ++ Aufruf pubseekoff () 'Ungültigmachungseinträge' der Puffer, um einen Anruf zu Zwingen Unterschreitung () .

Ich habe das Standarddokument lesen, und den Wortschwall auf pubseekoff () ist sicherlich nicht eindeutig. Wie ist das Verhältnis der zugrunde liegenden Dateizeigerposition, die der GPTR () , zum Beispiel? Vor oder nach ein Aufruf an Unterschreitung () ? Unabhängig davon, finde ich es irritierend, dass g ++ ‚geändert Pferde in Midstream‘, sozusagen. Außerdem, selbst wenn ein allgemeine seekoff () erforderlich, um die Pufferzeiger ungültig zu machen, warum sollte das Äquivalent von ftell ()

Kann jemand Punkt mich zu einer Diskussion unter den Implementierer, die im Verhalten zu dieser Änderung geführt? Haben Sie eine kurze Beschreibung der Entscheidungen und Abwägungen beteiligt?

Extra Credit

Klar weiß ich wirklich nicht, was ich tue. Ich experimentiere, um zu bestimmen, ob es eine Möglichkeit gäbe, aber nicht tragbar, zu umgehen die Entwertung in dem Fall, dass Offset 0 ist und seekdir ist ios :: cur . Ich kam mit dem folgenden Hack auf, die direkten Zugriff auf die filebuf Datenelement _M_file (dies wollte nur mit der 3.4.4-Version auf meinem Rechner kompilieren):

int sc(0);
filebuf::pos_type my_filebuf::seekoff(
   off_type           off,
   ios_base::seekdir  way,
   ios_base::openmode mode
)
{
   if ((off == 0) && (way == ios::cur))
   {
      FILE *file =_M_file.file();
      pos_type pos = pos_type(ftell(file));

      sc++;
      if ((sc % 100) == 0) {
         cerr << "POS IS " << pos << endl;
      }

      return pos;
   }

   return filebuf::seekoff(off, way, mode);
}

Allerdings ist die Diagnose, die Position drucken alle hundert seekoff Versuche Erträge 8192 jedes Mal. Huh? Da dies die Datei * Mitglied der filebuf selbst, würde ich es Dateipositionszeiger werden synchron mit jeder Unterschreitung () erwarten Anrufe, die von der filebuf gemacht. Warum bin ich falsch?

Update

Lassen Sie mich zunächst betonen, dass ich das später Teil meines Posts verstehen alles über nicht-portable Hacks ist. Noch verstehen, nicht die winzigsten hier. Ich habe versucht Aufruf

pos_type pos = _M_file.seekoff(0,ios::cur);

statt, und das glücklich Fortschritte durch die Beispieldatei, anstatt bei 8192 stecken zu bleiben.

Endgültigen aktualisieren

Intern meiner Firma haben wir einige Abhilfen gemacht, dass die Leistung reduzieren getroffen genug können wir damit leben.

Nach außen eingereicht David Krauss einen Bug gegen GNU libstdc ++ Streams und vor kurzem geprüft Paolo Carlini in einer Lösung. Der Konsens war, dass das unerwünschte Verhalten im Rahmen des Standard war, aber dass es eine vernünftige Lösung für den Rand Fall war ich beschrieben.

So danke, Stackoverflow, David Krauss, Paolo Carlini und alle GNU-Entwickler!

War es hilfreich?

Lösung

Die Anforderungen an seekoff sicherlich verwirrend sind, aber seekoff(0, ios::cur) soll ein Sonderfall sein, die synchronize etwas nicht. So könnte dies wahrscheinlich einen Fehler in Betracht gezogen werden.

Und es geschieht immer noch in GCC 4.2.1 und 4.5 ...

Das Problem ist, dass (0, ios::cur) in _M_seek nicht besondere Gefasste ist, die seekoff Verwendungen Anruf fseek ihren Rückgabewert zu erhalten. Solange das gelingt, _M_seek bedingungslos nennt _M_set_buffer(-1);, die vorhersagbar den internen Puffer ungültig. Die nächste Leseoperation verursacht underflow.

gefunden die diff! ändern -473,41 +486,26 ansehen. Kommentar war

    (seekoff): Simplify, set _M_reading, _M_writing to false, call
    _M_set_buffer(-1) ('uncommitted').

Das war also nicht einen Fehler zu beheben getan.

Filed Fehler: http://gcc.gnu.org/bugzilla/ show_bug.cgi? id = 45628

Andere Tipps

Nun, ich weiß nicht, den genauen Grund für die Änderung, aber anscheinend wurden die Änderungen vorgenommen für (Siehe GCC 3.4 Series Changelog ):

  • Optimiertes streambuf, filebuf, trennen mit C Standard I synched / O streambuf.
  • Unterstützung für große Dateien (Dateien, die größer als 2 GB auf 32-Bit-Systemen).

Ich vermute, dass Unterstützung für große Dateien das große Feature ist, das eine Änderung wie diese erfordern würde, weil iostreams nicht mehr davon ausgehen, kann es die gesamte Datei in dem Speicher abbilden kann.

Die korrekte Synchronisation mit cstdio ist auch eine Operation, die eine größere Anzahl von Spülungen auf die Platte erforderlich machen könnte. Sie können deaktivieren, dass die Verwendung std::sync_with_stdio .

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top