Parsen einer großen Matroska Datei

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
hubblec4
Beiträge: 341
Registriert: Sa 25. Jan 2014, 17:50

Parsen einer großen Matroska Datei

Beitrag von hubblec4 »

Hallo Lazarus Gemeinde

Eine Frage habe ich bevor ich weiter mit suchen und probieren verbringe.

Ich habe einen eigenen Matroska Parser geschrieben, welcher durch die Bytes "rattert" und mir die Daten ausliest.

Meistens gibt es Such-Eintrage und man kann schneller an die gewünschten Positionen springen.
Aber manchmal muss man eben auch alle Level 1 Elemente durchlaufen.
Dabei passiert es das wenn ich eine Datei zum erstenmal parse, dasss es gut und gerne 10-20 Sekunden dauert.
Lade ich die Datei ein zweites mal dauert das parsen keine 50ms mehr.

Es werden ca. 6000 bis 8000 Cluster-Einträge gefunden.

Warum geht das beim erstenmal laden so langsam?
Liegt das an Windows?

LG
Hubble

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Parsen einer großen Matroska Datei

Beitrag von Mathias »

Dies könnte am Cache des OS liegen, verwendest du noch eine Magnetplatte ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

hubblec4
Beiträge: 341
Registriert: Sa 25. Jan 2014, 17:50

Re: Parsen einer großen Matroska Datei

Beitrag von hubblec4 »

Ja die mkv liegt auf auf einer Magnetplatte.

EDIT:

Mir war auch aufgefallen das die Prozessorauslastung nie ansteigt. Für mein Prgramm werden 0% angezeigt.
Ich dachte, wenn sich das Programm in einer Schleife festhängt, dass dann auch der ganze Core voll belastet wird.

Habe die mkv mal auf eine SSD kopiert und da gehts ruckzuck. Danke für den Hinweis.

hubblec4
Beiträge: 341
Registriert: Sa 25. Jan 2014, 17:50

Re: Parsen einer großen Matroska Datei

Beitrag von hubblec4 »

Hi Mathias,
doch noch eine Frage:

Wenn ich die Magnet Platte benutzen muss, kann ich das im Windows einstellen das nicht gecacht wird, oder kann man das sogar im Programm mit etwas Code erledigen?

Oder muss man bei Magnetplatten einfach damit leben?

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Parsen einer großen Matroska Datei

Beitrag von wp_xyz »

Es kommt darauf an, wie du die Datei eingelesen hast. Mit Dateizugriffen oder einem FileStream? Damit wird's langsam. Wenn die Datei nicht zu groß ist, würde ich sie z.B. per MemoryStream lesen - damit liegt die Datei für die Analyse im Speicher, oder wenn sie zu groß ist, per TBufStream oder Varianten (z.B. dem aus fpspreadsheet) - diese Streams lesen die die Datei häppchenweise in den Speicher und laden dann nach, wenn das Häppchen nicht mehr ausreicht.

Für konkretere Hinweise bräuchte ich etwas mehr Code von dir.

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Parsen einer großen Matroska Datei

Beitrag von Mathias »

Wenn ich die Magnet Platte benutzen muss, kann ich das im Windows einstellen das nicht gecacht wird,

Bei Wechseldatenträger hat/hatte es in der Systemsteuerung ein Option um den Schreibcache abzustellen, ob es dies bei Fest installierten HDs auch gibt, weis ich nicht mehr. Auf jeden Fall eine Sache des OS.

Es kommt darauf an, wie du die Datei eingelesen hast. Mit Dateizugriffen oder einem FileStream? Damit wird's langsam.

Da kann ich voll zustimmen, eine Datei mit Write(f, Byte); in einer Schleife zu schreiben/lesen geht gähnend langsam, auch auf einer SSD.
Am schnellsten geht es eindeutig mit etwas, das Blockweise schreibt/liest. Am elegantesten, wie wp_xyz schreibt.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: Parsen einer großen Matroska Datei

Beitrag von siro »

Ich habe gute Erfahrungen mit Blockread gemacht.
und die ganze Datei eingelesen. Das geht immer Blitzartig.

Code: Alles auswählen

 
var size:Cardinal;
var readed : Cardinal;
var f:file;
var buffer:^Byte;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  AssignFile(F,'C:\Siro\xxx.xxx');
  Reset(F,1);                      // Byteweise lesen Recordgröße = 1 Byte
  size:=FileSize(f);               // Dateigrüsse ermitteln
  ReturnNilIfGrowHeapFails:=TRUE// GetMem liefert nun NIL wenn nicht genug Speicher da ist.
  GetMem(Buffer,size);             // Versuchen Speicher zu reservieren
  if Buffer <> NIL then begin           // wenn genug Speicher da ist, dann
    BlockRead(F,buffer^,size,readed);   // komplette Datei einlesen
  end;
  CloseFile(f)// Datei schliessen
  // nun sollte Alles im Speicher liegen
  // ....PARSEN ......
  // nicht vergessen, den Speicher wieder freizugeben
  if Buffer <> NIL then FreeMem(Buffer,size);
end;               
 
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

hubblec4
Beiträge: 341
Registriert: Sa 25. Jan 2014, 17:50

Re: Parsen einer großen Matroska Datei

Beitrag von hubblec4 »

Es ist nicht sehr viel Code den ich zum einlesen einer Binär-Datei nutze(hatte das hier im Forum gefunden)

Code: Alles auswählen

 
const FMkPath: String='Pfad zur Matroska Datei.mkv';
var
File_Size: QWord;
FMkFile: TFileStream;
 
FMkFile:=TFileStream.Create(FMkPath,fmOpenRead or fmShareDenyNone);
File_Size:=FMkFile.Size;                      // Datei Größe ermitteln
 


Dann beginnt auch schon das Parsen.

Matroska Dateien sind oft sehr groß, so um die 30gb.
@siro
Wird dann bei dem häppchenweisen Einlesen auch die ganzen 30gb in den Arbeitsspeicher geladen? Denke mal das wird so nicht gehen.

@wp_xyz
Ok da werde ich mich mal mit dem fpspreadsheet befassen müssen.
Ich weis jetzt nicht in wie weit mein obiger Code dir schon aussreicht, denn der Parser Code ist bissl umfangreicher.
Ich bin mir auch sicher das ich da nicht perfekten Code verwende(dennoch schnell ist der Parser).
Es werden halt Bytes ausgelesen und verarbeitet

Code: Alles auswählen

 
FMkFile.Read(IntTemp,nBytes);
 



Auf meiner SSD ist das parsen ja sehr sehr flott, muss das vll noch bissl testen und vorallem den Parser noch kompletieren um genau sagen zu können wie lange es dauert. Und wie gesagt beim zweiten mal einlesen geht es ja auch auf der Magnetplatte sehr schnell (keine 50ms).

siro
Beiträge: 730
Registriert: Di 23. Aug 2016, 14:25
OS, Lazarus, FPC: Windows 11
CPU-Target: 64Bit
Wohnort: Berlin

Re: Parsen einer großen Matroska Datei

Beitrag von siro »

Upps, 30 Gigabyte :shock: sind natürlich ne Menge, ich dachte so ein/zwei und die hat ja heutzutage jeder im Speicher übrig.
Ich glaube bei GetMem lagert das System automatisch wieder auf Festplatte aus, wenn nicht genügend Speicher zur Verfügung steht.
Das gibt dann natürlich nicht mehr wirklich Sinn... :roll:
Zudem fällt mir grad auf, der "cardinal" (Größe 4 Bytes) müsste ein"QWord" (8 Bytes) sein.
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Parsen einer großen Matroska Datei

Beitrag von wp_xyz »

hubblec4 hat geschrieben:Ok da werde ich mich mal mit dem fpspreadsheet befassen müssen.
 

Musst du nicht. Der gepufferte Stream steckt in der Unit fpsstreams (https://sourceforge.net/p/lazarus-ccr/s ... treams.pas); diese ist autark und kann auch unabhängig von fpspreadsheet verwendet werden -> einfach ins Projektverzeichnis kopieren.

Eigentlich müsstest du nur in deinem Beispiel oben TFileStream durch TBufStream ersetzen, als optionalen letzten Parameter kannst du noch die Buffer-Größe angeben, aber der Defaultwert ist mit 1MB wahrscheinlich eh schon zu groß. Ist allerdings wahrscheinlich nie mit 30 GB-Dateien getestet worden, insofern wäre ich dankbar für deine Erfahrungen.

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: Parsen einer großen Matroska Datei

Beitrag von theo »

wp_xyz hat geschrieben:Musst du nicht. Der gepufferte Stream steckt in der Unit fpsstreams (https://sourceforge.net/p/lazarus-ccr/s ... treams.pas); diese ist autark und kann auch unabhängig von fpspreadsheet verwendet werden -> einfach ins Projektverzeichnis kopieren.


Ist dieser besser, bzw. was ist der Unterschied zu dem in in Unit "bufstream", welcher zur FCL gehört? https://www.freepascal.org/docs-html/fc ... tream.html

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Parsen einer großen Matroska Datei

Beitrag von wp_xyz »

Ehrlich gesagt, weiß ich nicht mehr, warum ich den Stream-Typ geschrieben habe, auf jeden Fall bin ich mit dem FCL-BufStream nicht klargekommen, weil man den für's Lesen und Schreiben getrennt erzeugen muss. Der FPSpreadsheet-BufStream kann beides in einem. Für hubblec4's Dateien müsste aber wahrscheinlich der FPC-BufStream auch reichen.

Benutzeravatar
theo
Beiträge: 10467
Registriert: Mo 11. Sep 2006, 19:01

Re: Parsen einer großen Matroska Datei

Beitrag von theo »

OK, Danke.
Es hatte mich nur stutzig gemacht, warum du nicht die Unit aus der FCL empfiehlst.
Hubble muss afaics eh nur lesen.

hubblec4
Beiträge: 341
Registriert: Sa 25. Jan 2014, 17:50

Re: Parsen einer großen Matroska Datei

Beitrag von hubblec4 »

siro hat geschrieben:Upps, 30 Gigabyte :shock: sind natürlich ne Menge, ich dachte so ein/zwei und die hat ja heutzutage jeder im Speicher übrig.
Ich glaube bei GetMem lagert das System automatisch wieder auf Festplatte aus, wenn nicht genügend Speicher zur Verfügung steht.
Das gibt dann natürlich nicht mehr wirklich Sinn... :roll:
Zudem fällt mir grad auf, der "cardinal" (Größe 4 Bytes) müsste ein"QWord" (8 Bytes) sein.



Yupp Matroska Datein können groß sein, daher muss ich immer/oft mit QWord arbeiten. Ok, fällt das also weg, dennoch danke für deine Hilfe und den Code.


wp_xyz hat geschrieben:Eigentlich müsstest du nur in deinem Beispiel oben TFileStream durch TBufStream ersetzen, als optionalen letzten Parameter kannst du noch die Buffer-Größe angeben, aber der Defaultwert ist mit 1MB wahrscheinlich eh schon zu groß. Ist allerdings wahrscheinlich nie mit 30 GB-Dateien getestet worden, insofern wäre ich dankbar für deine Erfahrungen.


Ja ok, das kann ich gerne testen. Trotzdem muss ich da jetzt fagen: Der TBufStream liest dann die Matroska Datei komplett in den Speicher? oder ist das Verhalten ähnlich dem von TFileStream?


Ja im momenten ist ertsmal nur das Lesen von Matroska Dateien wichtig. Aber wie es dann öfters so kommt, will man dann vielleicht auch mal "Schreiben".

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Parsen einer großen Matroska Datei

Beitrag von wp_xyz »

hubblec4 hat geschrieben:Der TBufStream liest dann die Matroska Datei komplett in den Speicher? oder ist das Verhalten ähnlich dem von TFileStream?

Nein (zur ersten Frage). Der TBufStream von fpspreadsheet erzeugt im Hintergrund einen TFileStream und liest beim Öffnen einen Bufferblock ein, dessen Größe beim Konstruieren angegeben werden kann (per Default 1MB). Stream.Read holt sich dann die Daten aus dem Buffer, nicht aus dem FileStream. Kommt man beim Lesen an eine Stelle, die noch nicht im Buffer vorgehalten wird, so wird ab dieser Stelle wieder ein Buffer eingelesen, der den bisherigen Buffer ersetzt. Welcher Ausschnitt des FileStream in dem Buffer abgebildet ist, wird mitprotokolliert, so dass die Position des BufStream immer die ist, die man hätte, wenn man direkt von einem isolierten FileStream gelesen hätte. Der Stream ist nahezu genauso schnell wie ein Memorystream, nur wird halt NICHT die ganze Datei im Speicher abgelegt. Es bringt fast nicht mehr, die Buffergröße weiter zu erhöhen, und ich denke die 1MB sind auch schon zu groß.

Der FCL-BufStream sollte ähnlich funktionieren. Nur muss man den FileStream selbst vorab erzeugen und dem TBufStream.Create als Parameter mitgeben. Und man muss für Lesen und Schreiben getrennte Instanzen erzeugen: TReadBufStream und TWriteBufStream. Der fpspreadsheet-BufStream kann beides in derselben Instanz: Man kann also zuerst eine bestimmte Stelle suchen, und dann dort etwas überschreiben. Die Schreibzugriffe werden übrigens genauso gepuffert (zuerst in den Buffer schreiben, und wenn der Buffer voll ist, in den FileStream rausschreiben).

Antworten