[Java] Cross-class performance

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Iska
  • Registratie: November 2005
  • Laatst online: 07-10 22:49

Iska

In case of fire, use stairs!

Topicstarter
Hey guys,

Ik ben nu bezig met een app voor Android in Java. Nu heb ik een class die gebruikt wordt om alles te drawen op het scherm. Alle berekeningen en variables heb ik echter in een andere class staan die dus telkens wordt aangeroepen door de eerste class.
Wat ik mij nu afvraag is of het een verschil zal maken in performance als ik alle variables en functies in de eerste hoofdclass zet ipv een tweede 'assistant'-class..

-- All science is either physics or stamp collecting


Acties:
  • 0 Henk 'm!

  • CoolGamer
  • Registratie: Mei 2005
  • Laatst online: 12-10 15:22

CoolGamer

What is it? Dragons?

Voor performance maken zulke dingen tegenwoordig niet zoveel meer uit. De Just-in-time-compiler zorgt er meestal voor dat zulk soort dingen gewoon net zo efficiënt werken.

¸.·´¯`·.¸.·´¯`·.¸><(((º>¸.·´¯`·.¸><(((º>¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸<º)))><¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸


Acties:
  • 0 Henk 'm!

  • Iska
  • Registratie: November 2005
  • Laatst online: 07-10 22:49

Iska

In case of fire, use stairs!

Topicstarter
Prima :D, dan ga ik lkkr zo door. Werkt stuk makkelijker ;)

-- All science is either physics or stamp collecting


Acties:
  • 0 Henk 'm!

  • CoolGamer
  • Registratie: Mei 2005
  • Laatst online: 12-10 15:22

CoolGamer

What is it? Dragons?

Het is zelfs juist aan te raden om niet alles in 1 class zetten om zo een beter overzicht te behouden, beter ontwerp te krijgen en dat je daardoor makkelijker code kan hergebruiken.

¸.·´¯`·.¸.·´¯`·.¸><(((º>¸.·´¯`·.¸><(((º>¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸<º)))><¸.·´¯`·.¸.·´¯`·.¸.·´¯`·.¸


Acties:
  • 0 Henk 'm!

  • EddoH
  • Registratie: Maart 2009
  • Niet online

EddoH

Backpfeifengesicht

Weet niet of de JIT compiler voor Dalvik al overal gebruikt wordt, en als performance écht een absoluut vereiste is dan is het aan te raden in ieder geval:

http://developer.android.com/guide/practices/design/performance.html

...te lezen.

Acties:
  • 0 Henk 'm!

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Het is vooral aan te bevelen om de variabelen die je gebruikt bij een berekening in dezelfde klasse te hebben als waar de berekening zit. En ook eventuele loops om een berekening te starten kan je beter - indien dat past bij je code - dicht bij de berekening zelf houden. Of je de aanroep van die start en de weergave van het resultaat dan in losse klassen hebt is meestal niet zo relevant voor je performance.

Uiteraard moet je ook goed letten op de onderhoudbaarheid van je code. Het gros van je code is niet of nauwelijks relevant voor de runtime performance van je applicatie, dus je kan die code het beste netjes opzetten zodat je bugfixes en uitbreidingen makkelijker kunt realiseren.

Acties:
  • 0 Henk 'm!

  • Gorion3
  • Registratie: Februari 2005
  • Laatst online: 04-10 14:26

Gorion3

ABC++

Waar je vooral op moet gaan letten is in dit geval garbage collection, meestal zorgt dat er voor dat er stotteringen in je app/game komen.

Awesomenauts! Swords & Soldiers


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 02:34

.oisyn

Moderator Devschuur®

Demotivational Speaker

De vraag is hoe je bij dat andere object komt. Als je daar een referentie naar hebt als member van je huidige object, dan is dat een extra niveau aan indirectie (want je doet dan this.foo.bar, ipv gewoon this.bar), met extra cache misses tot gevolg. Wat cache betreft loont het sowieso om alle gegevens bij elkaar te hebben staan.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 01:41
EddoH schreef op dinsdag 25 januari 2011 @ 21:12:
Weet niet of de JIT compiler voor Dalvik al overal gebruikt wordt ..
Dalvik :? We hebben het hier over Java, niet over Android. ;) (En ja, ik weet dat Android de taal Java gebruikt, maar niet het Java platform). D'oh! Ik moet lezen. Het ging inderdaad om Android.
ACM schreef op woensdag 26 januari 2011 @ 08:04:
Het is vooral aan te bevelen om de variabelen die je gebruikt bij een berekening in dezelfde klasse te hebben als waar de berekening zit.
Heb je hier een bron bij? Het enige verschil tussen een attribuut binnen een object en buiten een object is dat de ene via een impliciete reference ("this") benaderd wordt en de andere via een expliciete reference, maar dat maakt voor de te genereren code niets uit.

De enige situatie waarin ik me kan voorstellen dat er een verschil zit tussen attributen binnen en buiten een klasse, zou zijn wanneer je attributen benadert via accessor methods én je gebruik maakt van polymorfisme op die methods, waardoor de compiler ze niet kan inlinen. Dat zal meestal niet het geval zijn, en de compiler is slim genoeg om te detecteren wanneer een methode niet overridden is.

Tenslotte zal bij het updaten van de GUI in de meeste gevallen het daadwerkelijke tekenwerk de bottleneck vormen en maakt het dus niet heel veel uit hoe efficiënt de rest van de code is. Er zijn wel uitzonderingen (als je een HTML-pagina met een paar duizend elementen eerst moet layouten bijvoorbeeld) maar dat zijn het ook precies: uitzonderingen.

Acties:
  • 0 Henk 'm!

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

Soultaker schreef op woensdag 26 januari 2011 @ 14:06:
Heb je hier een bron bij? Het enige verschil tussen een attribuut binnen een object en buiten een object is dat de ene via een impliciete reference ("this") benaderd wordt en de andere via een expliciete reference, maar dat maakt voor de te genereren code niets uit.
Het is vooral een gut-feeling dat (private) variabelen binnen een klasse - of zelfs wellicht binnen een functie - sneller zijn dan die buiten een klasse vandaan halen (zie ook .oisyn's reactie). De server-jvm is dan vziw in sommige situaties zelfs sneller. Maar zo'n veel simpelere jvm als die van dalvik zal nog wel wat meer optimalisaties (zoals de geavanceerdere escape analysis) wellicht nog missen.

Maar als je inderdaad je codekwaliteit/leesbaarheid moet opofferen moet je er wel heel goed naar kijken of je zoiets zou doen.

Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 01:41
ACM schreef op woensdag 26 januari 2011 @ 14:16:
Het is vooral een gut-feeling dat (private) variabelen binnen een klasse - of zelfs wellicht binnen een functie - sneller zijn dan die buiten een klasse vandaan halen (zie ook .oisyn's reactie).
Misschien moeten we het even wat concretiseren. Stel je hebt code als deze:
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Bar {
    public int[] a;
    public get(int i) { return a[i]; }
}

class Foo {
    private int[] a;
    private Bar bar;

    int methode1(Bar bar) {
        int res = 0;
        for (int i = 0; i < 10; ++i) res += bar.a[i];
        return res;
    }

    int methode2() {
        int res = 0;
        for (int i = 0; i < 10; ++i) res += a[i];  // a[i] == this.a[i]
        return res;
    }

    int methode3(Bar bar) {
        int res = 0;
        for (int i = 0; i < 10; ++i) res += bar.get(i);
        return res;
    }

    int methode4() {
        int res = 0;
        for (int i = 0; i < 10; ++i) res += bar.a[i];  // this.bar.a[i]
        return res;
    }
}

Er is mijns inziens weinig verschil in performance te verwachten tussen deze methoden. De eerste methode refereert alleen aan bar, en de tweede alleen aan this; voor de compiler is dat vergelijkbaar (er is geen reden waarom this magischerwijs efficiënter zou zijn.) De derde methode roept een bar.get() aan, maar deze call kan eenvoudig geïnlined worden, en dan is de code equivalent aan de eerste methode.

De eerste methode heeft een extra parameter wat in theorie een klein verschil kan maken, maar als de methode zelfde geïnlined kan worden verdwijnt dat voordeel ook.

De vierde methode is wat .oisyn bedoelde: om een referentie naar bar te krijgen moet je eerst aan this refereren wat een extra stap oplevert, en een extra cache miss. Maar in loops zoals deze kan de compiler deze extra stap buiten de lus halen, en sowieso is de overhead daarvan heel klein.

Al deze verschillen zijn dermate klein dat ik niet denk dat het zinnig is er in dit stadium voor te optimaliseren, zeker aangezien we het over GUI code hebben. Als die traag is, komt dat meestal omdat er teveel (her)berekend en (her)tekend wordt, en zijn er meestal zinnigere optimalisaties te vinden dan dit soort micro-optimalisaties die de leesbaarheid van de code niet ten goede komen.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 02:34

.oisyn

Moderator Devschuur®

Demotivational Speaker

Soultaker schreef op woensdag 26 januari 2011 @ 14:35:
De vierde methode is wat .oisyn bedoelde: om een referentie naar bar te krijgen moet je eerst aan this refereren wat een extra stap oplevert. Maar in loops zoals deze kan de compiler deze extra stap buiten de lus halen.
Zoals ACM terecht opmerkt, de vraag is of de Dalvik jitter aan uitgebreide escape analysis doet. In dit voorbeeld maakt het niet zoveel uit, maar als je in de method een andere method aanroept, en de jitter is niet slim genoeg om te kunnen zien wat die method intern doet, dan moet hij this.bar opnieuw opvragen. Wellicht heeft de aangeroepen method 'm namelijk aangepast.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • EddoH
  • Registratie: Maart 2009
  • Niet online

EddoH

Backpfeifengesicht

Er worden hier teveel aannames gedaan over de handigheid van de compiler in de verschillende situaties.

Om even in te haken op het voorbeeld van Soultaker:
...
Avoid Internal Getters/Setters

In native languages like C++ it's common practice to use getters (e.g. i = getCount()) instead of accessing the field directly (i = mCount). This is an excellent habit for C++, because the compiler can usually inline the access, and if you need to restrict or debug field access you can add the code at any time.

On Android, this is a bad idea. Virtual method calls are expensive, much more so than instance field lookups. It's reasonable to follow common object-oriented programming practices and have getters and setters in the public interface, but within a class you should always access fields directly.

Without a JIT, direct field access is about 3x faster than invoking a trivial getter. With the JIT (where direct field access is as cheap as accessing a local), direct field access is about 7x faster than invoking a trivial getter. This is true in Froyo, but will improve in the future when the JIT inlines getter methods.
...
Verder ben ik het er natuurlijk gewoon mee eens dat je wel de bottleneck moet zoeken en geen voorbarige optimalisaties toe moet poassen als die niet significant zijn.

Acties:
  • 0 Henk 'm!

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 01:41
.oisyn schreef op woensdag 26 januari 2011 @ 14:39:
In dit voorbeeld maakt het niet zoveel uit, maar als je in de method een andere method aanroept, en de jitter is niet slim genoeg om te kunnen zien wat die method intern doet, dan moet hij this.bar opnieuw opvragen.
Klopt, maar dan nog heb je in het algemeen alleen de eerste keer een cache miss. (Tenzij de cache entry al weer overschreven is natuurlijk, maar dat is meestal omdat er "veel" binnen de lus gebeurt, en in dat geval maakt één cache miss extra ook weer niet veel uit.)

(Deze hele discussie heeft een hoog "maar als, .. tenzij, .. mits" gehalte omdat het gewoon heel lastig is om precies aan te geven wat er wel of niet gebeurt zonder concrete code te evalueren, maar dat lijkt me juist een goede reden om de code niet overhoop te gooien voor enkele micro-optimalisaties waarvan je niet weet wat ze precies opleveren.)
EddoH schreef op woensdag 26 januari 2011 @ 14:43:
Er worden hier teveel aannames gedaan over de handigheid van de compiler in de verschillende situaties.
Ok, misschien wel, maar uit de docs die je quote blijkt alleen dat er mogelijk verschil zit tussen het direct benaderen van attributen, of via een accessor method, en niet dat de kosten daarvan verschillen tussen this of een andere reference, waar het de TS oorspronkelijk om te doen was.

Acties:
  • 0 Henk 'm!

  • EddoH
  • Registratie: Maart 2009
  • Niet online

EddoH

Backpfeifengesicht

Soultaker schreef op woensdag 26 januari 2011 @ 15:17:

[...]

Ok, misschien wel, maar uit de docs die je quote blijkt alleen dat er mogelijk verschil zit tussen het direct benaderen van attributen, of via een accessor method, en niet dat de kosten daarvan verschillen tussen this of een andere reference, waar het de TS oorspronkelijk om te doen was.
Klopt, slaat idd niet op originele vraag, wat vluchtig gelezen.
Maar het geeft wel aan dat niet alles wat je soms van een compiler kan verwachten, zoals het inlinen van een getter ook daadwerkelijk gebeurd in het geval van de Dalvik compiler.
Pagina: 1