2009-03-05 15 views
23

Sto scrivendo un gioco XNA in cui eseguo controlli di collisione per pixel. Il ciclo che verifica ciò avviene spostando un ORing bitonale e int e generalmente è difficile da leggere e capire.Posso controllare se il compilatore C# ha delineato una chiamata al metodo?

Vorrei aggiungere metodi privati ​​come private bool IsTransparent(int pixelColorValue) per rendere il ciclo più leggibile, ma non voglio il sovraccarico delle chiamate ai metodi poiché questo è un codice molto sensibile alle prestazioni.

C'è un modo per forzare il compilatore a incorporare questa chiamata o lo farò? Spero solo che il compilatore faccia questa ottimizzazione?

Se non c'è un modo per forzare questo, c'è un modo per verificare se il metodo è stato inarcato, a meno di leggere lo smontaggio? Il metodo verrà visualizzato in riflessione se è stato allineato e nessun altro chiamante esiste?

Modifica: Non riesco a forzarlo, quindi posso rilevarlo?

+1

È possibile (in .Net 4.5). usando: '[MethodImpl (MethodImplOptions.AggressiveInlining)]' – Mahmoodvcs

risposta

23

No non si può. Ancor più, colui che decide di inlining non è il compilatore VS che ti porta il codice e lo converte in IL, ma il compilatore JIT che prende IL e lo converte in codice macchina. Questo perché solo il compilatore JIT conosce abbastanza l'architettura del processore per decidere se mettere un metodo in linea sia appropriato in quanto è un compromesso tra il pipelining dell'istruzione e la dimensione della cache.

Quindi anche cercare in .NET Reflector non ti aiuterà.

+0

Altri elemosinano la differenza di riflessione poiché utilizza lo stack di chiamate. http://stackoverflow.com/questions/44153/can-you-use-reflection-to-find-the-name-of-the-currently-executing-method/44171#44171 –

+1

Non ho detto reflection, I detto riflettore, come in Red Gates .NET Reflector. –

+0

Mio male, ho capito male. –

1

No, non è possibile.

Fondamentalmente, non è possibile farlo nella maggior parte dei compilatori C++ moderni. inline è solo un'offerta al compilatore. È libero di prenderlo o no.

Il compilatore C# non esegue alcuna inlining speciale a livello IL. L'ottimizzatore JIT è quello che lo farà.

+0

"Se non c'è un modo per forzare questo, c'è un modo per verificare se il metodo è stato allineato, a meno di leggere lo smontaggio? Il metodo verrà mostrato in riflessione se era in linea e nessun altro chiamante esiste? " –

+0

No, dubito che il compilatore C# faccia qualche inlining. Compilatore JIT è responsabile per questo. –

+0

È possibile verificare System.Reflection.MethodBase.GetCurrentMethod(). Name. Se il metodo è in linea, restituirà il nome del chiamante. –

14

"È possibile controllare System.Reflection.MethodBase.GetCurrentMethod(). Name. Se il metodo è inline, verrà restituire il nome del chiamante invece."

- Joel Coehoorn

+0

Funzionerà solo in fase di esecuzione. –

+19

Ovviamente funzionerà solo in fase di esecuzione, ovvero quando si verifica l'inlining. –

+10

Non chiama questo metodo nel tuo codice cambia l'IL reale, che teoricamente cambierebbe il "ragionamento" del compilatore JIT se dovrebbe essere in linea o no? –

0

È possibile rilevarlo in fase di esecuzione con la chiamata GetCurrentMethod di cui sopra. Ma sembrerebbe un po 'uno spreco [1]. La cosa più semplice da fare sarebbe solo ILDASM il MSIL e controllare lì.

Nota che questo è specifico per il compilatore inlining della chiamata ed è coperto nei vari documenti Reflection su MSDN.

Se il metodo che chiama il metodo GetCallingAssembly viene espanso in linea dal compilatore (cioè, se il compilatore inserisce il corpo funzione nella lingua intermedia Microsoft emessa (MSIL), piuttosto che emettendo una chiamata di funzione), allora l'assembly restituito dal metodo GetCallingAssembly è l'assembly che contiene il codice inline. Questo potrebbe essere diverso dall'assembly che contiene il metodo originale. Per garantire che un metodo che richiama il metodo GetCallingAssembly non sia delineato dal compilatore, è possibile applicare l'attributo MethodImplAttribute con MethodImplOptions.NoInlining.

Tuttavia, il JITter è anche libero da chiamate in linea, ma penso che un disassemblatore sarebbe l'unico modo per verificare ciò che è e non è fatto a quel livello.

Modifica: solo per chiarire un po 'di confusione in questa discussione, csc.exe will inline MSIL calls - sebbene JITter sia (probabilmente) più aggressivo al suo interno.

[1] E, per rifiuto, intendo che (a) che sconfigge lo scopo dell'inlining (prestazioni migliori) a causa della ricerca di Reflection. E (b), probabilmente cambierebbe il comportamento in linea in modo che non fosse più in linea comunque. E, prima di pensare di poterlo solo accendere con build di Debug con un Assert o qualcosa del genere, renditi conto che non sarà inserito durante Debug, ma potrebbe essere in Release.

+0

Sì: è assolutamente inutile testarlo in fase di esecuzione. Se fosse JIT in linea, probabilmente c'era una buona ragione per farlo, e questo controllo non farebbe che peggiorare le cose. Ma ho preso questo come più di un esercizio di apprendimento: lui vuole "sperimentare" inlining per se stesso. Il codice non protetto –

1

perché non utilizzare codice non sicuro (inline c come è noto) e utilizzare i puntatori di stile c/C++, questo è sicuro dal GC (cioè non influenzato dalla raccolta) ma ha le sue implicazioni sulla sicurezza (non può essere usato per app di zona internet), ma è eccellente per il tipo di cosa che si sta cercando di ottenere soprattutto con le prestazioni e ancora di più con gli array e le operazioni bit a bit?

per riepilogare, vuoi prestazioni per una piccola parte della tua app? utilizzare codice non sicuro e utilizzare i puntatori, ecc sembra l'opzione migliore per me

EDIT: un po 'di un antipasto? http://msdn.microsoft.com/en-us/library/aa288474(VS.71).aspx

+4

è spesso più lento del codice gestito, poiché il JIT non può garantire il numero di garanzie in modo tale che non possa eseguire determinate ottimizzazioni. Quindi se lo fai, come sempre, ** profilo! ** –

0

C'è un modo per forzare il compilatore a inline questa chiamata o farò Spero solo che il compilatore farà questa ottimizzazione?

Se è meno costoso integrare la funzione, lo farà. Quindi non preoccuparti a meno che il tuo profiler non dica che in realtà è un problema.

Per ulteriori informazioni

JIT Enhancements in .NET 3.5 SP1

4

essere consapevoli del fatto che la Xbox funziona diverso.

Google alzato questa:

"Il metodo inline che mitiga il sovraccarico di una chiamata di un metodo forme JIT in una linea quanto soddisfa le seguenti condizioni

  • Il codice IL.. dimensione è di 16 byte o meno.
  • Il comando ramo non viene utilizzato (se frase ecc).
  • La variabile locale non viene utilizzato.
  • La gestione delle eccezioni non è stata effettuata a (try, catch, ecc.).
  • float non viene utilizzato come argomento o valore di ritorno di un metodo (probabilmente da Xbox 360, non applicato).
  • Quando due o più argomenti sono in un metodo , vengono utilizzati per il turno dichiarato .

Tuttavia, una funzione virtuale non è formata in linea."

http://xnafever.blogspot.com/2008/07/inline-method-by-xna-on-xbox360.html

ho idea se è corretta. Chiunque?

+0

Grazie per aver segnalato questo. In realtà è abbastanza rilevante per me. Sarebbe bello vederlo in un documento ufficiale però. –

1

L'unico modo per verificare questo è quello di ottenere o scrivere un profiler, e agganciare sui fatti JIT, è necessario anche fare assicurarsi inlining non si spegne come lo è di default a profilare

14

C'è un nuovo modo per incoraggiare più aggressivo di espansione in .net 4.5 che è descritto qui:. http://blogs.microsoft.co.il/blogs/sasha/archive/2012/01/20/aggressive-inlining-in-the-clr-4-5-jit.aspx

Fondamentalmente si tratta solo di una bandiera per TE Se il compilatore è in linea, se possibile. Sfortunatamente, non è disponibile nella versione corrente di XNA (Game Studio 4.0), ma dovrebbe essere disponibile quando XNA raggiungerà VS 2012 quest'anno. È già disponibile se in qualche modo stai girando su Mono.

[MethodImpl(MethodImplOptions.AggressiveInlining)] 
public static int LargeMethod(int i, int j) 
{ 
    if (i + 14 > j) 
    { 
     return i + j; 
    } 
    else if (j * 12 < i) 
    { 
     return 42 + i - j * 7; 
    } 
    else 
    { 
     return i % 14 - j; 
    } 
} 
Problemi correlati