Technology Experience

Contenuti gestiti da Igor Damiani
posts - 949, comments - 2741, trackbacks - 15120

My Links

News

  • Questo blog si propone di raccogliere riflessioni, teoriche e pratiche, su tutto quello che riguarda il world-computing che mi sta attorno: programmazione in .NET, software attuale e futuro, notizie provenienti dal web, tecnologia in generale, open-source.

    L'idea è quella di lasciare una sorta di patrimonio personale, una raccolta di idee che un giorno potrebbe farmi sorridere, al pensiero di dov'ero e cosa stavo facendo.

    10/05/2005,
    Milano

Archives

Post Categories

Generale

[MCAD.35] Creare assembly in codice nativo con ngen.exe

Abbiamo parlato di caspol.exe, di sn.exe e di gacutil.exe. Un altro tool incluso in .NET è ngen.exe. Quest'ultimo permette di compilare un assembly in codice nativo, allo scopo di (poterne) migliorarne le performance durante la sua esecuzione. Normalmente, come ben sappiamo, tutte le volte che generiamo un assembly con .NET, il file EXE o la DLL sono scritti in IL (intermediate language), il quale viene a sua volta tradotto in codice x86 tramite il meccanismo di compilazione JIT (just-in-time).

Quando un assembly viene eseguito, quindi, il framework deve intervenire, per compilarlo e finalmente eseguirlo. Ovviamente, le prestazioni potrebbero risentirne, dato che c'è tutta una fase che il framework deve completare prima di poter vedere qualcosa sullo schermo (parlando banalmente di un'applicazione Windows Forms). Questo è almeno parzialmente risolvibile con il tool ngen.exe. Non ho mai fatto un prova reale sul campo, quindi non so dirvi che tipo di guadagno c'è veramente. Però intanto vediamo come usare ngen, poi magari ne parleremo.

Compilare un assembly con ngen.exe
ngen.exe è sicuramente il tool con la sintassi più semplice (escludendo dir, cd, del e qualche altro comando DOS...  dai...sto scherzando). Per generare l'immagine nativa di un assembly basta infatti dare un comando simile al seguente:

ngen ReadPerformance.exe

Basta semplicemente specificare il nome dell'assembly (attenzione, senza path, bisogna essere nella directory giusta) su cui si vuole lavorare. Nulla di più. Già, ok, ma cosa abbiamo veramente fatto con questo comando? Inizialmente, da ignorante, mi aspettavo di vedere il mio EXE modificato, cambiato in qualche modo. Pensavo avvenisse una sorta di compilazione che cambiasse radicalmente il mio assembly: poi, ho visto che la dimensione del file, e la sua data/ora di ultima modifica erano rimaste le stesse. Dov'è finito il mio assembly compilato in native code?

Per capire meglio l'uso e lo scopo di ngen.exe ho dato più di una lettura a questa pagina su MSDN. C'è una riga, proprio all'inizio, che mi è sfuggita diverse volte e che alla fine mi ha risolto la questione: "The native image cache is a reserved area of the global assembly cache". Ah, adesso ho capito. Il mio assembly è finito nella GAC. Effettivamente, se provate a dare un'occhiata alla directory C:\Winnt\Assembly ecco il nostro assembly, denominato ReadPerformance, indicato come Native Images. Quindi, se noi provassimo a lanciare il nostro assembly dalla solita directory bin\Debug, in realtà il runtime di .NET si accorgebbe che nella GAC c'è un assembly in native-code, e quindi preferirebbe l'esecuzione di quest'ultimo.

Un'annotazione (che mi è costata qualche punticino negli ultimi test che ho fatto): ricordiamoci che per poter inserire un assembly nella GAC, dobbiamo avere diritti amministrativi sul PC (quindi, quando usiamo gacutil.exe o, appunto, ngen.exe).

Ci sono i pro, ma ci sono anche i contro
Ok, abbiamo capito che ngen.exe può essere molto utile per velocizzare l'esecuzione di una nostra applicazione. Ma non è tutto oro quello che luccica. Ci sono diversi fattori che possono rendere un assembly in native-code non valida. Cosa succede in questo caso? Nulla di drammatico: semplicemente, il runtime di .NET si accorge che la native-image è invalida, quindi ritorna al buon vecchio assembly in IL, e passa alla compilazione JIT. Quali sono questi fattori che possono invalidare un assembly? Li riporto da MSDN senza tradurre:

  1. the version of the .NET Framework
  2. the CPU type
  3. the version of the operating system
  4. the exact identity of the assembly (recompilation changes identity)
  5. the exact identity of all assemblies that the assembly references (recompilation changes identity)
  6. security factors

Se anche uno solo di questi fattori interviene, allora la nostra native image non è più valida, e l'assembly viene eseguito dal runtime in JIT. Voglio fare qualche commento.

Il punto (2) è chiaro. La native image contiene istruzioni in linguaggio macchina, specifiche quindi di una certa famiglia di processori. Se la native image viene eseguita su un sistema con un altro tipo di processore, con un altro set di istruzioni, l'assembly non può essere eseguito in native code.
I punti (4) e (5) dicono espressamente che ogni volta che ricompilo un assembly, la sua identity cambia, e di conseguenza anche la sua native image non è più valida. Di conseguenza, è molto meglio usare ngen.exe solo quando abbiamo compilato l'assembly pronto per il rilascio.
Il punto (6) parla di security. Ad esempio, se generiamo una native image con il Code Access Security disattivato, l'assembly in native code diventerà non valido quando riattiveremo il CAS. Francamente, non vedo perchè uno debba dare il comando:

caspol -security off

Non dite a nessuno che ve l'ho fatto vedere, mi è scappato per sbaglio un CTRL+V dalla mia command-line. Comunque sia, quelli elencati prima sono i fattori che possono influire sulla validità di una native image generata con ngen.exe. Come ho detto prima, .NET si accorge da solo di questo problema, non dice nulla, semplicemente ritorna ad eseguire l'assembly tradizionale. Può essere però che ci accorgiamo di una perdita di prestazioni, dovuta al fatto che l'assembly gira in JIT.

Usare ngen.exe su un assembly senza strong-name
Dunque, abbiamo detto che ngen.exe posiziona il nostro assembly in native code nella GAC. Abbiamo detto che per poter finire nella GAC, un assembly deve avere uno strong name. Allora, mi sono chiesto, com'è possibile che sono riuscito a generare una native image di un assembly senza strong name?

Lo so, questo è un blog e non un forum. Difatti, ho inserito questo post sul forum di UGIdotNET, ma non ho ancora avuto risposte. Se qualcuno sa illuminarmi, per favore, si faccia avanti.

powered by IMHO 1.2

Print | posted on Wednesday, September 21, 2005 12:10 PM | Filed Under [ MCAD ]

Feedback

Gravatar

# re: [MCAD.35] Creare assembly in codice nativo con ngen.exe

Prima di decidere di utilizzare NGEN per precompilare tutte le tue applicazioni, dovresti considerare che questo approccio riduce lo start-up time solo per un piccolo numero di applicazioni, prima tra tutte quelle che effettuano un considerevole numero di chiamate a metodi all'avvio. In alcuni casi, precompilare una applicazione può peggiorare le performance perchè NGEN non sa niente riguardo il runtime enviroment e non può quindi usare tecniche di ottimizzazioni come apdative method inling e l'ottimizzazione cross-assembly. Per ultima cosa, ricordarti che non puoi usare NGEN per convertire IL a native code ed eseguire l'eseguibile in un altro sistema.
9/21/2005 1:12 PM | alessio.marziali
Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET