Suche Buffered-File Klasse



  • Nur binary IO reicht vollkommen.
    Seeken brauch ich auch, ja.
    (Eine Klasse die mir gleich "read at" und "write at" anbeitet wäre sogar ideal. Über seek+read bzw. seek+write geht's aber natürlich auch.)

    Eigentlich der klassische Anwendungsfall für die FILE* Funktionen, aber wie gesagt: die MSVCRT macht mir da leider einen Strich durch die Rechnung.

    BTW: bitte niemand memory-mapped IO vorschlagen. Wenn ich genügend Adressraum übrig hätte, um mit memory-mapped IO zu arbeiten, bräuchte ich garkeine Files 😉
    (Portierung auf 64 Bit möchte ich vermeiden wenns geht)



  • Ich habe leider nur bedingt eine Ahnung davon, wie man unter Windows an die Kernelmodezugriffe herankommt. Aber Du scheinst ja ein Testprogramm dafür gemacht zu haben.

    Aber wirklich plattformneutral wird es wohl schwierig werden, wenn die Standard
    IO-Funktionen nicht die gewünschte Funktionalität bieten.

    Könntest Du nichht auf Grundlage der von Dir benutzen Kernelmode-Funktionen eine eigene filebuf-Klasse implementieren, welche die gewünschte Funktionalität anbietet? Die Filebuffer lassen sich leicht austauschen, wenn man die Plattform wechselt (auf *n*x*-Systemen könnte man z.B. die Standardvariante benutzen).

    Naja, vermutlich ist die Idee völlig scheisse...



  • blöde Frage: was spricht nochmal genau gegen std::fstream? der enthaltene filebuf ist doch gepuffert. Und wenn dir dort die Pufferung nicht genug ist, dann kannst du mit streambuf::pubsetbuf() einen größeren Puffer zur Verfügung stellen. (wobei du da bei zigtausend files natürlich irgendwann aufpassen musst).



  • pumuckl schrieb:

    blöde Frage: was spricht nochmal genau gegen std::fstream? der enthaltene filebuf ist doch gepuffert. Und wenn dir dort die Pufferung nicht genug ist, dann kannst du mit streambuf::pubsetbuf() einen größeren Puffer zur Verfügung stellen. (wobei du da bei zigtausend files natürlich irgendwann aufpassen musst).

    std::fstream schafft aber nicht mehr als 2048 offene Handles gleichzeitig. Und wenn ich das richtig verstanden habe, liegt genau da das Problem. Defaultmäßig scheint es sogar noch weniger zu sein, aber über _setmaxstdio lässt sich das immerhin auf 2048 erhöhen.

    Ich habe mich gerade mal aus Interesse etwas schlau gemacht. Mit der WinAPI kommt mit den Default-Einstellungen auf 10000 offene Handles. Und es gibt Funktionen, mit denen man dies noch weiter erhöhen kann.
    Bei den Funktionen aus der CRT kommt man allerdings tatsächlich nicht über 2048.
    Ich würde da tatsächlich eine eigene filebuf Klasse auf der Grundlage der WinAPI-Funktionen implementieren. So ist es mit minimalen Aufwand möglich, das Programm zu portieren.

    Edit: Siehe auch hier



  • Tachyon schrieb:

    Ich habe leider nur bedingt eine Ahnung davon, wie man unter Windows an die Kernelmodezugriffe herankommt. Aber Du scheinst ja ein Testprogramm dafür gemacht zu haben.

    Aber wirklich plattformneutral wird es wohl schwierig werden, wenn die Standard
    IO-Funktionen nicht die gewünschte Funktionalität bieten.

    Die Lösung muss auch nicht unbedingt Plattform-Neutral sein, es reicht Windows. Ich meinte bloss, dass eine Decorator-Klasse, die auf einem ungepufferten "read/write/seek" Interface ein gepuffertes macht, eigentlich nicht OS-spezifisch ist. So war das zu verstehen. Die Windows Kernel Calls kenne ich ausreichend gut, das wäre nicht das Problem.

    Könntest Du nichht auf Grundlage der von Dir benutzen Kernelmode-Funktionen eine eigene filebuf-Klasse implementieren, welche die gewünschte Funktionalität anbietet? Die Filebuffer lassen sich leicht austauschen, wenn man die Plattform wechselt (auf *n*x*-Systemen könnte man z.B. die Standardvariante benutzen).

    Naja, vermutlich ist die Idee völlig scheisse...

    Die Idee ist nicht völlig scheisse, aber eigentlich genau das was ich vermeiden möchte: nämlich selbst was zu basteln. Solche Sachen sind extrem nervig zu testen, und ich bin (zumindest bevor ich angefangen habe zu suchen) davon ausgegangen, dass es sowas doch schon zu Hauf geben müsste.



  • pumuckl schrieb:

    blöde Frage: was spricht nochmal genau gegen std::fstream? der enthaltene filebuf ist doch gepuffert. Und wenn dir dort die Pufferung nicht genug ist, dann kannst du mit streambuf::pubsetbuf() einen größeren Puffer zur Verfügung stellen. (wobei du da bei zigtausend files natürlich irgendwann aufpassen musst).

    Nönö, siehe Tachyons Beitrag: die Pufferung von fstream wäre 100% OK, bloss verwendet die fstream Implementierung in der MSVC Library eben die FILE* Funktionen, und die FILE* Funktionen sind auf 2048 Files limitiert. Genau das ist ja das Problem. Sprich: ich kann 2048-3=2045 fstream Objekte aufmachen (fstream.open()), beim 2046. bekomm ich einfach nen Fehler. (Schon ausprobiert, also nicht bloss hörensagen 😉 )



  • Tachyon schrieb:

    pumuckl schrieb:

    blöde Frage: was spricht nochmal genau gegen std::fstream? der enthaltene filebuf ist doch gepuffert. Und wenn dir dort die Pufferung nicht genug ist, dann kannst du mit streambuf::pubsetbuf() einen größeren Puffer zur Verfügung stellen. (wobei du da bei zigtausend files natürlich irgendwann aufpassen musst).

    std::fstream schafft aber nicht mehr als 2048 offene Handles gleichzeitig. Und wenn ich das richtig verstanden habe, liegt genau da das Problem. Defaultmäßig scheint es sogar noch weniger zu sein, aber über _setmaxstdio lässt sich das immerhin auf 2048 erhöhen.

    Ganz genau. Default ist 512, was aber nicht das Problem wäre. Das Limit von 2048 bei _setmaxstdio ist das Problem.

    Ich habe mich gerade mal aus Interesse etwas schlau gemacht. Mit der WinAPI kommt mit den Default-Einstellungen auf 10000 offene Handles. Und es gibt Funktionen, mit denen man dies noch weiter erhöhen kann.

    Hm. Wo gibt's da ein 10k Limit? Ich hab ohne irgendwelche Tricks 60k offene Files hinbekommen...

    Bei den Funktionen aus der CRT kommt man allerdings tatsächlich nicht über 2048.
    Ich würde da tatsächlich eine eigene filebuf Klasse auf der Grundlage der WinAPI-Funktionen implementieren. So ist es mit minimalen Aufwand möglich, das Programm zu portieren.

    Hm.
    Hier müsste ich dann basic_streambuf implementieren, oder wie? Leider hab' ich von der ganzen iostream Geschichte kaum eine Ahnung (also speziell was die lower-level Sachen ala basic_streambuf angeht) 😞
    Wie kompliziert wäre das? Gibt's da irgendwelche Hilfsteile, z.B. in der Boost? Werde diesbezüglich wohl mal selbst gucken, aber wenn jmd. was weiss, bitte lasst es mich wissen 🙂



  • könnt man ned die crt hacken???????



  • klein kind schrieb:

    könnt man ned die crt hacken???????

    Klar.
    Man könnte sich auch ein Loch ins Knie schiessen, und dann raustrinken.



  • 10k Limit: http://support.microsoft.com/kb/327699
    Scheint aber variabel zu sein.
    Simon



  • hustbaer schrieb:

    Hm. Wo gibt's da ein 10k Limit? Ich hab ohne irgendwelche Tricks 60k offene Files hinbekommen...

    Das habe ich selbst nur aus einem Forum. 🤡
    Kann also gut Blödsinn sein. Wie im EIngangspost geschrieben, habe ich nur bedingt Ahnung, und hab mich nur aus Interesse etwas (halb) schlau gemacht.

    hustbaer schrieb:

    Hier müsste ich dann basic_streambuf implementieren, oder wie? Leider hab' ich von der ganzen iostream Geschichte kaum eine Ahnung[...]

    Ich gucke morgen noch einmal nach. Vielleicht kann auch einer der Stream-Spezis was Genaueres aus dem Stegreif sagen (Werner?).



  • theta schrieb:

    10k Limit: http://support.microsoft.com/kb/327699
    Scheint aber variabel zu sein.
    Simon

    scheint sich nur auf user32.dll zu beziehen.



  • So.

    Hab mir mal die Boost.Iostreams ganz kurz angeguckt. Sieht so aus, als ob da alles drin wäre was ich brauche (und mehr).
    boost::iostreams::stream<boost::iostreams::file_descriptor> sieht auf den ersten Blick mal genau nach dem aus, was ich gesucht habe.
    Fix & fertig, out-of-the-box gepufferte IO Klasse, auf Basis von OS-Handles! 🙂

    Ich werde berichten wie das Ding sich macht. Speziell was Memory-Overhead angeht. Performance werd ich erstmal nicht gröber testen -- solange es deutlich schneller als direkte OS-Calls ist, wird es für meine Zwecke reichen.



  • Aus Spaß an der Sache hab ich da mal was gebastelt: *klick*. Wie eine streambuf-Lösung aussieht, würde mich aber auch interessieren.

    Interface von dem Ding sieht so aus:

    class BufferedFile
    {
    	public:
    		explicit BufferedFile( const std::string& filename, std::ios_base::openmode open_mode );
    		~BufferedFile();
    
    		void seek( long long offs, std::ios_base::seek_dir dir=std::ios::beg );
    
    		size_t read( void* buffer, size_t to_read );
    		size_t readAt( void* buffer, size_t to_read, long long offs, std::ios_base::seek_dir dir=std::ios::beg );
    
    		size_t write( const void* buffer, size_t to_write );
    		size_t writeAt( void* buffer, size_t to_write, long long offs, std::ios_base::seek_dir dir=std::ios_base::beg );
    
    		unsigned long long tell() const;
    		unsigned long long size() const;
    };
    

    edit: Mist... 🙂

    edit2: Link nochmal rausgenommen, war zu Testzwecken was gefährliches drin, korrigiere morgen

    edit3: Ist wieder da und in Ordnung gebracht.



  • @Badestrand:
    Das ist nur die halbe Miete, denn Writes werden garnicht gepuffert 😉



  • hustbaer schrieb:

    @Badestrand:
    Das ist nur die halbe Miete, denn Writes werden garnicht gepuffert 😉

    Argh, natürlich! Bin bis jetzt mit gepufferten Writes quasi nie direkt in Kontakt gekommen, da hab ich's einfach vergessen.. 🙂 Gut. Hm, nagut, hab ich halt ein wenig rumgespielt. Übrigens hab ich auch generell keine Ahnung von Buffering/Caching. Ich weiß, du willst es nur anwenden, aber hast du eventuell Links zu Artikeln? Ist an sich ja ein interessantes Feld.



  • hustbaer schrieb:

    Nur im Kernel-Mode, über den normalen File-Cache.
    100.000x ReadFile mit einem Byte ist allerdings *VIEL* langsamer, als wenn im User-Mode nochmal ein (kleiner) Buffer verwendet wird.
    ...
    jeder einzige ReadFile Befehl führt dazu dass eine User-Mode -> Kernel-Mode Transition stattfindet, ein neuer IRP erstellt wird, der IRP an den zuständigen Treiber übergeben wird, dann irgendwann "bedient", dann wieder freigegeben, dann wieder eine Kernel-Mode -> User-Mode Transition, und dann irgendwann, 100 Jahre später, kommt ReadFile zurück.
    ...

    Mich würde interessieren wo du diese detailierten Informationen her hast. Konnte es zwar auch relativ schnell nachschlagen und deine Angaben bestätigen, aber mich würde interessieren ob du dieselbe Quelle verwendest. In den gängigen Büchern zur Win32-API (Petzold, Richter, Hart) steht es jedenfalls nicht. 🙂



  • Ich habe schon zwei Treiber für Windows 2000/XP geschrieben, und musste mich daher etwas mit der Materie auseinandersetzen. Waren zwar beides keine File-System Treiber, aber mein Verständnis reicht soweit, um zu wissen, dass die grundlegenden Mechanismen die selben sind. Die Informationen hab' ich zum Teil aus der DDK Dokumentation, der Compuware DriverWorks Dokumentation, und zum Teil von äusserst hilfreichen Leuten über die "ntdev" Mailing-List von OSR Online (http://www.osronline.com/).



  • Klar, ich Trottel, Treiberentwicklung. In der entsprechenden Literatur finden sich dann auch die Informationen. Daran hab ich nicht gedacht. Danke für den Hinweis.



  • Nachfrager schrieb:

    Klar, ich Trottel,

    Wieso Trottel 😕
    War doch ne ganz normale Frage...
    (Und ne ganz normale Antwort)


Anmelden zum Antworten