Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Di Mär 19, 2024 05:48

Foren-Übersicht » Sonstiges » Projekte
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 64 Beiträge ]  Gehe zu Seite 1, 2, 3, 4, 5  Nächste
Autor Nachricht
 Betreff des Beitrags: Radon Framework
BeitragVerfasst: Mi Okt 06, 2010 11:00 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2621
Wohnort: Berlin
Programmiersprache: Go, C/C++
Das Radon Framework ist ein C++ Bibliothek, dessen Ziel es ist dem Entwickler möglichst viel Arbeit ab zu nehmen, wenn er ein Game, 3D Engine, Netzwerk Apps oder ähnliches entwickeln will.
So sind z.B. Interfaces für Sockets, DNS, DateTime, TimeSpan, Timer, Reflection, Portable Types, XML, Threads, Mutex, Conditions, Signals, Events, Delegates, PointerID's StackAllocator, PoolAllocator, Log, FileSystem, ProtocolService, Vector, Matrix, Quaternion, ProjectionMatrix, OpenGL1-3, Window, UnitTest, Hashtable und ne menge weiterer Klassen verfügbar.
Begonnen hab ich mitte 2009 und enthält auch portierten Code aus mein X-Dream und Karmarama Framework.
Es steht seit beginn unter Apache 2 Lizenz und nutzt auch externen Code, wie z.B. FastDelegate, URIpp, MurmurHash, libtiff, libpng und hashlib++ .
Alle externen Bibliotheken müssen unter BSD, X11, MIT oder einer Lizenz die sich genau so verhält sein(also kein lgpl oder gpl).
Die Module, welche verschiedene Backends haben können, wie z.B. Sockets, Window, XML, URI basierte Protokolle und so weiter, werden wie Java ServiceLocator aufgebaut.
Also es gibt ein NetworkServiceLocator, welcher alle auf dem System funktionierenden Backends zur Verfügung stellt und auch eines auf Default stellt.
Sollte man also Raknet und Windows Sockets verwenden wollen, dann kann man über den Servicenamen auf beide zugreifen, sofern die Services registriert werden.

Gestern hab ich Version 0.2 ins SVN gestellt, welches unter
svn://www.part-time-scientists.com/pts/ ... nframework
aktuell erreichbar ist.

Ich will im laufe der nächsten Woche auf ein eigenen Server umstellen, dann ändert sich auch die Domain.
Es kommen dann auch eine volle continuous integration über Hudson zum Einsatz.

Das ganze wird über cmake konfiguriert, welches VSC++, MinGW, Unix, NMake, Make und viele andere Makefiles sowie Projekte generieren kann.
Ich habe in 0.2 von UnitCpp auf ein eigenes UnitTest Framework umgestellt um die Abhängigkeiten weiter zu reduzieren.
Die einzigen externe Abhängigkeiten sind nun libtiff, libpng und doxygen.
Allerdings ist das Projekt so konfiguriert, dass beim fehlen die entsprechenden Module nicht mit kompiliert, bzw. die Doku. nicht generiert wird.

Mein Persönliches Ziel vom Projekt ist die Möglichkeit eine alternative zu Net+DX für Cross zu machen.
Also UI, alle erdenklichen Pattern, Container, Netzwerk, 2D/3D Hardware, Debugging und so weiter.
Ähnliche Projekte sind SDL und SFML.

Wieso mach ich genau sowas ?
Es ist nützlicher als wieder eine Neuauflage einer Gameengine zu machen, wie mein X-Dream, Karmarama und einige nicht veröffentlichten Varianten und es ist ein Endlosprojekt wo man sinnvoll seine Freizeit mit verbringen kann :)
Aktuell entwickle ich das Framework an den Stellen, die für Projekte gebraucht werden also einmal auf Arbeit und einmal für Part-Time-Scientists für eine Presentations Software. Ich versuche immer 1-2 Projekte zu haben, woran ich mein Framework weiter entwickeln kann.

Arbeit gibt es noch viel, denn nur ein Bruchteil des Codes ist schon mit Unit-Tests versehen, nur die wichtigsten teile hab ich dokumentiert und es schwirrt auch einiger toter Code im Repo rum.

Ich will es auch noch nicht groß umwerben, da es nach meiner Meinung noch zu Experimentell ist.
Deswegen will ich vorläufig nur auf diesem Forum darüber reden.

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Radon Framework
BeitragVerfasst: Mo Okt 18, 2010 18:18 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2621
Wohnort: Berlin
Programmiersprache: Go, C/C++
Ich hab nun ein Root-Server bei Strato bekommen und bin fleißig am installieren und konfigurieren.
Es wird zuerst der mir Hilfreiche Teil drauf kommen, also mail server, Hudson CI, cccc, cppcheck, cmake und einige weitere code coverage und building tools.
Der SVN Umzug wird zu einem späteren Punkt passieren, auch der Umzug auf die noch nicht aktivierte Domain radonframework.org schiebe ich vorerst auf die warte liste.
Worüber ich schon einige Woche grübel, ist die Website.
Zum einen ist mir wichtig, dass sie Leute anzieht und nicht abschreckt aber mir ist auch zum anderem wichtig, dass man alle wichtigen Infos sehr sehr schnell findet. Dann die üblichen verdächtigen, wenig platz, Kompatibilität, Design und Wartbarkeit.
Die größte Frage ist allerdings, selber machen oder etwas nehmen und anpassen bis es dann das ist was ich will und dabei doch ein teil neu schreiben.
Ich hab leider keine guten Erfahrungen mit externen CMS oder Dashboard Software gemacht.

Code Technisch gehts aktuell nicht so sehr vorran, ich habe für das Profiling Modul so weitreichende Tasks, das es wesentlich mehr Zeit braucht als gehofft.
Das Profiling Modul enthält eine SMBios Anbindung, welche das Auslese der Hardwaredaten eines PC's ermöglicht. Diese Informationen benutzt z.B. ein OS um Hardware zu erkennen und entsprechende Optimierungen, Treiber und so weiter zu verwenden.
Die wesentlichen Punkte vom SMBios liegen für das Profiling aber in der CPU, Memory, GPU und Sound.
Die Daten die man hier erhält sind sehr Umfangreich, z.B. alle Timing Werte des Memories, welche Spannung, FSB, Größe, verwendbare Größe, ist es ECC Speicher oder bei CPU die Modellreihe, Extensions, Cache, FSB, Cachegröße, Taktung, Temperatur, maximaler Hardware-Thread support, Kernanzahl und so weiter.
Um diese Daten zu lesen habe ich ein neuen ServiceLocator eingeführt, welcher aktuell ein Win2k und aufwärts Backend besitzt.
Das Linux-Backend ist fix gemacht aber die Arbeit liegt viel mehr im drum rum.
So hab ich 2 neue Klassen ReadBuffer und WriteBuffer, um einfacher und schneller den MemoryBuffer zu parsen, sowie eine neue AutoVector Klasse eingeführt, welche AutoPointer, AutoPointerArray und std::auto_ptr unterstützt. Dabei hab ich gleich noch die List Klasse vom Framework aktualisiert und dann natürlich überall die alten Klassen durch die neuen ersetzen und anpassen ^^. Ein großer Rattenschwanz.
Neben den SMBIOS gibt wird es auch ein ProfileManager und entsprechend eine TimeGraph Klasse geben, welche Informationen über die Zeit aufnimmt und als Benchmark, Log oder RessourceLog genutzt werden.
Es gab noch einige fixes aber sonnst ist nicht mehr zu berichten.

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Radon Framework
BeitragVerfasst: Fr Okt 22, 2010 11:12 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2621
Wohnort: Berlin
Programmiersprache: Go, C/C++
Der erste Website Entwurf steht und bis auf die Icons und das noch auskommentierte Contact bin ich damit zu frieden.
Contact benutzt Captcha und ein Text-Feld um mir eine Mail zu senden, da ich nicht meine e-mail Adresse rein stellen wollte.
Ab sofort findet man das Projekt unter folgender Domain.
http://www.radonframework.org/
Die Seite ist übersichtlich, klein, performant und ja sie ist ziemlich von Google ab geguckt :roll:
Dort findet man den letzten Branch und Trunk Code, letzte Dokumentation und den Link zu Hudson.

Wie üblich habe ich schlimmes erwartet und es kam noch viel schlimmer.
Die UnitTests laufen sauber durch aber aufgrund eines Bugs in meinem URI Klasse werden die URI's von Menschen lesbaren Addressen nicht sauber in URI(%,<,>,Space,alle nicht druckbaren und Ascii über 127 müssen durch #HEX) und wieder zurück transformiert. Das sorgt dafür, dass die Test Ergebnisse nicht in eine xml geschrieben werden können, wenn eines der oben genannten Zeichen im Pfad vor kommt. Also muss ein dirty Hack für das Branch und eine sauberes refactoring für den Trunk her, was mal wieder viel Arbeit macht, wo ich wieder bei dem Rattenschwanz wäre, den ich im letzten Post erwähnt habe.
Das Wochenende steht vor der Tür und ich bin frohen Mutes, dass ich einiges schaffen werde.

Was mich aktuell interessiert. Was haltet ihr von der Website und vermisst ihr noch was, was unbedingt rein sollte ?

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Radon Framework
BeitragVerfasst: Fr Okt 29, 2010 00:15 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2621
Wohnort: Berlin
Programmiersprache: Go, C/C++
An der Website hab ich die Woche nicht mehr viel dran geschraubt, ledeglich ein Bug im Hudson gefixt und Menüpunkte hinzugefügt. Ich denke, das ich nicht die notwendigen Informationen zum Projekt auf eine Seite bekomme und hab mich deswegen zu dem Menü entschlossen. Sobald ich Version 0.3 fertig hab, werde ich die News und noch kleinere dinge in der Seite einpflegen. Je mehr Zeit ich in die Seite stecke, des so weniger Zeit hab ich für das Coding ^^

Administrativ konnte ich noch E-Mails einrichten, git und noch ein bisschen hardening betreiben.
Also das Contact geht nun korrekt an meine Mail, git muss ich in ruhe alles vorbereiten und ist eher ein langfristiger Task.

Code Technisch geht es vorran, wenn auch wie gewohnt langsamer als gewollt. Wer kennt das nicht ? ^^
Im Trunk liegt nun ein funktionierendes SMBios Modul, welches unter Windows die CPU, VoltageProbe und Caches auslesen kann. Die ProcessorInformation Klasse gibt alle verfügbaren Informationen vom SMBios zurück und wenn cpuid unterstützt wird, dann wird noch ein cpuid ausgeführt und die verfügbaren Features ermittelt. So kommt man z.B. an die Geschwindigkeit, Anzahl der Kerne, jeden einzelnen Caches, Hersteller, Sockel und vieles mehr.
Es gab kleinere bug fixes, eine API Änderung im XML Module und es hat sich nun auch XPath dazu gesellt.
Ich hab viel an den CMake files geschraubt und hoffe bald neben den VisualStudio 2010 Solutions, Unix Makefiles auch CodeBlocks workspace files generieren zu können.

Im Anhang habe ich mal ein Bild gelegt, welches zeigt, wie man mit 2 Zeilen Code das ganze Logger Output auf Konsole und als mini Webserver weiter leitet. Dabei wird ein Event genutzt, welches auf Änderungen im Logger gehangen wird und somit auf die Shell schreibt. Beim Web-Server geht das ganze ein bisschen anders, da wird einfach nur ein Modul Registriert, welches auf GET Anforderungen von Log.html hört und dann eine entsprechende HTML Seite generiert und zurück gibt. Die Seite hat ein eingebautes Refresh, womit man recht angenehm einfaches remote debugging machen kann.

Auf meiner Liste stehen nun noch MemoryInformation, BiosInformation, TempProbeInformation und Notebook Battery in dem SMBios Module. Dann muss noch ein Prozessmonitor rein, die Quaternion, Matrix brauchen noch Unit-Tests und das URI Modul muss ich noch fixen. Dann hab ich meine Tasks für 0.3 geschafft.

Asserts, MemoryDump, weitere DebugServer Module, SmartPointer und ein GarbageCollector, sowie PoolAllocator hab ich in 0.4 verschoben. In 0.4 werde ich auch noch ein bisschen mehr im Window, UI und 2D Bereich machen, da ich für mitte Dezember eine Presentations Player schreiben muss. Dann gibt es auch mal tolle Screenshots und nicht immer nur Text.


Dateianhänge:
httplog.png [91.76 KiB]
Noch nie heruntergeladen

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004
Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Radon Framework
BeitragVerfasst: Mi Nov 24, 2010 11:58 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2621
Wohnort: Berlin
Programmiersprache: Go, C/C++
Der Umzug auf Redmine ist vollzogen. http://www.radonframework.org/
Ich hab ebenfalls ne neue Hudson und Fedora version(14) auf dem server.

Gestern hab ich mal den Milestone 0.3 fest geklopft und man sieht ziemlich gut, dass noch ein bisschen was fehlt. http://www.radonframework.org/projects/rf/versions/1
Das schönste an Redmine ist, dass man nun sehen kann, was so im svn, dem projekt und als admin auch in hudson(das plugin ist nicht ganz so ausgereift) passiert.
Das Ticket System ist ein bisschen gewöhnungsbedürftig aber es ist akzeptabel.

Ich sitze aktuell an der Process geschichte, sobald diese abgeschlossen ist, kommen die backends für Linux und der Fokus dieses Milestones wäre geschafft und dann wären die kleinen dinge dran.

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Radon Framework
BeitragVerfasst: Mi Jan 05, 2011 17:10 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2621
Wohnort: Berlin
Programmiersprache: Go, C/C++
Letzter Milestone(0.3)
Der Milestone hat länger gedauert als geplant, wesentlich länger aber ich bin auch kein Projekt Manager, sondern Programmierer.
Es kamen noch viele Dinge hinzu, die so garnicht eingeplant waren, z.B. habe ich noch viele Methoden bei der String verarbeitung eingebaut, einiges an Doku geschrieben und noch viele kleine Hilfsfunktionen an allen möglichen Stellen hinzu gefügt.
Letztlich war das ein ziemlich umfangreicher Milestone, der kommende muss und soll weniger Features auf der Liste haben, um die Zeitdauer besser zu planen.
Highlights des Milestones waren folgendes:
-Process Monitor(Processbaum, Process Informationen, Thread Informationen)
-SMBios implementierung(der größte Teil von den 2.7 Specs wird verarbeitet)
-neue Pointer Klassen(AutoVector, AutoPointer, AutoPointerArray)
-Read und WriteBuffer zum einfacherem schreiben auf Speicherbereichen
-übersichtlicherer WebDebugger(ein Webserver, welcher im Hintergrund läuft und das Processlog, separiert in den einzelnen Log-Channels, in echtzeit streamt)

Unter folgendem Link gibt es dann noch die Offiziellen Tickets zu dem letzten Milestone. http://www.radonframework.org/projects/rf/versions/1

Neuer Milestone(0.4)
Der neue Milestone 0.4 ist bereits Angelaufen und wird sich auf 2D fokusieren.
Ich will eine Presentations Software entwickeln und dafür brauche ich entsprechend einige neue Module.
Die wichtigsten sind folgende:
-Fonts(vektorbasiert)
-UI Components(Label, Button und EditBox)
-FileWatcher
-Screen(zuständig für Auflösung)

Es kommen natürlich wieder viele kleine dinge hinzu, welche z.B. Version-Klasse(Major,Minor,Revision,Build Nummer), Pool-Allocator, Memory und Coredumps, sowie Crashreports und so weiter.

Administration
Mein Buildsystem läuft mitlerweile recht gut aber leider bin ich nicht zufrieden.
Ich benutze Hudson als Buildsystem, welches Javabasiert und ist bisher das beste was ich je genutzt habe.
Das Problem ist, dass mein Framework auf mehreren Systemen laufen soll und daher braucht man auch mehrere Buildsysteme und hier ist der knackpunkt. Mein Server ist ein 1Kern, 1GB Ram,500GB HDD Strato server und eine VMware würde der nicht mehr verkraften. Wenn ich allerdings zuhause einen Aufsetze, dann hab ich das Problem, dass der Buildserver nicht rund um die Uhr erreichbar ist, da es 24h disc gibt und auch mal da Inet ausfallen kann.
Der Buildprozess braucht aktuell um die 12Minuten, in der er alles kompiliert, logischen code tests macht, dokumentation generiert und unit test durch führt.
Die Zeit ist recht gut, wenn man bedenkt, dass er den ganzen quellcode für jedes Define komplett neu prüfen muss und header von X11 und andere großen Libs recht viele davon haben.
Ich werde also in der Zukunft versuchen, diesen Prozess auf andere Webserver aus zu lagern.

Als Projekt Managment Software nutze ich Redmine und mitlerweile hab ich es recht gut im Griff und funktioniert nahezu so, wie ich es will.
Das Ticket und Versionierungssystem ist echt praktisch und kann ich weiter empfehlen.

Doku
Ich hab mich am Ende des letzten Milestones noch ein bisschen ins Zeug gelegt und noch eine vollständige Doku zur String Klasse gemacht und noch einige weitere Klassen ein bisschen Dokumentiert. Im Vergleich zu dem Code, der noch nicht Dokumentiert ist, wirkt das fast lächerlich :/

Weil es immer soviel Text ist, ohne Bilder, hier noch das neue Logo, was auch die neue Doku ziert.
Dateianhang:
RadonFramework.png
RadonFramework.png [ 22.08 KiB | 70785-mal betrachtet ]

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Radon Framework
BeitragVerfasst: Do Feb 24, 2011 02:02 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2621
Wohnort: Berlin
Programmiersprache: Go, C/C++
Ich möchte mal wieder ein kleines Update geben, zu dem Stand vom RadonFramework.

Die seit knapp 2 Wochen arbeite ich an 2 Themen, einmal multi Monitor Lösungen und zum anderem Information über den aktuellen Grafik Context.

Ich brauche für meine Software die Möglichkeit alle aktiven Monitore zu erkennen, Informationen über diese ein zu holen und die Auflösung zu ändern. Hierzu habe ich mich an der .Net API orientiert und eine Screen Klasse geschrieben. Diese nutzt unter Windows EnumDisplayDevices, EnumDisplaySettings und ChangeDisplaySettings, bzw.
unter X11 XRRSizes, XRRGetScreenInfo und XRRConfigCurrentConfiguration.
Die X11 Version ist noch nicht ganz fertig, da ich die ganze Sache nur auf Arbeit testen kann, da ich zuhause nur ein großen Monitor hab und zum testen ich aber mehr als 1 Monitor brauch. Das zieht sich so, da ich noch eine Array Klasse geschrieben hab, die ich in der Screen Klasse nutze.

Ich hab das Problem, dass ich für die beste Optimierung, für ein Darstellungsdevice Informationen über den aktuellen Grafik Kontext benötige. Also dinge wie ist ein DoubleBuffer verfügbar, wieviele Texturen kann ich gleichzeitig binden, welches ShaderModell ist verfügbar oder auch nicht ^^. Da ich allerdings das ganze auch für andere Nützlich machen will und ich irgendwie wieder auf die Delphi3D.net Grafikkarten Datenbank gekommen bin, hab ich mir überlegt alle verfügbaren Werte bis OpenGL 4.1 ein zu lesen und bereit zu stellen. Aus diesen Daten werden dann einige allgemeine gepickt und bilden eine Generische Version davon. Also alle meine OpenGL Contexte bieten zusätzlich zum Generischen GraphicDriverInformation noch die OpenGL spezifischen. Sollte also mal jemand einen anderen Context als OpenGL implementieren, dann braucht er sich nur um die recht kleine GraphicDriverInformation implementierung kümmern.
Code:
        struct GraphicDriverCapabilities
        {
         Portable::Bool DoubleBuffer;//a single boolean value indicating whether double buffering is supported
         Portable::Bool Stereo;//indicating whether stereo buffers(left and right) are supported
         Portable::Int32 MajorVersion;
         Portable::Int32 MinorVersion;
         Portable::String Renderer;
         Portable::Int32 ShaderModel;
         Portable::String Vendor;
         Portable::String Version;
        };

Ich muss noch ein ein bisschen feintuning machen, damit auch die dynamischen werte(z.B. GL_COMPRESSED_TEXTURE_FORMATS) gelesen werden aber knapp über 100 Werte stellt GraphicDriverInformationOpenGL nun bereit. Ich will das ganze noch in eine kleines Tool verpacken, welches dann erlaubt diese Infos in eine Datenbank zu schreiben. Dann gibt es wieder eine Möglichkeit Informationen über Grafikkarten zu erhalten. Es gibt ein ähnliches Projekt(http://www.kludx.com/card.php?card=118), welches schon um einiges weiter ist aber weder Platformunabhängigkeit noch Offenen Source bereit stellt.

Daneben hab ich auch einiges an Research betrieben, so hab ich in einem Buch eine Small Object Pattern gefunden. Es gibt in C++ wenig schlimmeres als Klassen und Structs die nur wenige Bytes groß sind. Diese passen nicht in Register und im Fall von einem return müssen diese mühsehlig über den Arbeitsspeicher rum geschleppt werden. Dies sorgt für ein new,delete und den aufruf des Copy Constructors. Dies ist alles andere als schnell und kann im Fall von häufiger verwendung, wie bei AutoPointer, AutoVector, String, Vector, Matrix richtig fies performance ziehen.
Deswegen dieses Small Object Pattern, dieses stellt eine Klasse, welche new und delete operator überladen und diesen auf ein eigenen Memory Allocator, der für sowas optimiert ist(PoolAllocator reicht schon), weiter reicht. So umgeht man die langen new und delete von der STL und hat nur noch mit dem CopyConstructor zu kämpfen. Wenn ich also solch eine kleine Klasse habe, z.B. meine String Klasse mit 2 Membern(Pointer4/8Byte und 4Byte Length) leite ich diese von SmallObject ab und fertig, dank vererbung reicht er das new bis zur SmallObject überladung runter, kein extra Code nötig.
Standard new und delete sind so langsam, da new sehr oft ein neuen Speicherlbock im OS anfragt und delete erst zurück geht, wenn der speicherblock beim OS wieder frei gegeben wurde. Dieser Pattern wird bald einzug in RadonFramework haben.

Ich hab auch ein bisschen research bzgl. Kompression und Archieve gemacht. Ich suchte ein streamfähiges file Archieve format, wo ich komprimierte datein hinein legen kann. Ich wollte dies eigentlich mit tar und lzma machen aber tar ist nicht streamfähig -_-.
Ledeglich lzma hat sich als gute Wahl herraus gestellt, lzma2 ist in sachen Größe nicht der beste Kompressor aber in sachen entspackgeschwindigkeit mit großen Vorsprung Nummer 1. LZMA gibt es in 2 versionen, die zweite ist etwas langsamer aber kann dafür binärdaten besser packen. Das LZMA SDK hat eine public domain Lizenz und wird meine Wahl als Kompressor sein.
Was aber mit dem Archive Format ? Nun nach reichlicher überlegung und einigen SDK's und Wiki Artikeln hab ich mich entschieden ein eigenes Archieve Format zu bauen. Das Hauptproblem ist Bibliotheken zu finden die unter, für mich, nutzbare Lizenz steht. Dann kommt der streaming support und KO gingen die restlichen bei der Performancefrage. Es gibt viele container Format wie AVI, OGG, Matroska und so weiter, welche streamfähig sind aber das lesen ist recht zeitaufwändig und das ganz zu wrappen kostet mich ja auch noch Zeit. Also hab ich mich zu einen eigenen Format mit streamfähigkeit und serialisierung entschieden.
Das Format ist recht schnell beschrieben. Am Anfang steht der Header, FourCC, nen Hash und der erste Infoblock, dann kommen die Datenblöcke, dann die Infoblöcke und die letzten 8Byte sind die Dateigröße. Der Sinn der Anordnung ist, dass die Infoblöcke eh am anfang geladen werden, damit man raus bekommt was denn so an files im Archieve steckt, diese zugriffe werden dann im Speicher gehalten und sind seltene zugriffe. Aufgrund, dass sie so klein sind greift der Cache besser, als wenn diese vor den jeweiligen files stehen.
Ein weiterer Vorteil ist die Platzierung auf DVDs, dort liegen die Nutzdaten am anfang und damit sind diese wesentlich schneller zu lesen als die Metadaten, die ich eh nur einmal lesen muss. Der 3. und mir wichtigste grund von der trennung von daten und infos ist die serialisierung, ich kann dan einer festen info struktur den ganzen Bereich in den speicher laden und über ein einfachen typecast sofort drauf zugreifen, statt irgendwas zu parsen, konvertieren, im archieve hin und her zu springen. Die serialisierung hatte sich schon bei mein alten Modelformat bewehrt und Ladegeschwindigkeiten mit Traumwerte gebracht. Sobald ich damit anfange, werde ich die Endgültigen structs zeigen.

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Radon Framework
BeitragVerfasst: So Apr 10, 2011 15:12 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2621
Wohnort: Berlin
Programmiersprache: Go, C/C++
Ich hab gerade ne knappe Stunde an nen Post gewerkelt und als ich ihn posten wollte ist meine Session ausgelaufen gewesen und der post war nach dem einloggen nicht gesendet worden, von daher nur ne 1min kurzfassung :p

Ich hab RadonFramework aufgeräumt, viel Code in ein Featurebranch verschoben, Code aus dem Trunk geworfen, gefixt und neuen geschrieben.
Der ganze Profiling kram, Hardware(SMBios) und Software(Processtree) Infos ist fertig und es kam ne menge Debugging(Threadnamen, Error klasse, bessere logs) kram hinzu.

Was ist nun geplant ?
Erstmal musste ich die Präsi Software auf Eis legen, da wir eine Simulations Software brauchen und entsprechend ändert sich die Roadmap.
In der Pipe liegt nun folgendes:
-FileWatcher//für Hot-Assets
-Physic Service//Kollision und Dynamik mit default backend Bullet
-Frustum culling
-Occlusion culling//geht über Events und wird ein brachial einfachen software renderer nutzen, der nur ein tiefenpuffer hat und dort triangles rein rendert(hardware geht ned überall, ist langsam und hängt 1 Frame hinterher)
-Modules//erweiterung von RF durch 3rd Party
-Plugins//neue Service-Backends durch 3rd Parties

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Radon Framework
BeitragVerfasst: Fr Apr 15, 2011 14:03 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2621
Wohnort: Berlin
Programmiersprache: Go, C/C++
Vorwort
Ich hatte im letzten Post ja geschrieben, dass ich ein großen Post vorbereitet hatte und beim senden ein Datencrash gab. Danach war ich recht Lustlos diesen nochmal zu schreiben und hatte mich zu kurz gehalten. Deswegen mache ich mir nochmal die Mühe alles zusammen zu tragen.

Ich werde das über mehrere News verteilen, damit keine Informationsüberflutung entsteht und ich will ja Wissen und Erfahrungen weiter geben.

Folgende Neuerungen werden angesprochen werden.
  • Debugging
  • Profiling
  • Erweiterbarkeit(Plugin/Modules/Data driven system)
Dieser Post wird von Debugging handeln.

Debugging

Dieser Punkt ist sehr wichtig, wenn man größere Projekte angeht, daher hab ich viele Helferklassen eingebaut, die Debugdaten erzeugen und verwalten können.
Die Basis bildet hier natürlich ein Logger, dieser hält alle rein kommenden Text Messages und triggered darauf hin ein Event. Dieses ist dafür da, um z.B. das Log in eine Datei, Datenbank oder sonnst wo ab zu legen. Dieser Teil ist Threadsafe und daher hat man schönes sauberes Log, auch wenn mehrere Threads versuchen gleichzeitig zu schreiben. Ich hab z.B. ein sehr primitiven WebServer mit hinzu gepackt, welcher die einzelnen Logchannels und deren Logs über Browser verfügbar macht. Sobald man also seine App startet, diesen Service instanziert und an das Logger Event hängt, dann kann man mit dem Browser auf der lokalen IP und dem default port vom service das log live sehen.
Neben diesen Log holder gibt es dann verschiedene Makros und Klassen, welche das Loggen vereinfachen. Die ScopeLogMessage Klasse dient zum erfassen von start und exit eines scopes und ob dazwischen etwas unerwartetes passiert ist. Sonnst gibt es noch 4 Makros, die wie printf eine Formatierungsanleitung und die Parameter an nimmt und dann entsprechende Log Messages generiert. Als letztes bleibt noch der Log Messages Aufbau, dieser wird durch ein Pattern für jeden LogChannel fest gelegt und kann ähnlich wie bei printf mit formatierungszeichen versehen werden aber man kann keine parameter übergen, dies macht der Logger selber.
  • Linenumber,//%l - Line number of the Add call.
  • Filename,//%f - Filename from where Add was called.
  • NowSeconds,//%s - Seconds of current time.
  • Message,//%d - The text message passed by Add call.
  • ChannelName,//%C - The name of the target channel
  • ProcessID,//%P - The ID of the calling process.
  • ...

Im Log steht dann z.B. folgende Zeile.
4/15 11:9:39 [15659] Debug: (Server.cpp:148) Found 42 nodes.
Das permanente festhalten des Programmablaufes ist natürlich nur ein Teil der Miete, denn man benötigt auch eine Fehlerbehandlung. Wo es möglich ist, umgehe ich Fehlerbehandlung durch design der Klassen, dies geht natürlich nicht immer und man braucht z.B. bei jeglicher IO Fehlerbehandlung.

Hierfür hab ich meine Errorklasse durch ein Template ersetzt, welches aus einem CPU freundlichen Fehlercode, Menschen lesbaren Fehlercode und InternalError, sowie einem Debugdaten pointer besteht. Man kann also zwischen Fehler, die aus dem Radonframework und welche die vom Backend kommen unterscheiden, sowie zusätzliche Informationen anhängen, die zum Debuggen des Problems hilfreich wären. Das Interface dient gleichzeitig zur vereinfachung von Usercode und ein effizienteres finden von Bugs oder Fehler die eventuell gar keine sind.

Wärend der Entwickung an einigen Servern hab ich immer wieder das Problem gehabt, welcher Thread steckt nun hinter der PID, die mir gerade um die Ohren geflogen ist. Daher hab ich im letzten Sprint hier abhilfe geschaffen und für Visual Studio 2010 und gdb Threadnamen eingeführt. Sobald man einem Thread einen Namen gibt, sieht man diesen im debugger anstelle der Prozessklasse(VS2010) oder PID(gdb).
VS2010 macht es einem hier nicht leicht, man muss im entsprechendem thread eine exception werfen, auf die der debugger horcht und den übergabe parameter auswertet und dann entsprechenden den Namen ersetzt. Blöder hätte man es nicht lösen können, sollte ich vieleicht nicht zu laut sagen, den fällt sonnst noch was ein. Hier der Link zum Vorgehen. http://msdn.microsoft.com/de-de/library/xcb2z8hs.aspx
Bei gdb kann man ein linux system call benutzen. Mehr dazu hier http://www.kernel.org/doc/man-pages/onl ... ctl.2.html (siehe PR_SET_NAME).

Was wird noch kommen ?
Was auf der Agenda für die nächsten Milestones steht sind Coredumps, Memorydumps, CallStack und Signal Handler.
Im Linux Bereich gibt es hierzu ne menge HowTo's, Doku und so weiter aber bei Windows muss man schon ein bisschen suchen. Für Arbeit habe ich all die Dinge auf Linux implementiert und man ist überrascht, wie einfach das geht.

Ein coredump kann man unter Linux mit dem system Tool gcore erstellen, man holt sich die ProzessID mit getpid() und übergibt dann gcore diese. Das Tool hält den Prozess an , dumpt den kompletten Prozess und setzt ihn fort. Diese kann man dann mit gdb und der binary laden(„gdb coredump binaryname“). Windows bietet hier minidumps an, die über Dbghelp(http://msdn.microsoft.com/en-us/library ... 85%29.aspx)angeboten wird.

Signal Handler sind ein wunderbares Thema, denn viele Prozess-Mechaniken, in Linux, laufen über Signals. Wenn man unter Linux ein binary erstellt, dann hat es die default Signal handler aktiv. Will man nun, dass ein Prozess nicht mehr durch ctrl+c beendet wird, dann kann man das entsprechende Signal überladen, indem man die Signal API nutzt(http://linux.die.net/man/2/signal). Es gibt hier Signals, die von Hardware und von Software geworfen werden. Windows hat nicht den Umfang von den Linux Signals aber bietet das im POSIX festgelegte API an.
Auf Arbeit habe ich z.B. die Signals so eingesetzt, dass bei Hardwarefehlern der Server sofort runter fährt und bei Softwarefehlern erstmal ein Crashreport anlegen und dann je nach Thread die App runter fährt oder einfach weiter macht, bzw. den Thread abschießt.

Für ein ordentlichen Crashreport sollte ein Callstack nicht fehlen, dieser ist unter Linux primitiv einfach. Hier mal ein Snippet.
Code:
  1.     void *array[200];//get the last 200 calls
  2.     size_t size;
  3.     char **strings;
  4.     size = backtrace (array, 200);
  5.     strings = backtrace_symbols (array, size);

Wie das Gegenstück unter Windows aussieht kann ich nicht sagen, da ich mich damit noch nicht beschäftigt habe.

Mit diesen Werkzeugen ist das aufspüren von Problemen relative einfach geworden und bilden eine wichtige Basis in meinem Framework.

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Radon Framework
BeitragVerfasst: So Apr 17, 2011 15:17 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2621
Wohnort: Berlin
Programmiersprache: Go, C/C++
Profiling

In den letzten Sprints habe ich das Profiling vorbereitet, welches dazu dienen soll dem Entwickler ein Werkzeug in die Hand zu geben, mit dem man Informationen aus dem System und der Hardware ziehen kann. Diese Informationen kann man für Optimierungs Schalter, Hardwareprofiles(für z.B. Benchmarks, bugreports) und natürlich für das auffinden von Bottlenecks dienen.

Prozessbäume

Was geht aktuelle ?

Ich hab nun den Code fertig, um alle laufenden Prozesse und deren Informationen aus dem System zu ziehen(windows und linux). Zu diesen Informationen gehören z.B. Laufzeiten im Kernel, Userspace, Speichernutzung, IO durchsatzt, Threads und vieles mehr.

Wie kommt man an die Daten ?

Wem das wie weniger interessiert als das wofür, der kann einfach zur nächsten Headline scrollen.

Windows
Unter Windows ist es sehr einfach an diese Informationen zu kommen. Es wird eine API angeboten, die aus OpenProcess, GetProcessImageFileName und einige weitere Befehle bietet. Hier der Link.
http://msdn.microsoft.com/en-us/library ... 85%29.aspx

Linux
Bei Linux ist die ganze Sache leider sehr aufwändig und daher gehe ich ein bisschen genauer drauf ein. Zuerst, es gibt keine API um auf solche Daten zu zugreifen, dies passiert alles über Dateien.
Die Linux Kernelentwickler haben extra für Klartextdaten, die vom Kernel bereit gestellt werden, einen Ordner namens proc eingeführt. Dieser ist laut Specs. unter /proc/ zu finden aber einige Distris. haben den Kernel und die Software entsprechend wo anders hin gepatcht.

Alle Datein in proc sind Klartext, haben ein bestimmten Aufbau und müssen im Inhalt mindestens dem Kernel Specs. folgen. Die erste und für uns wichtigste Regel /proc/[ProzessID]/ ist das Verzeichnis eines Prozesses. Die zweite Regel /proc/[ProzessID]/task/[ThreadID]/ ist das Verzeichnis eines Threads, des Prozesses. In allen 3 Ordnern gibt es jeweils ein stat Datei, welche die wichtigsten Informationen über ein Prozess, ein Thread und Informationen über alle Prozesse zusammen. Weitere Informatione, was in welcher Datei steht findet ihr in der Doku http://kernel.org/doc/Documentation/fil ... s/proc.txt . Okey soviel zur der Location und nun zu den Daten selber. Die ganze Dateistruktur wird durch das proc Filesystem(jupp ist ein komplettes eigenes Filesystem) zur Verfügung gestellt und liegt nicht auf der Platte sondern im Speicher.
Dies und das die Daten Klartext sind, macht die ganze Sache wesentlich einfacher, wenn man mit einer Scriptsprache auf die Daten zugreifen will. Als C++ Entwickler schüttel ich nur den Kopf und frag mich, wer auf diese völlig dumme Idee kam. Es gab mehrfach den Versuch, eine API bereit zu stellen aber all die SF. Projekte sind eingeschlafen und es gibt Bibliotheken in htop und top, welche das auslesen der Daten vereinfacht. Dies, der Grund, dass man diese Daten selten braucht, man oft Scripte nutzt(die kein Binary können) und die Faulheit der Entwickler hat wohl dafür gesorgt, dass die Nachfrage nach einer API zu gering ist. Das erfassen der Daten ist recht einfach aber sehr Zeitaufwändig, denn jeder Datensatz ist durch ein Leerzeichen getrennt und die Reihenfolge der Daten und Strukturen sind fest definiert. Man liest also die file ein, trennt die Daten an den Leerzeichen auf und bekommt eine Liste. Nun kann man mit einem enum z.B. direkt auf den Index der Liste zugreifen und bekommt den Wert als String. Der Aufwendige Teil ist nun das Konvertieren der Strings in die richtigen Daten.

In Linux konnte ich bisher 2 Informationen nicht ausfindig machen, die Modulliste, also welche Libraries sind zur Laufzeit geladen worden und einige Infos zum Speicher. Diese Informationen werden also irgendwann nachgereicht, sobald ich die Lösung gefunden haben.

Was mach ich mit den Informationen ?

Einer der bekanntesten Anwendungsfälle ist das ausfindig machen, ob ein Prozess schon läuft.
Die sauberste Variante ist hier zu gucken ob ein Prozess mit dem gleichen Prozessnamen bereits läuft und wenn ja den alten oder neuen Prozess zu beenden.

Ein anderer wichtiger Einsatz sind Watchdog Prozesse, die ein Prozess neu starten, sobald er weg ist.

Im Bereich der Spiele und Server sind aber auch Dinge wie Speicher Footprint wichtig, also wieviel hat ein Prozess jemals an Speicher gebraucht, wieviel Speicher ist noch da, ist genug Prozesszeit da, für Profiling kann user und kernel space Zeiten wichtig sein oder wie hoch war der größte IO peak und wie ist der durchschnittliche IO Transfer(Bottleneck HDD ?).

Hier mal ein Auszug aus den verfügbaren Daten.
Code:
  1. Profile.cpp(452): -Process[188/191]
  2. Profile.cpp(453): -Name: Profiler
  3. Profile.cpp(454): -ID: 23908
  4. Profile.cpp(455): -Binaryname: /home/thomas/Desktop/RadonFramework/trunk/demos/Profile/Profiler
  5. Profile.cpp(456): -CPU usage: 0.000000%
  6. Profile.cpp(457): -Creation time: 1.1.1 0:0:0
  7. Profile.cpp(458): -Executed by user: thomas
  8. Profile.cpp(459): -Exit time: 1.1.1 0:0:0
  9. Profile.cpp(460): -Kernel time: 0days:0hour:0min:0sec,0msec:0microsec
  10. Profile.cpp(461): -Memory access rights: true
  11. Profile.cpp(462): -Memory usage: 15267B
  12. Profile.cpp(463): -Non paged pool: 0B
  13. Profile.cpp(464): -Other operation count: 4293994218
  14. Profile.cpp(465): -Other transfered bytes: 65
  15. Profile.cpp(466): -Paged pool: 0
  16. Profile.cpp(467): -Page fault count: 0
  17. Profile.cpp(468): -Peak memory usage: 0B
  18. Profile.cpp(469): -Read operation count: 0
  19. Profile.cpp(470): -Read transfered bytes: 0B
  20. Profile.cpp(471): -Usable virtual memory: 0B
  21. Profile.cpp(472): -Usertime: 0days:0hour:0min:0sec,0msec:0microsec
  22. Profile.cpp(473): -Write operation count: 0
  23. Profile.cpp(474): -Write transfered bytes: 0
  24. Profile.cpp(475): -Module count: 0
  25. Profile.cpp(482): -Thread count: 1
  26. Profile.cpp(486): -Thread[1/1]
  27. Profile.cpp(487): --ID: 23908
  28. Profile.cpp(488): --Priority: Minimal
  29. Profile.cpp(489): --Creation time: 1.1.1 0:0:0
  30. Profile.cpp(490): --Exit time: 1.1.1 0:0:0
  31. Profile.cpp(491): --Kernel time: 0days:0hour:0min:0sec,32msec:0microsec
  32. Profile.cpp(492): --User time: 0days:0hour:0min:0sec,84msec:0microsec
  33. Profile.cpp(496): MyPID: 23908


Build Version

Ich verwende CMake als build System und ich habe ein kleines Makro eingebaut, welches guckt, ob svn auf dem lokalen System verfügbar ist und und dann die Revisionsnummer bezieht. Die Version kommt allerdings aus einer Define.hpp, welche manuell von mir gesetzt wird. Die Klasse, die diese RadonFramework Version enthält, ist natürlich auch für eigene Software nuztbar und wird z.B. für das künftige Plugin System von nöten sein.

Code:
  1. Profile.cpp(501): Version: 0.3 build 245 rev. 413


Graphic Context Information

Informationen über die Fähigkeiten der Grafikkarte zu bekommen werden oft benötigt aber es ist recht codeaufwändig die ganzen Informationen immer wieder aus zu lesen, in passende Form zu bringen und eventuell auch in Lesbare Varianten zu bringen. Ich hab mir diese Mühe gemacht und noch ein bisschen oben drauf gepackt. Das ganze läuft über den vorher erstellten Grafik Kontext, in dem Fall über OpenGL und glGet... . Es gibt eine Generische Schnittstelle, welche folgende Informationen raus rückt.

Code:
  1. main.cpp(35): -double buffer available: true
  2. main.cpp(36): -stereo available: true
  3. main.cpp(37): -renderer: Mesa DRI R600 (RV635 9591) 20090101  TCL DRI2
  4. main.cpp(38): -version: 2.1 Mesa 7.9
  5. main.cpp(39): -minor version: 1
  6. main.cpp(40): -major version: 2
  7. main.cpp(41): -vendor: Advanced Micro Devices, Inc.
  8. main.cpp(42): -shader model: 1


Ich habe mit absicht nicht die OpenGL Shaderversion genommen, da diese zu spezifisch ist, daher wandel ich diese in das entsprechende Shader Model um. Die Shader Model Version ist stärker verbreitet und lässt auch vergleiche mit D3D zu.
Hinter der Generischen Schnittstelle steckt natürlich eine Implementierung und diese ist im aktuellen Fall OpenGL. Nun kann man diese ebenfalls abfragen und bekommt dann halt zusätzlich noch OpenGL spezifische Möglichkeiten, wie z.B. Extensions, ARB's und sehr wichtig, die Capabilities. Letztens ist sehr wichtig, wenn man Laufzeitoptimierung machen will.
Alle Daten gibt es als Binary und Text(die Arbeit wünsche ich niemanden zu machen, das waren einige Tage) und hier mal ein Auszug von mein IBM T500, unter Linux.

Code:
  1. main.cpp(43): OpenGL extension
  2. main.cpp(45): GL_ARB_depth_clamp
  3. main.cpp(45): GL_ARB_depth_texture
  4. main.cpp(45): GL_ARB_draw_buffers
  5. main.cpp(45): GL_ARB_draw_elements_base_vertex
  6. main.cpp(45): GL_ARB_fragment_program
  7. ...
  8. main.cpp(45): GL_EXT_vertex_array
  9. main.cpp(45): GL_EXT_vertex_array_bgra
  10. main.cpp(45): GL_APPLE_packed_pixels
  11. main.cpp(45): GL_ATI_blend_equation_separate
  12. ...
  13. main.cpp(45): GL_SGIS_texture_lod
  14. main.cpp(45): GL_SUN_multi_draw_arrays
  15. main.cpp(46): OpenGL capabilites
  16. main.cpp(50): -GL_ALIASED_POINT_SIZE_RANGE available: true value: 0.125,8191.88
  17. main.cpp(50): -GL_ALIASED_LINE_WIDTH_RANGE available: true value: 0.125,8191.88
  18. main.cpp(50): -GL_COLOR_MATRIX_STACK_DEPTH available: true value: 1
  19. main.cpp(50): -GL_COMPRESSED_TEXTURE_FORMATS available: true value: 35916,35917,35918,35919
  20. ...
  21. main.cpp(50): -GL_IMPLEMENTATION_COLOR_READ_TYPE available: true value: 5121
  22. main.cpp(50): -GL_IMPLEMENTATION_COLOR_READ_FORMAT available: true value: 6408


Hardware Informationen

Hardware Informationen sind sehr nützlich, wenn man zur Laufzeit optimierungen vor nehmen möchte, z.B. nutzung von SIMD statt normales floatingpoint oder die Größe eine PoolAllocator, anhand des Maximalen Speicers, fest legen.
Es gibt viele Möglichkeiten aber die Daten zu bekommen ist recht Aufwändig, da einem immer wieder Steine in den Weg gelegt werden.

SMBios
Ich habe mich entschlossen ein SMBios Interface in RadonFramework auf zu nehmen. SMBios ist ein Standard, welcher von so ziemlich jeden BIOS implementiert wird und dem OS die benötigten Hardwareinformationen liefert. Windows, Linux und co nutzen das SMBios um ihre Gerätetreiber aus zu wählen und die Hardware erfolgreich zur verfügung zu stellen. An sich ist der Ablauf sehr einfach, jede Hardwarekomponente meldet sich beim BIOS oder das BIOS fragt die Komponenten und hält die ganzen Hardwareinformationen in einer spezifizierten Datenstruktur. Diese Daten werden dann in den Arbeitsspeicher gemapped und können von dort gelesen und in wenigen fällen auch geschrieben werden. Diese Daten werden zur Laufzeit aktualisiert, so bekommt man z.B. Spannungen, Temperaturen und so weiter. Wärend Linux an diesen System nicht rum geschraubt hat, wurde bei Windows diese Daten Stück für Stück für den Entwickler unzugänglich gemacht. Ab Windows Vista wurde das Memory Mapping, der Daten entfernt und man kann nur noch über COM und einer frisierten System Firmware Tabelle an die Daten. Hier der Link zur Windows Funktion.
http://msdn.microsoft.com/en-us/library ... 85%29.aspx

Sollte man also auf ein System Arbeiten, wo kein SMBios verfügbar ist, dann müsste man für die nutzung ein SMBios Service erstellen, diesem z.B. Konstanten Daten verpassen(bei Konsolen und Smartphones würde es Sinn machen) und die Highlevel API nutzt dann diese Daten.

Ich habe nicht die Vollständigen SMBios Spec. implementiert, sondern erst hatte ich das vor aber am Ende hab ich nur noch die Wichtigen dinge Implementiert. Daher findet man einige eher unbrauchbaren Infos. Viel gerede hier mal ein Log.

Code:
  1. Profile.cpp(51): BIOS information
  2. Profile.cpp(52): -Address: 61440
  3. Profile.cpp(53): -Embedded controller firmware: 3.5
  4. Profile.cpp(54): -Version: 0.0
  5. Profile.cpp(55): -Release date: 01/20/2011
  6. Profile.cpp(56): -ROM size: 4194304
  7. Profile.cpp(57): -Vendor: American Megatrends Inc.
  8. Profile.cpp(58): -Version: 1204
  9. Profile.cpp(59): -BIOS characteristics
  10. Profile.cpp(60): --Not supported: false
  11. Profile.cpp(61): --ISA: false
  12. Profile.cpp(62): --MCA: false
  13. Profile.cpp(63): --EISA: false
  14. Profile.cpp(64): --PCI: true
  15. ...


Code:
  1. Profile.cpp(108): System information
  2. ...
  3. Profile.cpp(118): -Wakeup type: Power switch


Code:
  1. Profile.cpp(126): Base board information
  2. Profile.cpp(127): -Product: P8P67
  3. Profile.cpp(128): -Manufacturer: ASUSTeK Computer INC.
  4. Profile.cpp(129): -Serial number: MT700BK42303508
  5. Profile.cpp(130): -Version: Rev 1.xx
  6. ...
  7. Profile.cpp(138): -Boardtype: Motherboard


Code:
  1. Profile.cpp(179): Processor information
  2. Profile.cpp(180): -Voltage: 1.000000
  3. Profile.cpp(181): -Version: Intel(R) Core(TM) i5-2500K CPU @ 3.30GHz
  4. Profile.cpp(182): -Upgrade: Other
  5. Profile.cpp(183): -Type: Central processor
  6. Profile.cpp(184): -Status: Enabled
  7. Profile.cpp(185): -Socket: LGA1155
  8. Profile.cpp(186): -Serial number: To Be Filled By O.E.M.
  9. Profile.cpp(187): -Part number: To Be Filled By O.E.M.
  10. Profile.cpp(188): -Max supported thread count: 0
  11. Profile.cpp(189): -Max possible speed: 3800
  12. Profile.cpp(190): -Manufacturer: Intel
  13. Profile.cpp(191): -Is cpu socket populated: false
  14. Profile.cpp(192): -Is cpu supported: true
  15. Profile.cpp(193): -Family: Intel Core 2 Duo
  16. Profile.cpp(194): -External clock: 100
  17. Profile.cpp(195): -Enabled core count: 1
  18. Profile.cpp(196): -Current speed: 3300
  19. Profile.cpp(197): -Core count: 4
  20. Profile.cpp(198): -Asset tag: To Be Filled By O.E.M.
  21. Profile.cpp(199): -Cache count: 3
  22. ...
  23. Profile.cpp(223): --Level: 1
  24. Profile.cpp(224): --Location: Internal
  25. Profile.cpp(225): --Max cache size: 256
  26. Profile.cpp(226): --Operation mode: Write back
  27. Profile.cpp(227): --Socket designation: L1-Cache
  28. ...
  29. Profile.cpp(262): -FPU supported: true
  30. Profile.cpp(263): -FXSR supported: true
  31. Profile.cpp(264): -HTT supported: true
  32. Profile.cpp(265): -IA64 supported: false
  33. ...
  34. Profile.cpp(287): -SSE supported: true
  35. Profile.cpp(288): -SSE2 supported: true
  36. Profile.cpp(289): -SSE3 supported: true
  37. Profile.cpp(290): -SSE4.1 supported: true
  38. Profile.cpp(291): -SSE4.2 supported: true
  39. Profile.cpp(292): -SSSE3 supported: true
  40. Profile.cpp(293): -TM1 supported: true
  41. Profile.cpp(294): -TM2 supported: true
  42. Profile.cpp(295): -TSC supported: true
  43. Profile.cpp(296): -VME supported: true


Code:
  1. Profile.cpp(313): Port connector information
  2. Profile.cpp(314): -External connector type: PS2
  3. Profile.cpp(315): -Internal connector type: None
  4. Profile.cpp(316): -External reference designator: PS/2 Keyboard
  5. Profile.cpp(317): -Internal reference designator: PS/2 Keyboard
  6. Profile.cpp(318): -Port type: Keyboard port


Code:
  1. Profile.cpp(313): Port connector information
  2. Profile.cpp(314): -External connector type: Other
  3. Profile.cpp(315): -Internal connector type: None
  4. Profile.cpp(316): -External reference designator: AUDIO
  5. Profile.cpp(317): -Internal reference designator: AUDIO
  6. Profile.cpp(318): -Port type: Audio port


Code:
  1. Profile.cpp(313): Port connector information
  2. Profile.cpp(314): -External connector type: None
  3. Profile.cpp(315): -Internal connector type: MiniJack
  4. Profile.cpp(316): -External reference designator: (null)
  5. Profile.cpp(317): -Internal reference designator: AAFP
  6. Profile.cpp(318): -Port type: Audio port


Code:
  1. Profile.cpp(313): Port connector information
  2. Profile.cpp(314): -External connector type: None
  3. Profile.cpp(315): -Internal connector type: Other
  4. Profile.cpp(316): -External reference designator: (null)
  5. Profile.cpp(317): -Internal reference designator: CPU_FAN
  6. Profile.cpp(318): -Port type: Other


Code:
  1. Profile.cpp(347): Onboard device information
  2. Profile.cpp(348): -Device count: 1
  3. Profile.cpp(351): -Device[1/1]
  4. Profile.cpp(353): --Is enabled: true
  5. Profile.cpp(354): --Description: Onboard Ethernet
  6. Profile.cpp(355): --Type: Ethernet


Code:
  1. Profile.cpp(383): BIOS language
  2. Profile.cpp(384): -Is long format: false
  3. Profile.cpp(385): -Current language: ger
  4. Profile.cpp(386): -Available languages: 6
  5. Profile.cpp(388): -Available language: eng
  6. Profile.cpp(388): -Available language: fra
  7. Profile.cpp(388): -Available language: ger
  8. ...


Code:
  1. Profile.cpp(411): Memory Information
  2. Profile.cpp(412): -Location: System board or motherboard
  3. Profile.cpp(413): -Max capacity: 16777216KB
  4. Profile.cpp(414): -Use: System Memory
  5. Profile.cpp(415): -Has error: false
  6. Profile.cpp(416): -Error correction type: None
  7. Profile.cpp(417): -Device count: 4
  8. Profile.cpp(421): -Memory device[1/4]
  9. Profile.cpp(422): --Type: DDR3
  10. Profile.cpp(423): --Total bandwidth: 64
  11. Profile.cpp(424): --Size: 2097152KB
  12. Profile.cpp(425): --Form factor
  13. Profile.cpp(426): --Device set: 0
  14. Profile.cpp(427): --Device locator: DIMM0
  15. Profile.cpp(428): --Data bandwidth: 64
  16. Profile.cpp(429): --Bank locator: BANK0
  17. Profile.cpp(430): --Is window DRAM: false
  18. Profile.cpp(431): --Is unregistered: false
  19. Profile.cpp(432): --Is synchronous: true
  20. Profile.cpp(433): --Is static column: false
  21. Profile.cpp(434): --Is registered: false
  22. Profile.cpp(435): --Is RAMBUS: false
  23. Profile.cpp(436): --Is pseudo static: false
  24. Profile.cpp(437): --Is non volatile: false
  25. Profile.cpp(438): --Is fast page: false
  26. Profile.cpp(439): --Is EDO: false
  27. Profile.cpp(440): --Is CMOS: false
  28. Profile.cpp(441): --Is cache DRAM: false
  29. ...


Bei den CPU Fähigkeiten hab ich nicht nur SMBios Daten vor liegen, die MMX,SSE und so weiter Flags kommen vom CPUID call, der wiederrum nur aufgerufen wird, wenn SMBios sagt,dass dieser von der CPU unterstützt wird.

Über die Zeit werde ich nun High level API Klassen bauen, die auf diese Daten aufsätzen und die eigentlich interessanten Daten raus filtern, sprich Processor und Memory Klassen.

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Radon Framework
BeitragVerfasst: So Aug 21, 2011 22:09 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2621
Wohnort: Berlin
Programmiersprache: Go, C/C++
Ich habe lange kein Update mehr gemacht, dass will ich mal nach holen.

Die Planung ist halt nicht Realität und die Zeit, die ich für das Plugin System eingeplant hatte war viel zu knapp bemessen, daher noch kein 3. Post, über Plugins, Modules und Data Driven system.
Module funktionieren, das war auch nicht schwer aber Plugins sind ein großer Brocken und ich hab Änderungen in der Prio Liste und deswegen zieht sich der 3. Beitrag noch ein bisschen.

Was hab ich bis dato gemacht ?

Ich trainiere meine Hard-Skills und beschäftige mich aktuell mit jQuery, Cassandra, Centos und Code optimierung.
Ich bastel ein Prototypen, welcher ein Netzwerk Service skalieren kann und das effizient.
Cassandra ist keine Datenbank in dem sinne und erst recht keine Relationelle Datenbank.
Üblicherweise verwenden Firmen MySQL oder MSSQL Server, viele würden als Netzwerk Datenbank garnicht in Frage stellen, dass man es mit MySQL erschlägt. Ein kleiner Teil würde sogar PostgreSQL nehmen, wenn man weiß, man muss skalieren.
Das Problem, skalieren geht damit nur bis zu einem Gewissen Punkt, ab da kann man nicht mehr kostengünstig die Last mit Hardware erschlagen. Facebook, Google und natürlich kleinere Services, die aber viel Daten generieren funktionieren mit diesen Systemen nicht.
Solche Dienste nutzen Datenbanken, die sich nach den Query strukturieren, also ein Query ein Datensatz, statts wie bei Relationellen Datenbanken, mehrere Queries, join und filter regeln für ein Datensatz.
Die Nodes spiegeln sich untereinander und müssen nicht alle Server, vom Service kennen.
Sowas ist Cassandra, ein auf DHT basierte Datenverwaltung, die neben Tabellen auch Binärdaten, Texte und Counter hinter einem Hash packt. Die Daten werden im Pool gesynct und es gibt eine History(abfrage in einer Tabelle gibt 2 oder mehr Zeilen, statt 1 zurück), wenn wirklich mal eine Kollision passiert.
Wie, Was, Wo, synct und was bei Kollison gemacht werden soll, kann man in der Config und in den Datenstrukturen fest legen. Ein single node läuft out of the box auf allen bisher getesteten Systemen und laut netzt ist ein Pool mit 2 Zeilen Text eingerichtet aber hab ich bisher nicht hin bekommen ^^.
Back to topic. Man hat ein Webserver, auf diesem liegt ein Cassandra und unser Netzwerk Service.
PHP macht die Datenverwaltung zwischen User und Cassandra und braucht auch nicht mehr Code als bei MySQL und co.
Cassandra hat bereits ein Cache integriert, also fällt auch Memcache weg, was ohnehin sehr zu wünschen übrig lässt.
Der Netzwerk Service ist dann ein Server, bei mir wird dieser natürlich in C++ sein, bin ja C++ progger.
Um mit mein Server auf die Daten von Cassandra zu kommen gibt es 2 Möglichkeiten, 1. über lokale PHP Scripte und 2. über Thrift API.
1. Geht schnell ist aber nicht Performant, da aus einem Prozess herraus ein Fork(prozess wird geklont) gemacht wird und dann dieser Prozess php auf ruft und wenn es fertig ist steht alles im shared memory, von beiden Prozessen und der 2. tötet sich. Das passiert halt, wenn man aus einer Binary eine andere Binary ausführen will.
2. Recht aufwändig, wegen Doku und mangelndem support für Bibliotheken aber deutlich schneller, da man über Netzwerk mit den Server kommuniziert.

Testumgebung und Erfahrungswerte
Der Service muss so geschrieben sein, dass er keine Kommunikation mit jemand anderem als Cassandra oder lokalen PHP machen muss. Damit wird verhindert, dass bei Kommunikation mit aussen ein skalierungsproblem entsteht.
Die Erfahrung hab ich auf Arbeit schmerzlich machen müssen und nach 1Jahr muss das Serversystem korrigiert werden und das kostet nun viel Schweiß und Zeit.

Meine Testumgebung besteht aus 3 Servern.
http://g1.radonframework.org/ <- mein RadonFramework.org Webserver
http://g2.radonframework.org/ <- aktuell down, die VM in Rechenzentrum wird neu gemacht
http://g3.radonframework.org/ <- Home Server mit dyndns angebunden

Jeder weitere Server würde dann halt ne neue Zahl bekommen und ein DNS Eintrag, der alle g[Zahl] enthält würde eingerichtet werden. So kann ein Client bei seinem DNS-Server nach der service domain fragen und bekommt eine liste mit allen Alias DNS-Server zurück. Dann sucht der Client per Zufallszahl eine Nummer zwischen 0 und N und versucht auf den entsprechenden Server zu kommen, wenn das nicht geht wird der Prozess wiederholt, bis alle Zahlen aufgebraucht sind und merkt, dass der Service nicht mehr existiert ^^

Das ist skalierbar :) kein single point of fail, der den User authentifiziert und an ein Server leitet, Proxy oder Load Balancer die nicht skalieren können. Ein einzelner oder ein Pool aus Server, die das balancing machen, können problemlos mit DDOS ausser gefecht gesetzt werden und der Service ist nicht mehr verfügbar. LOL und HON haben das Schmerzlich erleben müssen. Die DNS-Server aller User auser gefecht zu setzen ist ein ding der Unmöglichkeit. Also bleibt nur der direkte Angriff.
Jeder Server, des Netzwerk Service kann das gleiche und man sollte definiv kein Sharding oder Instancing verwenden. Sharding benötigt eine Kommunikation unter den einzelnen Servern, eines Shards und das ist sehr aufwendig zu entwickeln und Bugfrei zu bekommen. Instancing ist kritisch, da wenn dieser Server Probleme hat, dann ist die Instanz nicht mehr verfügbar und kann bis zum ausfall des ganzen Service führen. Aus Programmierer sicht sind die letzten beiden Lösungen auch recht aufwändig.

Was ich nun mache ist eine Service, der User authentifizieren kann und validiert, dass man ein authentifizierter User ist.
Hier passiert nix kompliziertes, salted Hash password(sha1) wird über javascript im client browser erstellt und am Server gegen geprüft(damit auch ohne ssl sicher :) ) und ein SessionID generiert. Ist die IP und SessionID unterschiedlich, wird der request denied und man sollte sich neu authentifizieren. Das ist sicherer, damit keiner die Session kapert.

Der Service selber wird ein primitiver RTS server, welcher die Aktionen des Clients überprüft. Der Server hat immer Recht und was er bei der simulierung raus hat ist Gesetz und hebelt Cheater Kiddies aus. Das Problem bei diesem Konzept ist, dass man viel Power braucht, da für jeden User eine Logik/Physik simulation läuft. Ich hab RTS gewählt, weil dort wenig Last entsteht(jeder Klick). Ich werde 2 Wege testen, einmal reine CPU mit SSE und einmal mit OpenCL. Für 2. werde ich eine Nvidia Workstation Karte verwenden. Ich bin überzeugt, dass 2. wesentlich besser sein wird aber ka. wie viel ^^
Ich werde kein RTS schreiben, bin ja nicht wahnsinnig, okey liest sich vieleicht schon xD.
Es wird nur ein Triangle-Sphere, Ray-Sphere und Sphere-Sphere intersection check geben. Darauf baue ich dann ein Pathfinding. Der Server gibt dem Client auf Anfrage dann eine Pfad und eine Zeit t auf dem Pfad, der Client errechnet dann daraus die Position. Der Client kann ein neues GoTo Message absetzen, der Server wird darauf die Position auf dem Pfad berechnen, Punkt A durch diesen ersetzen und B auf den gewünschten Zielort setzen. Nun läuft der teure Pathfinding Algo, bei misserfolgt wird B=A und bei erfolg wird ein Path mit B und/oder C,D... erstellt, Punkt A wird der aktuelle Zeitstempel vergeben und die weiteren Punkte bekommen anhand der Weglänge und einer Laufzeit entsprechende Zeitstempel.

Mein RadonFramework bekommt gerade eine Optimierungskur verpasst. Ich überarbeitet ja den Code, damit er solide wird und flexibel bleibt aber vorallem schneller. STL ist auf flexibilität ausgelegt und hat eine schreckliche Performance. Daher habe ich in einer recht frühen Version schon eigene Container eingeführt. Diese mach ich aktuell sauber. Ich ziehe aktuell auch den Sring typen glatt. Meine aktuelle String Klasse beherrscht nur ASCII und ANSI aber ein Unicode support muss her.
Beim designen sind mir weitere Mängel in der Performance und flexibilität aufgefallen, daher sind neue Typen ins Spiel gekommen. Neben Char gibt es UTF8,16,32 Typen, die beim String als Template Parameter übergeben werden können.
Die API muss ich noch ausbauen aber das hat low Prio. Viel mehr ist mir die Perf. wichtig, da auf Arbeit ich ~30% der Serverzeit in String Operationen verbringe, diese nicht langsam(so schnell wie c string), es sind einfach massig String Operationen im Code. Um hier noch mehr raus kitzeln zu können müssen Optimierungen her, die nicht jede Hardware kann, die Rede ist von CPU SIMD Operationen(MMX, SSE1-5, AVX,...). Um sowas sinnvoll in den Code zu bekommen und trotzdem Platformunabhängig zu programmieren braucht man ein CPU-Dispatcher. GCC und MS Visual Studio C++ haben dafür Instrincs aber wie zu erwarten, ist das völlig unterschiedlich von der API, also nix mit einfach in den Code hacken.
Ein CPU Dispatcher ist total simpel.

CPU-Dispatcher

Code:
  1. if (IsCPUSupportSSE2)
  2.   SIMDFactory::OperationSet=SIMDOperationSet::SSE2; // jede 64Bit fähige CPU und eine Handl voll älterer 32Bit kann das
  3. else if (IsCPUSupportMMX)
  4.   SIMDFactory::OperationSet=SIMDOperationSet::MMX; // so ziemlich jede CPU, die heute noch in PC's steckt kann das
  5. else
  6.   SIMDFactory::OperationSet=SIMDOperationSet::ALU_FPU; // default, jede CPU hat ALU und FPU
  7.  
  8. /* Hier differiert nun je nach Entwickler der Code.
  9. SIMDFactory wurde als Facade implementiert und wrapped alle Operationen zur Laufzeit, abhängig von OperationSet Variable, auf die jeweilige Funktion. Jede ausführung hat ein extra Funktionsaufruf und ein Branching call und ist damit teurer.
  10.  
  11. SIMDFactory stellt Funktionspointer bereit, die einmal durch ein Init mit den entsprechenden Pointer des OperationSet überschrieben werden. Ein Funktionscall vom Arbeitsspeicher aus, da der Pointer variable Werte enthalten kann.*/
  12.  
  13. // Meine Implementierung
  14.         #define OPSETSWITCH(OPERATION) executeoperation:\
  15.         switch (m_OpSet)\
  16.         {\
  17.             case SIMDOpSet::Default:\
  18.                 a.m_Value=RadonFramework::Core::SIMD::FPU_ALU<VecType>::OPERATION(m_Value,Other);\
  19.                 break;\
  20.             case SIMDOpSet::SSE2:\
  21.                 a.m_Value=RadonFramework::Core::SIMD::SSE2<VecType>::OPERATION(m_Value,Other);\
  22.                 break;\
  23.             case SIMDOpSet::Unset:\
  24.                 m_OpSet=SIMDOpSet::SSE2;\
  25.                 goto executeoperation;\
  26.                 break;\
  27.         }
  28.  
  29.         template <typename VecType>
  30.         struct SIMDVec
  31.         {
  32.                 VecType m_Value;
  33.                 static Types::Int32 m_OpSet;
  34.  
  35.                 SIMDVec operator+(const VecType& Other)const{
  36.                     SIMDVec a;
  37.                     OPSETSWITCH(Add);
  38.                     return a;
  39.                 }
  40.           ...
  41.  


Ich nutze also ein Facade, templates, Policies und ein goto mit Label.
SIMDVec ist ein Template, welches als Parameter den Datentyp(Vec128Float, Vec128Int, Vec64Int,...) bekommt, damit man nicht alles zig mal schreiben muss.
Die Methoden verstecken ein branching also ist die Klasse ein Facade.
Das switch case wird in the theorie zu einem statischen array optimiert, da der Typ von m_OpSet ein enum ist, welches keine Lücke in der Aufzählung hat. Praktisch bleibt es ein riesen if else if else ... Konstrukt auf den meisten Compilern.
Daher werde ich diese optimierung später erzwingen, indem ich selber ein statischen array anlege und dort die funktionspointer rein packe. Statisch, damit nicht extra Code für Stackmanipulation an fällt und Array, weil es codetechnisch einfach nicht schnelleres gibt.

Wer genau hin geguckt hat, der sieht ein Unset case, der aktuell noch SSE2 fest einstellt, da mein System dies kann aber da wird eine cpuid abfrage rein kommen und entsprechend den wirklich besten weg einstellen. Danach passiert ein goto, das wird eigentlich verteufelt aber in dem Fall ist es wirklich super duper cool, weil ich somit mir ein Init für SIMD sparen konnte und einfach in allen Operationen, wo der Wert benötigt wird ein Unset case hab, der initialisiert und dann noch einmal probiert, ohne noch den umweg für ein weiteren funktions call zu machen.

Die Klasse hat übrigens ein untypisches Design, da steht struct und kein class ^^
class ist in c++ ein struct, nur das default alle member protected statt public sind.
Die Klasse ist ein POD Datentyp, also Plain old data und damit können viele coole optimierungen genutzt werden, damit es POD ist muss alles public sein also hab ich class durch struct ersetzt und spar mir die public: Zeile und erfahrenden C++ Entwicklern erkennen es schneller.
Mehr infos zu POD hier http://www.fnal.gov/docs/working-groups ... c/POD.html .

Also brachial viel Performance und das handling ist dadurch viel einfacher.
Code:
  1.     Vec128Int8 a,b,c;
  2.     a=Vec128Int8::Init(1);// füll mit 1 auf
  3.     b=Vec128Int8::Init(2);// füll mit 2 auf
  4. // explizieter aufruf einer SIMD Operations set
  5.     c=RadonFramework::Core::SIMD::FPU_ALU<Vec128Int8>::Add(a,b);// c=3,3...
  6.  
  7.     c=Vec128Int8::Init();// füll mit 0 auf
  8. // je nach implementierung würde bei nicht verfügbarkeit von SSE die App hier explodieren
  9.     c=RadonFramework::Core::SIMD::SSE2<Vec128Int8>::Add(a,b);// c=3,3...
  10.  
  11. // der coole weg, wo hinter der Bühne die Magier passiert, kein init, kein verschiedenen code paths, immer schneller
  12.     RadonFramework::Core::SIMDVec<Vec128Int8> s;// eine klasse aber pod sei dank muss kein Konstruktor gecalled werden
  13.     s.m_Value=a;
  14.     c=s+b;// pod sei dank kann ein flat copy gemacht werden, kein Copy Konstruktor, assign operator oder ähnliches


Mit der Macht von Grayskull, eh SIMD
SIMD bedeutet mehr Geschwindigkeit, in 99,9% der Fälle.
Der erste Schritt war, die verwendung von SIMD so brachial einfach zu machen, dass Entwickler es gerne nutzen und der 2. ist es in RadonFramework selber ein zu setzen ^^
Ich schrieb oben von lahmen Strings *Glühbirne rein dreh und Licht an mach*.
Ein String ist eine aneinander reihung von 1 bis 4 byte Elementen, mit SSE2 und höher kann man 16 Byte gleichzeitig verarbeiten. Dabei kann je nach Erweiterung, unterschiedliche Operationen zusätzlich boosten und läuft sonnst auf standard ALU_FPU Pfad, wie es fast alle Programmierer sowieso machen aber selbst hier ist diese Variante noch oft schneller, da diese Implementierung fest legt, dass 16Byte verarbeitet werden und damit kann man schleifen ausrollen und caching misses runter schrauben. Operationen wie ToLower/UpperCase, Length, MemSet, MemCopy, MemMove werden schneller und die letzten 3 sorgen für verketten, ersetzen und substring Operationen.
Lineare Algebra wird natürlich auch ordentlich davon profitieren.

Client für den Service
Der Client ist auch ein Test für Technologien. Ich weiß aus Erfahrung, die ich auf Arbeit gemacht habe, dass Browser Plugins wie Unity3D generell Leute abschrecken und der Prozentsatz, der über bleibt muss sich dann mit den Eigenheiten von Plugins rum ärgern. Eigenständige Clients sind auch eine Hürde im Casual Bereich, bei Inet Games, muss man auch noch die ganze UI einbauen, Shops und so weiter sind sehr Aufwändig und man kann nicht einfach ein PC wechsel machen, da man neu installierne muss. Daher hab ich mich für die 3. Lösung entschlossen, Java-Applet. Ein Java-Applet wird supported, sobald das Java Plugin installiert ist, bei Windows immer der Fall und bei Linux häufig der Fall, also eine riesen Menge an User haben kein mehr aufwand, ausser den Security Fenster von Java zu zustimmen. Natürlich bin ich C++ Entwickler und daher kommt nur ein Java-Applet wrapper, welcher eine c++ binary nach lädt, je nach Target und die macht dann die Arbeit.
Da ich ein OpenGL Context brauch, muss ich mich da erst einlesen, wie das am besten zu lösen ist.
Abgesehen davon, werde ich ganz primitiv eine top-down Kamera, ohne Texturen, nur Farben, mit Primitiven 3D Feldern rendern. Der Character wird ein anderes Primitives Objekt sein und Maus zeiger werden für die Netzwerk Messages abgefangen. Ach Interpolation für die Pfade vom Server kommt noch aber das war es dann auch. Alles im allen sollte das doch schnell machbar sein.

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Radon Framework
BeitragVerfasst: So Okt 09, 2011 02:56 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2621
Wohnort: Berlin
Programmiersprache: Go, C/C++
Wegen stressiger Arbeit habe ich aktuell eigentlich garnicht programmiert aber ich hatte diese Woche mal 2 gute Abenden und wieder mal was geschafft.

Abseits der Roadmap

Letzte Woche fand ich im Netz eine Seite (http://www.inf.fh-flensburg.de/lang/alg ... /index.htm) auf der diverse Suchalgorythmen aufgelistet und erklärt werden.
Da ich an meiner Stringklasse rum werkel hab ich mal ein kleines Template geschaffen, welches sich um Textverarbeitung kümmert. Das Template nennt sich StringProcessor und erwartet als Parameter eine Policy mit Init, Reset, DoNext und DoAll Funktionen.

Code:
  1.             StringProcessor<BruteForce> proc;
  2.             proc.Storage().Search="knowledge";
  3.             proc.Init(txt,0,false);
  4.             count=proc.DoAll();

Jeder Suchalgo ist ein Struct mit entsprechend implementierten statischen Funktionen und durch verschachteln von Policies kann man auch noch ein bisschen mehr machen.

Code:
  1.             StringProcessor<Replace<ShiftAnd> > proc;
  2.             proc.Storage().Search="knowledge";
  3.             proc.Storage().Replace="beer";
  4.             proc.Init(txt,0,false);
  5.             count=proc.DoAll();

Init nimmt bis zu 3 Parameter, wobei 1.) der zu durchsuchende Text ist, 2.) Position im Text, wo gestartet werden soll und 3.) Flag ob der Text kopiert werden soll.
Große Texte zu duplizieren um drauf zu arbeiten ist nicht gerade was tolles, daher das optimierungs Flag.
Passend dazu hab ich auch meine Stringklasse aufgebohrt und um ein DataManagment Flag erweitert.
Code:
  1. const char* LONGERTEXT=
  2.             "The term ‘research’ has been viewed with mystique by many people. \
  3.             It is seen to be the preserve of academicians and professional \
  4.             .... ne menge text kommt hier eigentlich noch ^^
  5.  
  6. String txt(LONGERTEXT,DataManagment::UnmanagedInstance);

Beim programmieren hat man oft, dass man globale Variablen, Konstanten, statics, singleton variablen oder einfach Variablen hat, wo man weiß das die noch da ist, bis der String zerstört wird. Daher hab ich UnmanagedInstance, Copy und TransfereOwnership beim String eingeführt. UnmanagedInstance erwartet, dass der Input noch existiert, wenn der Destruktor durch läuft und räumt den Speicher auch selber nicht weg.
Copy braucht wohl keine Erklärung und TransfereOwnership geht davon aus, dass keine Kopie gemacht werden muss aber der Destruktor den Speicher abräumt. Letztes ist gerade beim arbeiten mit C API super dupa praktisch.

Ich hab mal einige Algos implementiert und gegeneinander antreten lassen, hier das Ergebnis.
Code:
  1. main.cpp(84): 1.000.000x brute force take 0days:0hour:0min:34sec,826msec:992microsec
  2. main.cpp(97): 1.000.000x Kuth Morris Pratt take 0days:0hour:0min:27sec,50msec:547microsec
  3. main.cpp(110): 1.000.000x Horspool take 0days:0hour:0min:7sec,311msec:418microsec
  4. main.cpp(123): 1.000.000x Sunday take 0days:0hour:0min:7sec,110msec:406microsec
  5. main.cpp(136): 1.000.000x Skip-Search take 0days:0hour:0min:7sec,899msec:451microsec
  6. main.cpp(149): 1.000.000x ShiftAnd take 0days:0hour:0min:20sec,576msec:176microsec


Ein Problem, was ich später noch Lösen muss, ist dass die letzten 4 Algos alle Lookupmaps nutzen, die die Größe von dem genutzten Alphabet haben. Das geht bei Ansi/Ascii noch gut aber bei UTF16 und 32 ist das ein bisschen Problematisch, 65KB Speicher kann man bei UTF16 vieleicht noch verkraften aber 4GB Speicher zu alloziieren ist dann doch eher unrealistisch, daher muss was für UTF32 anders gemacht werden.
Aktuell denke ich über ein compiletime Konstruktion, welche entsprechend dem Zeichensatz entweder einen array oder ein struct lädt, welches den suchtext analysiert und ein dynamische liste erzeugt. Das Struct müsste dann den Index( operator [](int index) ) operator überladen und wenn der Index nicht in der Liste ist entsprechend -1 zurück geben.

Never ending story

Ich habe fast alle SIMD operationen für ALU/FPU und SSE2 implementiert(die ich haben will ^^), es fehlt nur noch Avg, Min und Max.
Aktuell liegt der Code für SIMD um die 3000 Zeilen und das nachdem ich nochmal ordentlich sauber gemacht hab :\
Der wird auch nochmal ordentlich anwachsen, wenn ich 256Bit Variablen für SSE4, AVX und co nachziehe.
Zwischendurch hab ich auch noch Atomic Operation eingebaut, gibt ja nicht viele und hat auch nur ein paar Minuten gedauert.
Mitlerweile weiß ich, wieso es keine SIMD Bibliotheken gibt, das ist ne menge Arbeit und die Libs implementieren dann doch lieber den SIMD basierten Code direkt in den eigenen.
Ich freue mich schon auf die ersten Benchmarks, wenn ich meine Stringklasse SIMD fähig mache :)

Erfahrungen aus dem letzten Projekt

Für das nächste Projekt, auf Arbeit, muss ich den Logger überarbeiten, da unsere Server die meiste Zeit im Logger verbringen.
Der Logger war ein Konzeptuelles Fail, da er zwar Threadsafe ist aber der Thread, der was geloggt haben will es selber macht.
Also der Thread locked den Logger, schreibt in die Pipeline. Am Ende der Pipeline hängen Events, welche dann z.B. in Syslog, txt file und Konsole schreiben.
Wenn der Thread auf das schreiben, auf die Platte, warten würde, dann wäre das nicht so wild aber solange sind alle anderen Thread auf blocking, weil diese ja auch ins Log schreiben wollen. Nun mal ein paar hundert threads vorstellen und das Ergebnis ist erklärt.
Bei unseren Tests, mit 1600 Clients hatten wir bis zu 5 sekunden Verzögerung, beim schreiben ins Log.
Okey man muss sagen, wir öffnen und schliessen jedes mal das log, weil ein externes backupscript, von den Admins, auf unser log läuft und dann in /dev/null weiter schreibt, wenn das Script aktiv wurde.
Mein Plan, der Logger bekommt 2 Queues, einen mit spinlock(wird von anderen threads gefüllt) und der andere ist nicht threadsafe.
Der Logger Thread locked die externe Queue, swaped den Inhalt mit der internen und unlocked diese wieder und fängt an die interne ab zu arbeiten. Damit verlagert sich die ganze Pipeline Arbeit und die Threads können wieder weiter loggen, da ja die public queue frei ist.
Die Meiste CPU Zeit verbringe ich in malloc, welches von vsprintf gecalled wird(http://www.cplusplus.com/reference/clib ... /vsprintf/).
Ich will die Funktion selber nach schreiben und dort ein PoolAllocator verwenden, damit malloc und free raus bekommen(die teuersten calls, die man auf ein Windows machen kann, weil die bis zum OS gehen und der im OS Memory Manager rum wuselt, in Linux um einiges günstiger aber trotzdem teuer genug).

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Radon Framework
BeitragVerfasst: Mi Jan 11, 2012 01:36 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2621
Wohnort: Berlin
Programmiersprache: Go, C/C++
Ich habe lange nix mehr geschrieben und dass will ich nun mal nach holen.

Neue Hardware/Software, das alte Lied!
Am letzten Wochenende habe ich mein Server umgezogen, der neue Server ist um ein vielfaches besser und ich hab gleich mal die Chance genutzt und ein bisschen Software gepimpt.
Ich bin auf die aktuellen Versionen von Redmine und Jenkins umgestiegen und das SVN ist nun auch auf dem Server und auf dem neuesten Stand.
Es gibt nun ein svn+ssh zum schreiben und http für readonly.
In den nächsten Wochen werde ich dann mal ein paar kleine automatisierte Task einpflegen, Unittest und Static Code Analyse werden rein kommen.

Ohne Fundament kein Haus
In der Vergangenheit hab ich für alle Klassen immer direkt C/C++ array und pointer Container wieder und wieder implementiert und das kostet natürlich Zeit.
Entsprechend hab ich nach wenigen malen mich auf die STL Klassen gestürzt, dann aber immer wieder bestimmte Funktionalitäten neu implementiert, da STL Container nicht gerade viel Funktionalität bieten(soll es ja auch garnicht). Daher hatte ich mich vor einer weile dazu durch gerungen und angefangen eigene Container zu schreiben. Die Container hab ich von C# .Net4 abgeguckt und die haben ja viel von Java, also steckt insgesamt viel Hirnschmalz drin und ich konnte mich so mehr darauf konzentrieren alles raus zu werfen, was in C++ und speziell in der Gameentwicklung wenig Sinn macht.
Die erste Klasse ist fertig und es ist eine generische Array Klasse, welche nicht dynamisch ist. Hier ein paar Zahlen.
*1683 Zeilen Code
*66 Methoden/Constructor/Destructor
*621 Zeilen Unittest code
*41 Test cases
*0 mögliche Exceptions :)

Aktuell arbeite ich an einer Queue aber bin dabei auf ein Problem gestoßen.
Viele Entwickler steigen auf Lockfree Container um, da diese einfach performant sind und potenzielle Fehlerquellen eliminieren.
Leider hat die Medaille 2 Seiten und die Kehrseite ist düster, denn man kann nur ein kleinen Bereich der Funktionalität lockfree umsetzen.
Daher hab ich mich gegen das direkte Implementieren entschieden aber nun gibt es 2 neue Klassen AtomicInt32 und AtomicPointer.
Beide sind stark von QT inspiriert und die Implementierung war eine sache von Sekunden, da ich schon alle allgemeinen Funktionen vor einiger Zeit gewrapped habe.

Ich will möglichst viele Container implementieren, damit ich möglichst wenig Code neu schreibe, wenn ich höhere Klassen entwickle.
Aktueller Plan sind folgende.
*Array
*BitArray
*Queue
*PriorityQueue
*Stack
*List
*SortedList
*LinkedList
*Dictionary
*KeyValuePair
*Tree
*AVLTree
*Binary Heap

In den nächsten Tagen will ich auch noch die Stringklasse um eine Funktion erweitern, da ich im Netzt ein Artikel zu compile time hash gefunden habe und mit C++0x auch noch constexp hinzu kam.
Wenn man durch sein Code streift, dann findet man oft Codefetzen wie
Code:
  1. container["lustigerStringAlsKey"]=0;
oder ähnliches.
Dieser Fall und ähnliche Freunde machen viel Ärger, denn man wird sie zur Laufzeit nicht los, liegen im Speicher rum, kosten unnötig Zeit.
Daher kommt man natürlich auf die Idee, dass man statt einem string ein integer nutzten könnte aber dann wird der Code unleserlich.
In C++ kann man einige Dinge machen und beim Kompilieren den Hash eines Strings berechnen zählt dazu ^^.
Über kleine recht kurze templates kann man dafür sorgen, dass jedes Zeichen, des Strings, durchlaufen und ein Hash generiert wird.
Dank compiler optimierung wird dann der ganze entrollte code als konstant erkannt und vom compiler zusammen gerechnet und übrig bleibt dann eine Hash.
Für alle die auf den neuen Standard setzen geht das noch einfacher, da man dank constexp nicht mal mehr templates braucht.
http://gamedevstudent.com/journal/2011/05/compile-time-string-hashing-in-c0x/
C++ basierte data driven game Engines lieben diese Möglichkeit und mein ServiceLocator auch :) .

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Radon Framework
BeitragVerfasst: Sa Feb 04, 2012 23:51 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2621
Wohnort: Berlin
Programmiersprache: Go, C/C++
Automatisierung
Ich hab seit dem letzten Post die automatische generierung der Dokumentation und die statische Code Analyse umgesetzt.
Leider funktionieren die Unit-Tests nicht, da mein Code aktuell nicht unter Linux kompiliert :shock:
Dank CppCheck hab ich schon diverse Style Probleme gelöst und es sind auch keine neuen Meldungen mehr hinzu gekommen aber die Zeit, die für die Analyse benötigt wird ist schon recht lang(1h 16min). Daher muss man schon mal ein weilchen weiter Arbeiten, bevor man das Resultat des letzten Commits sehen kann.
Die Compiler Fehler, unter Linux, werde ich in laufe der kommenden Woche fixen, wenn nicht soviel Zeit habe.
Docu vom trunk
CppCheck results

Collections
Die Liste, vom letztem Post wird so langsam kleiner und in Anbetracht, dass ich verhältnismäßig wenig Zeit rein gesteckt habe sogar schneller als Erwartet.
*Array done
*BitArray
*Queue done
*PriorityQueue
*Stack (refactoring wird irgendwann folgen)
*List (refactoring wird irgendwann folgen)
*SortedList
*LinkedList
*Dictionary
*KeyValuePair done
*Tree done
*AVLTree (refactoring wird irgendwann folgen)
*Binary Heap

Refactoring

Aktuell strukturiere ich sehr stark um, damit sich klare Grenzen ziehen lassen, die Abhängigkeiten sich reduzieren und die Entwicklung einfacher wird.
Ich teile mein Code in 3 Kategorien, System spezifischer Code, auswechselbarer Code und generischen Code.
System spezifischer Code sollte immer so klein wie möglich sein, da man bei einer portierung diesen komplett neu schreiben muss.
Auswechselbarer Code sind z.B. fremde Bibliotheken ala SQLite und kann unter umständen Arbeit bedeuten, wenn man eine neue Platform erschliesst aber in der Regel sollte man Bibliotheken nutzten, die auf vielen Zielplatformen verfügbar sind.
Generischer Code ist Platformunabhängig und baut eventuell auf den beiden anderen Arten von Code auf.
Daher sollte natürlich die letzte Art von Code nahezu die ganze Codebase aus machen, damit wenig Arbeit an fällt, wenn man neue Zielsysteme erschliesst.
Mein Code war diesbezüglich recht unsortiert, zwar sind die Klassen alle nach den 3 Typen entwickelt und sauber getrennt aber man konnte bis dato nicht erkennen, ob nun eine Klasse Platformabhängig ist oder auswechselbar.
Ich hab nun mit den Namespaces von .Net gebrochen(welches für mich eine Vorlage für die Struktur war).

Namespace RadonFramework::... Auswechselbarer und Generischer Code.
Namespace RadonFramework::System... Systemspezifischer Code, der für jede Platform neu geschrieben werden muss.

Man kann auswechselbaren Code ganz einfach von dem generischen Code unterscheiden, da ich für den auswechselbaren Code immer das Service und ServiceLocator Pattern verwende(abgeleitete Klassen tragen immer Service und ServiceLocator mit im Namen).
Also kann man nun anhand des Namespaces und des Klassennamen auf den Typ von Code schliessen.

In den letzten 2 Tagen hab ich gut 100 files im Framework angefasst und refactored und es werden noch mehr werden.
Viele Klassen sind für mein Geschmack am falschen Ort, da sie noch aus Uralt Zeiten stammen oder schlicht aufgrund der .Net Namespaces auch wirklich falsch lagen.
Das verschieben ist mit einiges an Arbeit verbunden und kostet Zeit, daher tu ich immer Etappenweise Klassen verschieben und neuen Code schreiben.
So hab ich nun support für farbigen Konsolen Text :D
Bild

Ich arbeite auch an ein data driven design für RadonFramework, so hab ich eine neue Demo geschrieben.
Code:
  1. <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  2. <config>
  3.     <Logger DefaultPatternLayout="%M %D %h:%m:%s %C(%P): %d"
  4.             EnableExtendedMemoryManagment="true">
  5.         <SetChannel ID="0" MaxEntries="100" Pattern="Fun house in channel %C: %d"/>
  6.         <SetChannel ID="1" MaxEntries="100"/>
  7.         <SetChannel ID="2" MaxEntries="100"/>
  8.         <SetChannel ID="3" MaxEntries="100"/>
  9.         <OnChange Add="Console"/>
  10.     </Logger>
  11. </config>

Die Demo lädt die xml über eine URI, bestimmt dabei über ServiceLocator das Protokoll und den Decoder und gibt mir dann ein XML Baum zurück. Ich habe ein 28Zeilen Code, der XML-Bäume in ein generischen Baum umwandelt.
Dieser Baum ist vom Typ DataTree und kennt nur key,value Nodes, vom Typ String(Attribute werden z.B. zu Nodes umgewandelt).
Man kann also Problemslos SQL, ini, json, mkv und so weiter einlesen und muss dann über ein eigenen Konverter in den DataTree konvertieren.
Es gibt nun Interpreter Code, welcher ein DataTree entgegen nimmt und dann sich aus dem Baum die Daten saugt und im Framework setzt.
Im Beispiel hab ich den Logger konfigurierbar gemacht.

Ich hab meine CMake Konfiguration erweitert und lasse nun eine C++ file generieren, welche statische Konstanten enthält, die sagen welchen Endiantyp das Binary hat, welche Bit-Architektur und welche Framework Version verwendet wurde.
Vor lagen diese Informationen in Funktionen und defines bereit, da aber Defines meine Statische Code Analyse extrem in die Länge ziehen, hab ich angefangen die Defines zu entfernen.

Es gibt nun auch eine Klasse Environment, welche Informationen über die OS Version, Typ und Bit Architektur zur verfügung stellt.
So kann man raus bekommen, ob man z.B. in WOW64 als 32Bit App läuft und darauf hin die 64Bit Variante starten und den 32Bit Prozess beenden.

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Radon Framework
BeitragVerfasst: So Mär 11, 2012 06:45 
Offline
DGL Member
Benutzeravatar

Registriert: Di Mai 18, 2004 16:45
Beiträge: 2621
Wohnort: Berlin
Programmiersprache: Go, C/C++
Der letzte Post ist auch schon ein Monat her und da hat sich ein bisschen getan.
Neben den regulären Aufräumen und Bugfixes hab ich folgende nennenswerten Dinge getan.

Time
Ich hab ein interessanten Artikel über floatingpoint Genauigkeit gelesen.
Darauf hin hab ich nochmal in meine Zeitbezogenen Code geguckt und fest gestellt, dass ich zwar diese Problemstellen korrekt umgangen hab aber gar kein high resolution counter für Windows hatte. Also eigentlich hatte ich gar keine API dafür aber unter Linux benutze ich "gettimeofday(...)" und der ist high resolution.
Windows GetSystemTimeAsFileTime ist zwar wahnsinnig schnell aber hat eine genauigkeit von 10-20ms, da hat man kein Spaß dran.
Nun hab ich eine API dafür nach geliefert.

Wenn man sich vorstellt, dass man eine Physik mit 200Hz(5ms) hat, die CPU verbrennt die meiste CPU Zeit mit GetSystemTimeAsFileTime, weil er 10-20ms nur diese Funktion auf ruft um dann zu merken, oh 20ms sind vergangen, hol ich mal fix 4 Durchläufe nach, verbrenne wieder 10-20ms CPU Zeit für GetSystemTimeAsFileTime, nun sind 20ms+Zeit für 4 Durchläufe vergangen(sagen wir mal 6ms), also müssen 5 Updates gemacht werden und so weiter.
Das ist ganz fern von ordentlicher CPU Nutzung, da lange nix passiert, dann ein Peek auf voller CPU last, wieder ruhe und das ist schlecht.

Thread Pool
Ich habe ein Thread Pool implementiert, welcher bisher noch fix 8 Thread generiert und diese mit Task füttert.
Es gibt 2 Arten von Tasks Strategien, Concurrent und SerialPerThread.
Der ersten Typ von Task interessiert sich nicht dafür, wann er ausgeführt wird und ist der typische Task.
Der zweite Typ von Task wird seriell ausgeführt aber mit dem Unterschied, dass er der gleiche Task von einem anderem Thread gleichzeitig ausgeführt werden kann. Ein Beispiel für SerialPerThread ist das loggen. Jeder Thread kann in das Log System schreiben und alle Logeinträge, eines Threads, sind in korrekter Reihenfolge aber dazwischen können Logeinträge von einem anderem Thread stehen.
Würde man kein SerialPerThread nutzten, dann wäre alles durcheinander und in meinem Fall hatte der UnitTest das Endgültige Resultat zwischen den einzelnen Tests ausgegeben und auch einzelne Tests in falschen TestSuites einsortiert.

Log System
Ich hab das Log System überarbeitet und ich bin recht zufrieden :)
Das neue System nutzt den ThreadPool, statt ein eigenen Thread.
Es besteht nun nur noch aus statischen Methoden, statt einem Singleton.
Vorher haben sich Console und Logfile über ein Callback beim Logger registriert und nun gibt es Appender Klassen.
Diese werden in eine Liste eingetragen und der Task, aus dem ThreadPool, ruft nun alle Appender mit dem Text auf.
Es gibt nun keine Custom Channels mehr und damit gibt es Info, Error, FatalError und Debug.
Jeder Channel kann über eine statische Variable an und aus makiert werden(schaltet es nicht ab).
Die Macros, mit den man weniger Tippen musste, habe ich auch stark gepimpt, diese überprüfen nun die statischen Variablen und führt den Code nur entsprechend aus.
All diese Änderungen haben die Performance, Latenz, Speicher Operationen, Verwendbarkeit stark verbessert.
Code:
  1. //vorher
  2. Log::GetInstance().OnChange+=Console::GetInstance().Connector<Console,const LogChannel*>(&Console::WriteLog);
  3. //nachher
  4. Log::AddAppender(AutoPointer<Appender>(new LogConsole()));
  5.  
  6. LogInfo("OS: %s",os.VersionString().c_str());


Im Rahmen, dessen hab ich noch die String formatierungs Funktions stark optimiert, obwohl es nur 2 Zeilen Code wahren ^^.
Ich hab ein statischen Buffer eingebaut, dieser 8K Buffer wird entsprechend beim Programmstart erstellt und beim Programmende zerstört.
Stringlängen von mehr als 8096 Zeichen hab ich bisher nicht gebraucht und damit entfallen die teuren Speicheroperationen.
Sollte mal doch mehr benötigt werden, dann wird dynamisch Speicher erstellt, was natürlich lahm ist.
Ein weiterer Punkt, der bei dieser Optimierung zu nennen ist, man muss nun diese Funktion Thread-Safe machen, da ja sonnst mehrere Threads in den gleichen Buffer schreiben würden.
Bisher hatte ich noch kein Fall, wo ich damit Probleme bekommen würde aber eine Lösung ist schon in der Hinterhand.
Ich übergebe einfach den Buffer, als Parameter, dann muss der Highlevel Code sich drum kümmern und da ist das recht einfach.

Core Types
Für einige Typen, die ich für Radon Framework definiert habe, nutzte ich ein typedef auf den passenden C++ Typ.
Code:
  1. typedef Bool unsigned char;

Das ging lange gut aber mit den C++ Typen ist das wie ne Wundertüte, nicht alle halten sich an die C Konventionen und einige Typen gab/gibt es auch gar nicht.
Jedenfalls hat VC++ Probleme damit Bool und andere C++ Typen auseinander zu halten, da mein typedef zum einen nur ein alias ist, den der Compiler auflöst und zum anderem sind wohl einige Typen aliase auf C typen und damit kam VC++ nicht klar.
Nun hab ich Bool zu einem struct gemacht und damit ist es wirklich ein neuer Typ, der auch ein paar goodies dabei hat :)
Die String Klasse kann nun beim Konvertieren "True" und "False" erzeugen, statt "1" oder "0", damit auch der Logger und bei allen bool Operationen, mit Bool variablen wird ein Bool result entstehen.

Projekt pflege
Ich hab einige tote Header/Source/Nutzdaten aus dem SVN geworfen, darunter auch ein paar MB an Texturen, Models und Sound.

Der XML Namespace ist aus den Trunk raus gewandert und liegt nun im Modules Ordner.
Damit ist es kein Bestandteil von RF mehr.
Ich will alle Dateiformate aus RF raus haben, da sowas Projektspezifisch ist und jeder andere Präferenzen hat.
Es gibt zig Bibliotheken, welche Dateiformate lesen können und ich sehe die bei mir nur die Arbeit, die Binärdaten zu laden aber nicht diese zu interpretieren.
Um die Daten korrekt zu interpretieren, braucht man Informationen, die nur im Kontext einer Software bekannt sind, z.B. ist xml bei Programm A eine config und bei Programm B ein UI-Form.

Ich hab die CMake files überarbeitet und nun hat man mehr Kontrolle über die einzelnen Bereiche vom RF.
So habe ich ein minimal Build für das HardProf Projekt.

Aktuelle Aufgaben
Ich habe ein Subproject angefangen, HardProf soll ein Hardware Profil erstellen können und dieses über ein Webservice bereit stellen.
Der Client und ein großteil der Funktionalität soll aus dem RF kommen und daher ändert sich die Roadmap mal wieder.

Folgende Container entwickle ich gerade.
-BitSet
-BitList
BitSet ist ein fixer Bitarray, welcher die bestmögliche Platznutzung verwendet.
Die Klasse ist fertig und ich schreibe aktuell die UnitTests dafür.
BitList ist eine dynamische Variante, welche ein bisschen größer ist, weil sie eine Variable mit Länge und ein Pointer benötigt, um die Bit-Liste zu verwalten.
Die Klasse ist auch fertig aber wie BitSet ungetestet und bekommt entsprechend auch ein UnitTest.

Ich muss die Thread Klasse um eine Thread Affinity Mask Funktion erweitern, damit ich die Codeausführung auf ein bestimmten CPU-Kern erzwingen kann.
Dies benötige ich für die CPUID funktion und auch für den HighPrecisionCounter.
CPUID gibt immer die Daten der CPU zurück, auf dem die Instruktions ausgeführt wird, wenn man also 2 CPUs hat, dann muss man diese auch auf beiden ausführen, sonnst bekommt man ja nur Infos über eine doppelt.
Für diese Funktion benötige ich aber eine BitMask und daher die beiden Container, die ich vorher erwähnt habe.

Ich werde eine ProcessorInformation Klasse schreiben, die Informationen über die Extensions, Caches, Family, Name, Hardware Threads und so weiter raus gibt.
Diese werde ich über CPUID füttern, also brauch ich erstmal Thread Affinity Mask ^^

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 64 Beiträge ]  Gehe zu Seite 1, 2, 3, 4, 5  Nächste
Foren-Übersicht » Sonstiges » Projekte


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 6 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
cron
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.033s | 19 Queries | GZIP : On ]