Parsen einer großen Matroska Datei
Parsen einer großen Matroska Datei
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
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
-
- Beiträge: 6918
- 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
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
Mit Java und C/C++ sehe ich rot
Re: Parsen einer großen Matroska Datei
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.
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.
Re: Parsen einer großen Matroska Datei
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?
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?
Re: Parsen einer großen Matroska Datei
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.
Für konkretere Hinweise bräuchte ich etwas mehr Code von dir.
-
- Beiträge: 6918
- 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
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.Wenn ich die Magnet Platte benutzen muss, kann ich das im Windows einstellen das nicht gecacht wird,
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.Es kommt darauf an, wie du die Datei eingelesen hast. Mit Dateizugriffen oder einem FileStream? Damit wird's langsam.
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
Mit Java und C/C++ sehe ich rot
-
- Beiträge: 760
- Registriert: Di 23. Aug 2016, 14:25
- OS, Lazarus, FPC: Windows 11
- CPU-Target: 64Bit
- Wohnort: Berlin
Re: Parsen einer großen Matroska Datei
Ich habe gute Erfahrungen mit Blockread gemacht.
und die ganze Datei eingelesen. Das geht immer Blitzartig.
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...
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...
Re: Parsen einer großen Matroska Datei
Es ist nicht sehr viel Code den ich zum einlesen einer Binär-Datei nutze(hatte das hier im Forum gefunden)
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
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).
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
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).
-
- Beiträge: 760
- Registriert: Di 23. Aug 2016, 14:25
- OS, Lazarus, FPC: Windows 11
- CPU-Target: 64Bit
- Wohnort: Berlin
Re: Parsen einer großen Matroska Datei
Upps, 30 Gigabyte
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...
Zudem fällt mir grad auf, der "cardinal" (Größe 4 Bytes) müsste ein"QWord" (8 Bytes) sein.

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...

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...
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...
Re: Parsen einer großen Matroska Datei
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.hubblec4 hat geschrieben: Ok da werde ich mich mal mit dem fpspreadsheet befassen müssen.
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.
Re: Parsen einer großen Matroska Datei
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.htmlwp_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.
Re: Parsen einer großen Matroska Datei
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.
Re: Parsen einer großen Matroska Datei
OK, Danke.
Es hatte mich nur stutzig gemacht, warum du nicht die Unit aus der FCL empfiehlst.
Hubble muss afaics eh nur lesen.
Es hatte mich nur stutzig gemacht, warum du nicht die Unit aus der FCL empfiehlst.
Hubble muss afaics eh nur lesen.
Re: Parsen einer großen Matroska Datei
siro hat geschrieben:Upps, 30 Gigabytesind 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...
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.
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?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 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".
Re: Parsen einer großen Matroska Datei
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ß.hubblec4 hat geschrieben:Der TBufStream liest dann die Matroska Datei komplett in den Speicher? oder ist das Verhalten ähnlich dem von TFileStream?
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).