-
Notifications
You must be signed in to change notification settings - Fork 2
GameFileMapper
Das GameFileMapper Projekt ist ein Hilfsprojekt. Es wurde eingeführt, um die Daten aus der Originaldatei in ein neues, effizienter verarbeitbares Format zu überführen um somit den Leseprozess zu beschleunigen.
Die Sensor-Rohdaten besitzen ein wohlgeformtes Format. Ein typischer Eintrag aus der Aufzeichnung besitzt das Format:
69,10632024809835772,27679,-221,1011,553570,2481132,-9441,2048,2580,-8913,1107,4396
Die Bedeutung der Werte folgt der in der Kommunikationsarchitektur vorgestellten Grundstruktur. Insgesamt wurden während eines Spieles 49.576.081 Einträge aufgezeichnet. Das entspricht einem Datenvolumen von 4.255.018.857 Bytes und einer Eintragsdichte von einem Eintrag pro 86 Bytes.
Um einen Eintrag aus der Originaldatei auszulesen, musste ein unangemessener Verarbeitungsaufwand eingeplant werden. Damit die eigentliche Kernaufgabe des Traffic-Generators, also die Übertragung der Daten in Echtzeit, nicht durch einen zu langsamen Leseprozess gestört wird, soll diese Komponente durch eine höhere Eintragsdichte den Leseprozess beschleunigen.
Die wesentlich interessantere Intention stellt jedoch die Messung der Prozessgrößen dar. Mithilfe der Originaldatei konnte bereits eine echtzeitfähige Kommunikation umgesetzt werden, allerdings wirkt sich die wesentlich ineffizientere Datenstruktur negativ auf den Übertragungsprozess unter Volllast aus. Die Ursache für dieses Verhalten korreliert direkt mit dem hohen Datenvolumen, da das Auslesen der Originaldatei mit 4 GByte bereits wesentlich den Prozessablauf stört. Es soll daher eine Datenstruktur entworfen werden, die durch weniger Redundanz und sinnvolle Aufteilungen den Leseprozess beschleunigt und somit eine sinnvolle, weitestgehend störungsfreie Messung der Übertragungsgeschwindigkeit ermöglicht.
Das Format der Sensor-Rohdaten bietet verschiedene Möglichkeiten der Optimierung an. Das erste Problem stellt das menschenlesbare Format dar. Will man beispielsweise den ersten Wert eines Eintrages auslesen, können unterschiedliche Verfahren angewendet werden.
Der primitive Ansatz könnte über ein einfaches Splitting der Werte realisiert werden. Da die Werte eines Eintrages über einen vorgeschriebenen Delimiter (,) getrennt werden, kann natürlich jeder Eintrag mit einem regulären Ausdruck in seine Bestandteile zerlegt werden. Dieser Ansatz würde aufgrund der bereits durch Java umgesetzten Vorverarbeitung und der zusätzlich langsamen Verarbeitung des regulären Ausdrucks zu Performance-Einbußen führen (auch wenn sie vernachlässigbar sind).
Als alternativen Ansatz könnte man versuchen die Daten sequentiell auszulesen und somit die Verarbeitung zu beschleunigen. Der interessante Faktor bei diesem Ansatz ist natürlich die einmalige Datenverarbeitung. Wenn ein Wert gelesen werden soll, muss solange ein Lesepuffer gefüllt werden bis der Delimiter auftritt. Schließlich kann der Puffer in einen realen Wert umgewandelt und der Puffer gelöscht werden. Dies führt bereits zu einer wesentlich höheren Performance, da die gesamte Vorverarbeitung durch Java wegfällt und sogar die Auswertung eines regulären Ausdrucks direkt durchgeführt werden kann. Eine ähnliche Umsetzung würde sich entsprechend für die neue Datenstruktur anbieten.
Besonders beim sequentiellen Auslesen der Daten erkennt man jedoch, dass einige Potentiale noch ungenutzt bleiben. Obwohl bei beiden Ansätzen bereits ein "Vorpuffern" von größeren Datenblöcken stattfinden sollte, können in beiden Fällen die Größe/Länge eines Wertes variieren. Das führt dazu, dass man stets einen Test auf den sowieso irrelevanten Delimiter durchführen muss. Für eine optimale Verarbeitung wäre es ideal, wenn man die Länge eines Wertes kennt und sofort den Wert auslesen kann. Die angestrebte und auch schließlich auch umgesetzte Lösung wandelt daher die dezimalen Werte in ein Binärformat mit einer festen Breite pro Wert um. Die somit gespeicherten Werte besitzen dabei die Länge der Typen, wie sie in der Datengrundlage definiert sind (Integer: 4 Byte, Long: 8 Byte). Da es sich zudem nur um ein einheitliches Datenformat handelt, können die Daten auch ohne Delimiter abgelegt werden.
Das neue Datenformat folgt dabei dem Schema:
4 Byte (int), 8 Byte (int), 11 * 4 Byte (int)
Als Kennwerte ergeben sich entsprechend:
- Größe: 2.776.260.480 Bytes (~35% weniger Datenvolumen)
- Eintragsdichte: 1 Eintrag pro 56 Byte
Insgesamt können mit diesem neuen Format 35% des Datenvolumens eingespart werden, was sich wiederrum direkt auf die Lesegeschwindigkeit auswirkt, da nun auch entsprechend weniger Daten eingelesen werden müssen. Neben dem geringeren Datenvolumen ist nun auch die logische Verarbeitung der Daten wesentlich performanter, da kein Vergleich über einen Delimiter ausgeführt werden muss. Beispielsweise kann nun ein lesender Prozess den ersten Wert auslesen, indem er direkt die ersten 4 Bytes ausliest und in einen Integer-Wert umwandelt.
Das GameFileMapper Projekt muss zur Umwandlung der Daten zuerst konfiguriert werden. Dafür ist in der main
-Methode sowohl der Pfad zur entpackten Originaldatei (full-game) anzugeben. Zusätzlich muss der Pfad inklusive Dateiname für die zu erstellende Datei angegeben werden. Die Ausgabedatei muss nicht existieren, aber das Verzeichnis, in dem die Datei erstellt werden soll, muss beschreibbar sein.