Domanda

Non so molto riguardo la struttura interna del compilatore JIT e le ottimizzazioni, ma io di solito cerco di usare "buon senso" di indovinare quello che potrebbe essere ottimizzato e ciò che non poteva. Così ci stavo scrivendo un metodo di test di unità semplice di oggi:

@Test  // [Test] in C#
public void testDefaultConstructor() {
    new MyObject();
}

Questo metodo è in realtà tutto quello che serve. Si controlla che il costruttore di default esiste e funziona senza eccezioni.

Ma poi ho cominciato a pensare l'effetto di ottimizzazioni del compilatore / JIT. Potrebbe il compilatore / JIT ottimizzare questo metodo, eliminando completamente la dichiarazione new MyObject();? Naturalmente, sarebbe necessario determinare che il grafico chiamata non ha effetti collaterali ad altri oggetti, che è il caso tipico di un normale costruttore che inizializza semplicemente lo stato interno dell'oggetto.

presumo che solo il JIT sarebbe stato permesso di eseguire una tale ottimizzazione. Questo probabilmente significa che non è qualcosa che dovrei preoccupare, perché il metodo di prova viene eseguita una sola volta. Sono la mia ipotesi è corretta?

Tuttavia, sto cercando di pensare al tema generale. Quando ho pensato di come evitare questo metodo venga ottimizzato, ho pensato posso assertTrue(new MyObject().toString() != null), ma questo è molto dipendente dalla effettiva implementazione del metodo toString(), e anche allora, il SIC può determinare tale metodo toString() restituisce sempre un non nullo stringa (ad esempio, se effettivamente Object.toString() viene chiamata), e quindi ottimizzare l'intero settore. Quindi in questo modo non avrebbe funzionato.

So che in C # posso usare [MethodImpl(MethodImplOptions.NoOptimization)], ma questo non è quello che sto effettivamente cercando. Spero di trovare un modo (indipendente dal linguaggio) di fare in modo che una parte specifica (s) del mio codice verrà effettivamente eseguito come mi aspetto, senza il JIT interferire in questo processo.

In aggiunta, ci sono casi tipici di ottimizzazione dovrei essere a conoscenza di quando la creazione di mio test di unità?

Grazie mille!

È stato utile?

Soluzione

Non ti preoccupare. Non è permesso di ottimizzare sempre tutto ciò che può fare la differenza per il vostro sistema (fatta eccezione per la velocità). Se un oggetto nuovo, il codice viene chiamato, la memoria viene allocata, si deve lavorare.

Se avessi è protetto da un if (false), in cui falsa è una finale, potrebbe essere ottimizzato dal sistema completamente, allora si potrebbe rilevare che il metodo non fa nulla e ottimizzare out (in teoria ).

Modifica: tra l'altro, può anche essere abbastanza intelligente per determinare che questo metodo:

newIfTrue(boolean b) {
    if(b)
        new ThisClass();
}

sarà sempre fare nulla se B è falso, e alla fine a capire che a un certo punto nel codice B è sempre false e compilare questa routine da quel codice completamente.

Questo è dove il JIT può fare cose che è praticamente impossibile in qualsiasi lingua non gestiti.

Altri suggerimenti

Credo che se siete preoccupati per ottenerlo ottimizzato via, si può fare un po 'di prove eccessivo.

In un linguaggio statico, tendo a pensare al compilatore come un test. Se passa la compilazione, il che significa che certe cose sono lì (come i metodi). Se non si dispone di un altro test che esercita il vostro costruttore di default (che si rivelerà non ci vorrà buttare eccezioni), si consiglia di riflettere sul perché si sta scrivendo che costruttore di default, in primo luogo (YAGNI e tutto il resto).

So che ci sono persone che non sono d'accordo con me, ma mi sento come questo genere di cose è solo qualcosa che gonfiare il tuo numero di test per nessun motivo utile, anche guardando attraverso gli occhiali TDD.

Pensare in questo modo:

lascia supporre che il compilatore in grado di determinare che il grafico chiamata non ha effetti collaterali (non credo sia possibile, mi ricordo vagamente qualcosa su P = NP dai miei corsi CS). Sarà ottimizzare qualsiasi metodo che non ha effetti collaterali. Dal momento che la maggior parte delle prove non hanno e non devono avere alcun effetto collaterale poi compilatore li può ottimizzare tutti via.

Il JIT è consentito solo per eseguire operazioni che non influenzano la semantica garantiti del linguaggio. In teoria, si potrebbe rimuovere l'assegnazione e chiamata al costruttore MyObject se è in grado di garantire che la chiamata non ha effetti collaterali e non può mai generare un'eccezione (senza contare OutOfMemoryError).

In altre parole, se il JIT ottimizza la chiamata fuori del test, allora il test sarebbe passato comunque .

PS: Si noti che questo si applica in quanto si sta facendo funzionalità di prova al contrario di prestazioni testing. Nel test delle prestazioni, è importante assicurarsi che il JIT non ottimizza via l'operazione che si sta misurando, altrimenti i risultati diventano inutili.

Sembra che in C # ho potuto fare questo:

[Test]
public void testDefaultConstructor() {
    GC.KeepAlive(new MyObject());
}

AFAIU, il metodo GC.KeepAlive non verrà inline dal JIT, in modo che il codice verrà garantito per funzionare come previsto. Tuttavia, non so un costrutto simile a Java.

Perché dovrebbe importare? Se il compilatore / JIT in grado di determinare in modo statico non afferma stanno per essere colpito (che potrebbe causare effetti collaterali), allora stai bene.

Ogni I / O è un effetto collaterale, in modo da poter semplicemente mettere

Object obj = new MyObject();
System.out.println(obj.toString());

e che stai bene.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top