dinsdag 16 december 2008

Delphi Prism: XNA, LINQ, .Net CF en meer!

Aangezien Delphi Prism een volledige .Net taal is, ondersteunt het zonder problemen het MS XNA Framework (voor oa game ontwikkeling).
Voor een demo van de "XNA Tutorial 1" in Delphi Prism:
http://blogs.codegear.com/pawelglowacki/2008/12/11/38629

Verder ondersteunt Delphi Prism gewoon LINQ.
Voor een demo van "LINQ to Objects":
http://www.monien.net/blog/index.php/2008/12/delphi-can-do-linq/
En een demo van "LINQ to SQL":
http://www.monien.net/blog/index.php/2008/12/delphi-can-even-linq-to-sql/

En met een paar kleine aanpassingen kun je Delphi Prism ook gewoon gebruiken met het .Net Compact Framework (video):
http://cc.codegear.com/Item/26379

CodeGear heeft ook een handig overzicht gemaakt van Delphi Prism gemaakt, waarbij de belangrijkste features uitlegd worden:
"Delphi Prism Reviewers Guide"
http://dn.codegear.com/article/39113

Met Delphi Prism is Delphi weer helemaal terug, en vooral "Cross Platform":
http://www.infoq.com/news/2008/11/Delphi-Prism

Naast de "Class Completion" die de Delphi ontwikkelaars goed kennen, heeft Prism nu ook "Variable Completion" en "Method Completion":
http://prismwiki.codegear.com/en/Variable_Completion
http://prismwiki.codegear.com/en/Method_completion

Ook "Sync Editing" is een handige extra feature:
http://prismwiki.codegear.com/en/Sync_Editing
http://www.monien.net/blog/index.php/2008/12/enable-sync-editing-in-delphi-prism/

Trouwens, de wiki help van Delphi Prism ondersteunt ook RSS feeds (te zien aan het oranje feeds symbool in Firefox).
Dan kun je makkelijk zien wat er gewijzigd is, als er iets verandert:
http://prismwiki.codegear.com/en-w/index.php?title=Special:RecentChanges&feed=rss

maandag 15 december 2008

Delphi Object Repository gebruiken

Bij mijn huidige klant moest ik even uitzoeken hoe de "Object Repository" van Delphi gebruikt kan worden, zodat bepaalde framework templates (forms, frames, datamodules, maar ook complete template projecten) door de ontwikkelaars gebruikt kunnen worden. Ik kon voor Delphi 2007 op internet niet direct iets vinden hoe dit nou werkt en hoe je dit in kunt stellen (wel voor oudere versies). In de CodeGear Help stond gelukkig wel het een en ander (trouwens, niet via de "help" knoppen in Delphi zelf, daar heb je niks aan).

Shared Repository instellen

Als eerste maak je een bepaalde map aan, bijvoorbeeld "P:\Lib\Repository". Dit kan een gesharede netwerk map zijn, maar kan ook een lokale map zijn die je via een versie beheer systeem beheert. Vervolgens moet in Delphi de eerder gemaakte map als “Shared Repository” ingesteld worden:
Delphi 2007 Tools Options:













Delphi 2007 verwacht het bestand “BorlandStudioRepository.xml” in deze directory. Dit XML bestand bevat de items die Delphi kan gebruiken uit de repository. Dit bestand is overigens zelf eenvoudig aan te passen (namen, bestanden, etc). Delphi maakt dit bestand zelf niet aan, maar verwacht wel dit bestand (anders werkt het niet!). Het beste is om het huidige bestand te gebruiken: deze staat in de map "C:\Documents and Settings\\Application Data\Borland\BDS\5.0\". Kopieer deze in de eerder gemaakt directory, en start Delphi opnieuw op (!).

Repository gebruiken

De items die in de repository staan, kunnen gebruikt worden via:
Delphi → File → New → Other:











Het volgende scherm wordt dan getoond:

Selecteer een item en "Inherit" en druk op “OK”.

Items toevoegen aan de repository

Er kunnen 2 soorten items aan de repository toegevoegd worden: losse items (forms, frames, datamodules) en complete projecten.

Project toevoegen

Een project kan aan de repository toegevoegd worden via:
Delphi → Project → Add to repository:
























Los item toevoegen

Een los item kan aan de repository toegevoegd worden, door in de “Form manager” (form, frame of datamodule) met de rechtermuisknop te klikken, en dan “Add to Repository”:












Repository beheren

Items in de repository kunnen bewerkt of verwijderd worden via:
Delphi Tools Repository












Alleen items kunnen bewerkt worden, de categorieën zelf niet (hiervoor moet je “BorlandStudioRepository.xml” zelf aanpassen).

donderdag 11 december 2008

Random things & tips #2

Even weer een "dump" van mijn bezigheden, ontdekkingen en ervaringen tijdens het programmeren :-)
  • TThread.Queue (asynchroon!)
    Sinds Delphi 2007 (?) kun in plaats van "Synchronize" ook de "Queue" functie gebruiken. Nadeel van "Synchronize" is dat de huidige thread geblokkeerd wordt totdat de main thread de functie uitgevoerd heeft (synchroon). Met "Queue" kun je asynchroon de functie laten uitvoeren in de main thread! (de huidige thread gaat dus gewoon door).
  • TryStrToInt, StrToIntDef
    Vaak kom ik de volgende code tegen:
    try
    i := StrToInt( s );
    except
    i := 0;
    end;
    Beter is om TryStrToInt of StrToIntDef te gebruiken!
  • "Pretty Print" XML (netjes inspringen etc)
    Dit kan eenvoudig met de functie "FormatXMLData" uit de unit "XMLDoc".

  • Delphi uitbreidingen en unsupported fixes:
    http://andy.jgknet.de/blog/
    - DDevExtensions 1.9.2 (handige plugin!)
    - DelphiSpeedUp 2.78 (sneller opstarten)
    - IDE Fix Pack 2007 2.1 (IDE bugfixes)
    - VCL Fix Pack 1.0 (VCL runtime fixes)
  • Stomme laptop "Fn" toets zit vast!
    Dit bleek een "numlock" functie te zijn van mijn Acer Aspire: Fn + F11 om aan/uit te zetten
  • ModelMaker tutorials
    Voor diegene die nog nooit ModelMaker gebruikt heeft:
    http://www.thoughtsmithy.com/mmjump/MMGettingStarted_Intro.html
    ModelMaker is echt een hele mooi en goede tool voor ontwikkeling (UML diagrammen, eenvoudig en snel classes en properties maken, etc), maar ook voor documentatie: UML diagrammen genereren van de classes van je code!
  • Tip: Low prio programma starten
    Om een programma in een batch bestand (of gewoon command line) met lage prio uit te voeren, kan het "start" commando gebruikt worden. Bijvoorbeeld: 7zip in batch bestand, low prio, 1 voor 1, geminimaliseerd:
    start /LOW /WAIT /MIN C:\7za\7za.exe a -tzip -mx9 files.7z *.txt

dinsdag 9 december 2008

Delphi Prism beschikbaar!

Delphi Prism is de nieuwste Delphi .Net versie. Het is echter een geheel andere versie dan vorige Delphi .Net versies: het is een soort plug-in in de Visual Studio Shell. Hierover zijn de meningen nogal verdeeld, vooral omdat het geen echte nieuwe Delphi .Net "versie" is maar een geheel nieuw en ander product. Anderzijds is het nu een volledige up-to-date .Net taal, met volledige ondersteuning voor de allerlaatste .Net technieken (LINQ, WPF, WCF, etc). Het heeft ALLE features van C#, PLUS extra handige uitbreidingen! Voor een vergelijking
met C#: http://prismwiki.codegear.com/en/Delphi_Prism_vs._CSharp


Vooral deze extra uitbreidingen maken Delphi Prism interessant. Zo kan nu heel gemakkelijk een blok code of functie asynchroon c.q. parallel uitgevoerd worden via "async
" blokken en "future" variabelen. Dit is veel makkelijker dat dan met C# en Parallel Framework! Verder kan makkelijker met "nullable types" en nil objecten gewerkt worden. "Locked" properties, "Property Notification","Exception filters" etc etc, allemaal handige verbeteringen voor programmeurs.
Nog een voordeel ten opzicht van standaard Visual Studio, is de support voor Linux en Mac OS X
, door middel van Mono.
En ja, de Wiki van Delphi Prism is erg interessant: http://prismwiki.codegear.com
.

Wat dat betreft biedt Delphi Prism veel meer .Net mogelijkheden dan de vorige Delphi .Net versies. Borland heeft wel geprobeerd om te concurreren met Microsoft, ook met C# Builder, maar dit was een bijna onmogelijk taak. Vooral omdat met .Net de ontwikkelomgeving heel nauw samenwerkt met het framework. Zoals de designers voor Winforms en WPF, ondersteuning voor LINQ, Parallel Framework, etc. De ontwikkelingen gingen zo snel, en Borland moest steeds het wiel opnieuw uitvinden c.q. implementeren, zodat het altijd een stuk achter zou lopen. Vandaar: "If you can't beat them, join them". Door de Visual Studio Shell te gebruiken, hoeft men niet meer alles zelf te maken, maar kan direct gebruik gemaakt worden van de aanwezige designers en technieken.

De taal Delphi zelf is wel wat veranderd en uitgebreid. Het sluit nu beter met .Net aan. De reden hiervoor is dat de Win32 en .Net ontwikkelingen steeds meer uiteen lopen. Als men de beide Delphi's zou proberen compatibel te houden met elkaar, zou dat alleen maar vertragen en hinderen. Nu kunnen beide versies ontwikkeld en geoptimaliseerd worden voor hun eigen doelgebieden. Marc Hoffman licht dit ook toe in een interview:
http://www.bitwisemag.com/2/Delphi-Prism-Visual-Studio-Pascal


Als Delphi ontwikkelaar vind ik de VS Shell enerzijds wel jammer, ik had ook liever een echte Delphi IDE gehad ipv VS Shell. Ook het missen van de VCL is jammer. Aan de andere kant is de VCL voor .Net overbodig geworden door WinForms en al helemaal met WPF. De situatie is nu anders dan destijds met Windows 3.11 tot Windows XP. Trouwens, de volgende Visual Studio wordt helemaal WPF based:
http://blogs.msdn.com/ricom/archive/2008/11/18/the-visual-studio-tech-roadmap-starring-visual-studio-2010.aspx

Dus de volgende versie van Delphi Prism kan hiervan gelijk profiteren!

Bestaande Delphi projecten kunnen dus niet 1 op 1 in Delphi Prism geopend worden. Wel zijn ze bezig met een tool die het converteren makkelijker moet maken, namelijk Oxidizer:
http://prismwiki.codegear.com/en/Oxidizer

Ook een Delphi compatible RTL is in ontwikkeling, ShineOn:
http://prismwiki.codegear.com/en/ShineOn

Trouwens, C++ en VB programmeurs moeten een veel grotere omslag maken, die moeten helemaal "opnieuw" beginnen.

Hoewel het voor bestaande Delphi.Net gebruikers jammer is voor deze omslag, heb ik in deze stap van CodeGear meer vertrouwen. Nu kan men zich volledig richten op extra features en uitbreidingen, gericht op de ontwikkelaars.En deze lijst is met verbeteringen is groot:
http://prismwiki.codegear.com/en/Delphi_Prism_Syntax_compared_with_Win32_Delphi


Delphi is onder CodeGear weer sterk bezig met grote opmars. Met Prism is het weer modern en klaar voor de toekomst!

Delphi Prism kan als .iso gedownload worden:
http://cc.codegear.com/free/radstudio

ftp://ftpd.codegear.com/download/RADStudio2009/DelphiPrismISO.iso

vrijdag 21 november 2008

Random thoughts…

  • Ik heb een nieuwe versie van "map2dbg" gemaakt. Hiermee kun je weer de .map bestanden van Delphi en C++Builder 2007, 2009 (en verder?) omzetten naar een .dbg (Microsoft debug) bestand. Deze kun je weer gebruiken met Proces Explorer (kijken waarom je app. hangt of waar hij mee bezig is etc) en met MS WinDbg (analyseren van minidumps/memorydumps).
    http://asmprofiler.googlecode.com/files/map2dbg.zip

  • Eerste ervaringen met de gratis Turbo C++ Builder:
    De sources van map2dbg waren gelukkig openbaar, dus ik kon met de gratis versie van Turbo C++ een fix en een nieuwe build maken. Mijn eerste ervaring met C++Builder ("wat een boel compiler opties! die wil ik ook in Delphi!") en na een lange tijd weer met C++. Brrr, wat kun je met C++ lelijke code maken zeg... :-)
    http://turboexplorer.com/downloads

dinsdag 4 november 2008

Delphi Prism (.Net) beter dan C#?

Er is een interessant interview met Marc Hoffman over Delphi Prism:
http://www.bitwisemag.com/2/Delphi-Prism-Visual-Studio-Pascal
Screencast:
http://www.delphi.org/screencasts/3-DelphiPrismVideo1.html

Onder andere over verbeteringen van Delphi Prism ten opzichte van C#:

Makkelijker werken met null values en nullable types:
http://wiki.remobjects.com/wiki/Colon_Operator
http://wiki.remobjects.com/wiki/Nullable_Types

Makkelijker "Parallel Framework" / PFX features gebruiken:
http://wiki.remobjects.com/wiki/Future_(keyword)
http://wiki.remobjects.com/wiki/Parallel_Loops
http://wiki.remobjects.com/wiki/Asynchronous_Statements

Overig: locking, uitgebreide "for each", support:
http://wiki.remobjects.com/wiki/Locked_(keyword)
http://wiki.remobjects.com/wiki/For_(keyword)#Shortcut_syntax_.22for_each.22.2B.22from.22
Support voor "Mono on Linux" en "Cocoa# on MaxOS X"

Overzicht van alle features:
http://wiki.remobjects.com/wiki/Oxygene
http://wiki.remobjects.com/wiki/Language_Features_3.0_(Oxyg%C3%A8ne)

donderdag 9 oktober 2008

SQL Server: nested transacties dmv workaround

Oa voor unit testen wilde ik nested transacties gebruiken bij MS Sql Server 2005. Tot mijn verbazing is dit standaard niet mogelijk via ADO! Het is wel mogelijk via SQL, maar dan nogal omslachtig… Uiteindelijk is het me gelukt…

Je kunt namelijk handmatig transacties starten en committen via SQL met “BEGIN TRANSACTION” en “COMMIT TRANSACTION” statements. Dit kan ook nested, waarbij je transacties een naam kunt geven, bijv: “BEGIN TRANSACTION level1″.

Echter, een rollback wordt ALTIJD op de buitenste transactie gedaan! Dus niet netjes nested zoals met een commit…
Na wat zoekwerk vond ik de oplossing: savepoints gebruiken. Na elke “BEGIN TRANSACTION” doe ik een “SAVE TRANSACTION ”. Deze savepoint kunt je weer ongedaan maken via “ROLLBACK TRANSACTION ”. Echter, de transactie bestaat nog steeds, dus na de rollback moet je nog een commit (!) doen op de transactie zelf. Verre van netjes, maar het werkt…

Bijvoorbeeld:
In het onderstaande voorbeeld worden 2 transacties gebruikt, waarbij de 2e en geneste transactie weer ongedaan gemaakt wordt. De 1e transactie wordt wel gecommit. Het resultaat is dat “something 1″ wel opgeslagen is, maar dat “something 2″ niet doorgevoerd is in de database.

BEGIN TRANSACTION level1
SAVE TRANSACTION save1

BEGIN TRANSACTION level2
SAVE TRANSACTION save2

ROLLBACK TRANSACTION save2
COMMIT TRANSACTION level2

COMMIT TRANSACTION level1

dinsdag 23 september 2008

Dll Import Table van executable aanpassen

In mijn vorige blogpost over de TC hack, had ik beloofd uit te leggen hoe je de hack (dll) vast in kunt bouwen, zodat het elke keer direct bij het starten van het programma actief wordt.

Dit is onder andere mogelijke door de "DLL Import Table" van de executable aan te passen. Deze table bevat namelijk de statisch gelinkte dlls en hun procedures (dus niet wat het programma zelf runtime dynamisch kan laden!). Deze tabel wordt door Windows in gelezen en alle dll's worden automatisch geladen. Door nu deze tabel aan te passen, kun je dus je eigen dll laden!

Na wat zoek en prutswerk kwam ik de volgende (werkende) tool tegen:
"Explorer Suite" (http://www.ntcore.com/exsuite.php ).
Een van de onderdelen van deze suite is de "CFF Explorer". Dit is een resource explorer, waarmee allerlei "resources" van een exe/dll bekeken en aangepast kan worden (icons, resourcestrings, etc). Een van de dingen die aangepast kan worden is de Import Table.

Hiermee heb ik met succes de "TCMain.exe" (exe van TC) aangepast, zodat het altijd mijn extra dll laadt. Bij het laden van de dll wordt direct de hook toegepast (zie vorige post).
Een simpel stappenplan:

  1. Bestand laden (TCMain.exe in dit geval)
  2. "Import Adder" selecteren
  3. Add knop en dll selecteren (TCHook.dll in dit geval)
  4. Een willekeurige functie van de dll selecteren (deze wordt toch niet aangeroepen, maar je hebt nu eenmaal 1 nodig)
    Vervolgens op "Import by Name" knop drukken
  5. Import table opnieuw bouwen
  6. En de aangepaste exe opslaan

Dat was alles!

maandag 1 september 2008

Team Coherence hack -> 10x sneller!

Op mijn huidige detacheringsplek gebruiken ze "Team Coherence" (http://www.teamcoherence.com) voor versie beheer en bug/issue tracking. Ze gebruiken dit pakket heel strict: bijvoorbeeld elke check-in moet een tracker melding hebben, een tracker heeft aantal stadia (waaronder controle door de aanvrager of indiener), versie labels, promotion levels, etc.

Op zich zijn ze tevreden over dit pakket. Het pakket heeft wel een poos een dip gehad, waarbij het niet meer onderhouden werd door de makers, maar nu wordt weer af en toe een update uitgebracht. Het grootste probleem echter wat ze hadden, was dat het pakket steeds trager werd: opstarten duurde maar liefst anderhalve minuut! Ook wisselen van views etc duurde dik een minuut.

Toen ik even niets te doen had (wachten op specs etc), heb ik even gekeken met Proces Explorer naar wat de oorzaak kon zijn. Nu blijkt dat hij veel geheugen acties doet (van 10Mb oplopend naar 65Mb en dan weer 36Mb), en veel kernel/system (rood) tijd gebruikt. Zie onder (er is trouwens getest op een HT systeem, vandaar niet meer dan 50% CPU):


1 thead (main thread) is druk bezig. Zie onder:



Als we nu de stack trace opvragen (en dit een paar keer doen), dan blijkt dat hij steeds bezig is met "GlobalRealloc".
Zie onder:


Ik weet dat het een Delphi 5 programma is, en Delphi gebruikt maar op 1 plek Global memory: TMemorystream.SetSize. Waarschijnlijk wordt steeds een paar bytes geschreven (stream.Write(s) oid), zodat het geheugenblok steeds met paar bytes vergroot moet worden. Nu doet Windows dit niet efficiënt: zelfs als na het huidige blok genoeg ruimte is, hij kopieert altijd naar een nieuw blok geheugen. En dit kost tijd, vooral als het heel vaak gebeurt. Vandaar de "rode" systeem CPU tijd.

Nu heb ik al wat ervaring met hacken gekregen met mijn profiler (http://code.google.com/p/asmprofiler) en detouring, dus ik heb ik een kleine dll geschreven die de GlobalRealloc overruled, en 1Mb extra reserveert. Als de nieuwe ruimte nog past in het oude, dan doet het niets, anders vraagt het door middel van de originele GlobalRealloc nieuw geheugen aan (met weer 1Mb extra):

function HookedGlobalReAlloc(hMem: HGLOBAL; dwBytes: SIZE_T; uFlags: UINT): HGLOBAL; stdcall;
begin
if GlobalSize(hMem) < id="pcex4"> Result := trampoline_GlobalReAlloc(hMem, dwBytes + (1000*1024), uFlags) //reserve 1Mb extra mem
else
Result := hMem; //do not realloc if needed size fits in current size, GlobalRealloc ALWAYS does a resize, even when it is not needed!
end;

Door middel van dll injection heb ik dit in Team Coherence geladen (zowel server als client), en nu duurt het opstarten maar 10 seconden! Dus 10x sneller!

P.S. ik heb dit ook aan de makers gestuurd, nog geen reactie tot nu toe...
P.S.2 de volgende keer zal ik demonstreren hoe ik de executable aangepast heb, zodat altijd mijn extra dll geladen wordt (dll injection dus niet meer nodig elke keer).

dinsdag 19 augustus 2008

ADO = Traag, kan 2x sneller!

Ik had wel eens eerder gehoord dat ADO traag zou zijn, maar ik had met ADO nog geen ervaring.
(trouwens, deze traagheid geldt voor ADO Win32, ADO.net weet ik niet, maar als ik SQL Server Enterprise Manager 2003 (win32)
vergelijk met SQL Server Management Studio 2005 (.net) dan is de .Net versie VELE malen trager!)

Geen ervaring, tot nu toe, want bij mijn huidige opdracht hebben ze een aantal database performance problemen.
De performance problemen komen oa door een slecht ontwerp (elke cell in een grid/lijst is een object
met allerlei properties -> veel overhead), maar ook voor een deel door ADO. De data wordt namelijk
via ADO geladen in hun eigen data objecten.

Nu verloopt bij ADO alles via OLE interfaces. Elke call moet worden geconverteerd, gecontrolleerd, foutafhandeling ,etc.
Dit geeft veel overhead. En bij het laden van data gebeurt dit bij elke cell! Als je veel records met veel velden hebt, gaat het dus hard...
Om deze overhead te minimaliseren kun je zelf ook gebruik maken van de interfaces ipv bijv. de standaard ADO dataset van Delphi.
Dit kan het ongeveer 2x sneller maken! Vooral bij veel enkelvoudige queries (detail record van een ID ophalen).

Voorbeeld:

//eerst data laden
procedure LoadData(aSQL: string);
var
connection : TADOConnection;
recordset : _Recordset;
dataset : TADODataSet;
begin
//recordset bevat data van SQL statement (select * from bla)
recordset := connection.Execute( aSQL );

//of van (bestaande) dataset
dataset.CommandText := aSQL;
dataset.Open;
recordset := dataset.RecordSet;
end;

//dan data vullen in een data object oid
procedure FillData;
var
field : TField;
adofield : ADOInt.Field;
recordset : ADOInt._Recordset
i : integer;
olerows : OleVariant;
begin
for i := 0 to recordset.Fields.Count-1 do
begin
//store adofield reference
adofield := recordset.Fields[i];
//get field object by name
f := data.FieldByName( adofield.Name );

//get value
f.Value := adofield.Value;

//of
//vanaf ADO 2.5 30% sneller?
f.Value := recordset.Collect[i];

end;

//of: alle waarden van record (of meerdere regels) in een array:
//get all values of current row
olerows := recordset.GetRows(1, 0, EmptyParam);

for i := 0 to recordset.Fields.Count-1 do
//niet sneller maar iets trager?
f.Value := olerows[i, 0];
end;

PS: eventueel de waarde van OleVariant nog omzetten naar juiste type Variant dmv "VarAsType", want met
OLE kan bijvoorbeeld een datum of een decimaal als een intern type opgeslagen zijn.

vrijdag 13 juni 2008

Reflector + Reflexil: Verander de code van een assembly (!)

".Net Reflector" zullen de meeste .Net'ers wel kennen (.Net assemblies details bekijken, analyseren, decompilen, etc):
http://www.aisto.com/roeder/dotnet/Download.aspx?File=Reflector
Voor dit mooie programma zijn ook allerlei "add ins" beschikbaar:
http://www.codeplex.com/reflectoraddins

1 ervan is "Reflexil":
http://sebastien.lebreton.free.fr/reflexil/
Hiermee kan een assembly ook bewerkt worden! Bestaande code kan aangepast worden, of geheel vervangen worden door nieuwe code. Ik heb het zelf even getest met een Delphi.Net programma, en het werkt super.

Het is gebasseerd op Mono.Cecil, wat onderdeel is van het open source "Mono" project:
http://www.mono-project.com/Cecil

Een aantal voorbeelden hoe je een assembly kunt aanpassen:
http://www.codeproject.com/KB/msil/reflexil.aspx
http://blog.cumps.be/reverse-engineering-with-reflector-and-reflexil/

Wat wel even belangrijk is als je het zelf probeert: als je iets aangepast hebt, moet je in de tree van Reflector de assembly zelf selecteren. Dan pas kun je de wijzigingen opslaan :-).

Nu kan het een en ander natuurlijk moeilijker gemaakt worden dmv "obfuscation". Hiermee worden de originele namen vervangen door "abc", code structuur iets aangepast (geen mooie "if then else" constructies, etc):
http://blog.cumps.be/obfuscation-making-reverse-engineering-harder/

Ook kun je "Code Signing" gebruiken om het nog moeilijker te maken, maar het is en blijft vrij eenvoudig mogelijk om een assembly aan te passen:
http://blog.cumps.be/code-signing-as-reverse-engineering-protection/

Veel succes ermee! :-)

vrijdag 6 juni 2008

Snelheid + Schaalbaarheid .Net & Delphi

Als Delphi programmeur was ik nog een beetje sceptisch over .Net, vooral mbt de snelheid. Hiervoor heb ik in Delphi een klein programmaatje gemaakt, wat in 2 for loops wat strings heen en weer kopieert. Dit heb ik gemaakt in een thread, zodat ik ook makkelijk met meerdere threads kon testen. Dit programmaatje heb ik met Delphi 2006 zowel native als met Delphi.Net gecompileerd.

Test resultaten: Win32 vs .Net
Resultaten op een Intel Core2 Duo (dual core dus), MS .Net 2.0:
Delphi.Win32:
1 thread = 3s
2 threads = 6s + 6s

Delphi.Net:
1 thread = 2s
2 threads = 4s + 4s

.Net is dus sneller dan native! Bovendien schalen ze allebei niet goed, want beide keren bleef de CPU steken op zo'n 50% (dus geen goed gebruik van dual core).

Test resultaten: TopMM
Standaard gebruikt Delphi 200X de FastMM memory manager. Ik had al eens eerder een andere gezien, die wel goed zou moeten schalen: TopMM (http://topsoftwaresite.nl/Downloads/TopMemoryManager22.zip).

Resultaten:
Delphi.Win32, TopMM:
1 thread = 6s
2 threads = 6s + 6s

Tja, nu schaalt hij heel mooi (beide cores op 100%) maar de performance is wel slechter...

FastMM fix
Benieuwd waarom TopMM wel goed schaalt en FastMM niet, zat ik in de code te duiken. FastMM gebruikt een lock voor de memory pool, terwijl TopMM per thread een aparte pool heeft (geen locks dus nodig). Als eerste heb ik de lock eruit gehaald: nu kwam de snelheid ook op 2s! Maar goed, voor meerdere threads is die lock wel nodig. Toen heb ik even snel een hack gemaakt voor FastMM door oa een "threadvar" te gebruiken, zodat elke thread zijn eigen pool krijgt. Nu hebben beide threads 2s en 100% CPU, oftewel: Delphi.Win32 is even snel als .Net, maar bovenal: het schaalt beter!

Multi cores: nadeel voor .Net
Het grote nadeel nu aan .Net is dat je dit niet makkelijk zelf kunt fixen, wat in Delphi.Win32 wel makkelijk kan. Vooral met het oog op steeds meer cores per CPU is dit een slecht punt voor MS .Net.

MS CLR shared code
Benieuw hoe in .Net oa de string allocatie is, kwam ik via het volgende artikel:
http://selvasamuel.wordpress.com/2008/03/14/boxingunboxing-in-net/
op het idee om in de CLR code van Microsoft te duiken. Via het "Shared source" initiatief van MS kan iedereen een gedeelte van oa de CLR downloaden (maar niet aanpassen etc!):

Shared Source Common Language Infrastructure 2.0 Release
http://www.microsoft.com/downloads/details.aspx?FamilyId=8C09FD61-3F26-4555-AE17-3121B4F51D4D&displaylang=en

Als eerste heb ik in de ".Net Reflector" (http://www.aisto.com/roeder/dotnet/Download.aspx?File=Reflector)
de code opgezocht van mijn thread. Aan de hand hiervan naar de functie gesprongen (door te klikken in de code) voor het kopiëren van strings: System.String.Copy. Deze maakt oa gebruik van "FastAllocateString":
Deze functie was als volgt gedeclareerd (in C#):
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern string FastAllocateString(int length);

"InterCall" betekent dat het in de .Net CLR zelf geïmplementeerd is. Aan de hand van de shared code van MS van de CLR heb ik gezocht op "FastAllocateString". Deze functie wordt weer doorgelinkt van "ECall::FastAllocateString" naar "JIT_TrialAlloc::GenAllocString(flags)".
Hierin wordt net als FastMM een lock gebruikt. Helaas is deze lock niet makkelijk aan te fixen, oa omdat de Shared Source CLR niet compleet is.