Moderne OO-talen en HPC: wat is er tegenwoordig mogelijk?

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • Bananenplant
  • Registratie: Januari 2001
  • Laatst online: 20:51
Op zich ben ik blij met talen als Java en C#. Je kunt dingen intuïtief modelleren en vervolgens behoorlijk rap implementeren. Ook is de onderhoudbaarheid goed, gegeven dat je bij je ontwikkelproces een beetje nadenkt. Tegelijkertijd heb je te maken met een (soort van) virtual machine, garbage collection en dientengevolge performanceverlies. Ga je bikkelen in bv. Fortran, dan heb je misschien wel performance, maar is het ontwikkelen een stuk lastiger.

Nu vroeg ik me af of er niet een soort beste van de twee werelden bestaat. Als je complexe simulaties wilt doen lijkt voor de beheers- en begrijpbaarheid OO me namelijk een grote winst terwijl je ook performance wilt. Ik heb al wel wat gegoogled: in Edinburgh geven ze een HPC-cursus voor Java, ik heb ergens benchmarks van .Net 1.1 gezien met matrixmultiplicaties, maar het lijkt een beetje dun gezaaid allemaal.

Nu vroeg ik me af of jullie een idee hebben hoe het landschap inzake OO + HPC eruit ziet tegenwoordig. Ik kan me namelijk niet voorstellen dat men in de HPC-wereld wil blijven hangen in talen die qua begrijpelijkheid en onderhoudbaarheid "achterblijven", om het zo even te zeggen.

💶 Wil je in een vrije democratie blijven wonen? Betaal dan voor nieuws. 📰
❌ ceterum censeo contra factiones ad dextrum extremum esse pugnandum. 🙅🏻‍♂️


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Dit lijkt me meer wat voor SEA
PRG >> SEA

Verder lijkt het me nogal afhankelijk van wat je onder HPC verstaat en je probleem domein. Je hebt wellicht wat overhead in managed talen e.d., maar dat maakt het nog niet meteen HPC-ongeschikt lijkt me? En dat kleine beetje overhead lijkt me prima op te lossen door wat meer te investeren in hardware (want: goedkoper dan ontwikkeltijd). Sure, voor max. performance is het mischien niet altijd de beste keus, maar dan nog zijn er zoveel wegen die naar Rome leiden. Het is niet zwart-wit en je kunt natuurlijk altijd nog kiezen voor een mix van talen om je doel te bereiken én max. performance te halen.

[ Voor 87% gewijzigd door RobIII op 06-11-2008 17:34 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • eamelink
  • Registratie: Juni 2001
  • Niet online

eamelink

Droptikkels

Zit je met een specifiek probleem dat je op wilt lossen, of is het meer gewoon algemeen?

Per probleem kan je kijken of er goede libraries zijn die uitrekenen wat jij wilt weten. Snell BLAS libs zijn er voor vrijwel elke taal. Verder zijn er ook veel native libraries die bindings hebben voor veel talen. Zo kan je met JNI GSL gebruiken in Java.

Het is ook niet ongebruikelijk om de 'inner loop' van je simulatie te implementeren in een 'snelle' taal, en het spul er omheen zoals configuratie, user interface, resultaten verwerken enzo, door een taal waarin het wat sneller ontwikkelen is. Python heeft bijvoorbeeld wat aardige methoden om native C code te gebruiken in een script.

Mogelijkheden genoeg, maar lastig om te bepalen wat voor jou het handigste is zonder een specifieke probleembeschrijving :)

Acties:
  • 0 Henk 'm!

  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

Ik weet niet hoe het met C# zit, maar Java is tegenwoordig retesnel. Zo snel zelfs dat in de core steeds minder native calls meer gedaan worden, behalve voor hele specifieke zaken.

Garbage collection betekent niet dat een taal traag is. Op veel vlakken performt Java (omdat de JVM @runtime kan profilen en optimaliseren) zelfs beter dan oldskool C++.

Het grootste probleem van een garbage collector is als je real time bezig bent, want een GC run kan wel voor een hapering zorgen. Maar goed, als je GC-friendly programmeert valt dat ook mee... (makkelijker gezegd dan gedaan btw)

Fat Pizza's pizza, they are big and they are cheezy


Acties:
  • 0 Henk 'm!

  • Data-base
  • Registratie: Maart 2007
  • Laatst online: 07-09 10:33
JKVA schreef op donderdag 06 november 2008 @ 18:22:
Ik weet niet hoe het met C# zit, maar Java is tegenwoordig retesnel. Zo snel zelfs dat in de core steeds minder native calls meer gedaan worden, behalve voor hele specifieke zaken.

Garbage collection betekent niet dat een taal traag is. Op veel vlakken performt Java (omdat de JVM @runtime kan profilen en optimaliseren) zelfs beter dan oldskool C++.

Het grootste probleem van een garbage collector is als je real time bezig bent, want een GC run kan wel voor een hapering zorgen. Maar goed, als je GC-friendly programmeert valt dat ook mee... (makkelijker gezegd dan gedaan btw)
Ik ben het met je eens dat GC niet betekent dat een taal traag is, maar het zorg voor overhead en is dus zeker niet sneller dan zonder gc. Tuurlijk, als je voor iedere byte dat je nodig hebt een malloc doet in c, zal dat langzamer zijn dan new-en en gc'en in een managed taal, maar als je een beetje engineer hebt die verstand heeft van zaken, dan blijft een native taal sneller. Ook al zijn de verschillen minimaal. Maar ik geloof niet dat java sneller is dan c. En als ik me niet vergis wordt java niet eens jit gecompiled naar native, dan kan je t helemaal schudden tegen native code.

Echter, dit betreft alleen fysieke performance, vanuit een reeel punt gezien is een managed taal over het algemeen "beter" inzetbaar door een kortere ontwikkeltraject (en wellicht betere onderhoudbaarheid). Ook hier weer geldt dat het grotendeels aan je engineer ligt.

En wat versta jij onder GC-friendly programmeren? Gewoon de GC zn werk laten doen en vooral geen aanroepen doen naar je GC?


@ontopic
Zoals gezegd denk ik dat het verschil in performance tussen een JIT-compilde taal en native taal klein is. Enige wat verschil maakt is runtime safety van je VM, dat is dus bounds checken etc. En gezien meer dan de helft van alle C programma's flinke security problemen heeft (overflows), denk ik dat de voordelen van een managed taal ruimschoots opwegen tegen de performance, zelfs bij HPC. (Er zijn natuurlijk wel uitzonderingen, maar goed...)

Acties:
  • 0 Henk 'm!

  • djc
  • Registratie: December 2001
  • Laatst online: 08-09 23:18

djc

Data-base schreef op donderdag 06 november 2008 @ 20:44:
maar het zorg voor overhead en is dus zeker niet sneller dan zonder gc. Tuurlijk, als je voor iedere byte dat je nodig hebt een malloc doet in c, zal dat langzamer zijn dan new-en en gc'en in een managed taal, maar als je een beetje engineer hebt die verstand heeft van zaken, dan blijft een native taal sneller. Ook al zijn de verschillen minimaal. Maar ik geloof niet dat java sneller is dan c. En als ik me niet vergis wordt java niet eens jit gecompiled naar native, dan kan je t helemaal schudden tegen native code.
Fundamenteel is het best wel mogelijk dat een goede JIT-compiling interpreter sneller is dan een puur gecompileerde taal, juist omdat de JIT compiler beschikt over veel meer informatie (behalve misschien als je een goede PGO compiler hebt). Volgens mij klopt het wel dat Java in sommige gevallen sneller is dan C. De laatste versies van de JVM bevatten wel degelijk een JIT compiler.

Rustacean


Acties:
  • 0 Henk 'm!

  • Data-base
  • Registratie: Maart 2007
  • Laatst online: 07-09 10:33
djc schreef op vrijdag 07 november 2008 @ 11:57:
[...]
Fundamenteel is het best wel mogelijk dat een goede JIT-compiling interpreter sneller is dan een puur gecompileerde taal, juist omdat de JIT compiler beschikt over veel meer informatie (behalve misschien als je een goede PGO compiler hebt). Volgens mij klopt het wel dat Java in sommige gevallen sneller is dan C. De laatste versies van de JVM bevatten wel degelijk een JIT compiler.
Ik blijf er sceptisch over! Heb je hier referenties voor? Ik kan me namelijk niet voorstellen dat java sneller is dan c, mits de programma's gelijk zijn en je ze allebei build onder gelijke omstandigheden. Bij iedere memory access meot je VM bounds en overflows checken!!
Tuurlijk er zijn misschien heir en daar wat gevallen dat java sneller is onder bepaalde omstandigheden, maar ik denk niet dat een managed taal ooit sneller kan worden dan een native gecompilde taal, puur door het overhead van managen. En dat zal niet opwegen tegen het voordeel wat een jit-compiler heeft aangezien het probleem van "kijken wat code doet zonder het uit te voeren" onbeslisbaar is.

Acties:
  • 0 Henk 'm!

  • RayNbow
  • Registratie: Maart 2003
  • Laatst online: 20:59

RayNbow

Kirika <3

Data-base schreef op vrijdag 07 november 2008 @ 12:20:
Ik kan me namelijk niet voorstellen dat java sneller is dan c
[...]
Let’s make one thing clear, here: performance benchmarking actual languages is not possible. Languages themselves are little more than a grammar and some rules for various things all nicely wrapped up in a thick document that comprises the standard for that language. They don’t have an intrinsic speed, except in the form of possible complexity and efficiency guarantees for algorithms in the language’s standard library. When people (including myself) discuss the relative performance of languages, the topic at hand is really particular implementations of those languages being applied to particular solutions to particular problems within a particular context. In most cases this distinction is implicitly understood by all parties involved, but it’s worth mentioning here because, well, you never know.
[...]
? :+

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


Acties:
  • 0 Henk 'm!

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ten eerste, laten we vooropstellen dat JIT compilatie geen eigenschap is van de taal. Java kan ook naar native gecompileerd worden, en C++ kan ook in een jitter draaien. Maar laten we for the sake of argument even aannemen dat java gejit wordt en C++ niet.
Data-base schreef op vrijdag 07 november 2008 @ 12:20:

Ik blijf er sceptisch over! Heb je hier referenties voor? Ik kan me namelijk niet voorstellen dat java sneller is dan c, mits de programma's gelijk zijn en je ze allebei build onder gelijke omstandigheden. Bij iedere memory access meot je VM bounds en overflows checken!!
Niet bij iedere memory access. En ook niet bij iedere array access. Als je bijvoorbeeld een lokaal gedefinieerde array hebt en je loopt daar met een lusje van 0 tot array.length doorheen dan is het al vrij gemakkelijk te bewijzen dat je code nooit een out of bounds access gaat doen waardoor de check overbodig is (en vziw doen moderne java jitters dit ook). Daarnaast is een taal als java iets makkelijker te optimizen omdat de featureset een stuk gelimiteerder is dan een taal als C++ (zoals bv. geen ruwe pointers naar random memory), waardoor de semantiek voor de compiler op een hoger niveau bekend is. Een naief geïmplementeerde java applicatie kan dus sneller zijn dan een naïef geïmplementeerde C++ applicatie.

That said, op het moment dat je als programmeur weet waar je mee bezig bent en je gaat ervoor om het maximale eruit te halen, en je richt je ook nog eens op 1 specifiek platform, dan haal je er met C++ echt wel meer uit dan met Java, en dat zit 'm voornamelijk in het verschil in taalfeatures (om maar even keihard tegen de post van de inmiddels hierboven geposte post van RayNbow in te gaan ;)) (zoals bv. dat Java idd vereist dat bounds gecontroleerd dienen te worden, of dat je er in Java niet specifiek ervoor kunt kiezen om een object op de stack of op de heap aan te maken, etc). .Net komt hier de native talen wel iets meer tegemoet met oa het concept value types en het toelaten van unsafe code.

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!

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

Niet helemaal mee eens, zoals uit m'n post hierboven ook wel blijkt. Je kunt weldegelijk talen vergelijken. Een taal is meer dan een set grammatica-regels. Een java-achtige taal waarin een out of bounds array access geen ArrayOutOfBoundsException oplevert is geen java. En als je je sec concentreert op de specs dan kun je stellen dat Java bepaalde handmatige optimalisaties in de weg staat. In Java mag je heel veel dingen niet doen die in C++ wel mogen (maar volgens de spec "undefined behaviour" opleveren, waardoor een implementatie vrij is om te doen wat hij wilt, wat meestal resulteert in geen enkele controle, maar if it blows up it's your own fault)

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!

  • RayNbow
  • Registratie: Maart 2003
  • Laatst online: 20:59

RayNbow

Kirika <3

.oisyn schreef op vrijdag 07 november 2008 @ 13:01:
That said, op het moment dat je als programmeur weet waar je mee bezig bent en je gaat ervoor om het maximale eruit te halen, en je richt je ook nog eens op 1 specifiek platform, dan haal je er met C++ echt wel meer uit dan met Java, en dat zit 'm voornamelijk in het verschil in taalfeatures [...] of dat je er in Java niet specifiek ervoor kunt kiezen om een object op de stack of op de heap aan te maken, etc). [...]
Klopt. :) In C++ heb je meer mogelijkheden om de compiler een handje te helpen met het produceren van bloedsnelle code. In Java kan dat niet en moet de JITter harder werken (en moet je dus hopen dat ie dat ook doet/kan).

Edit:
Hey, niet stiekem dubbelposten, he! :+

[ Voor 3% gewijzigd door RayNbow op 07-11-2008 13:14 ]

Ipsa Scientia Potestas Est
NNID: ShinNoNoir


Acties:
  • 0 Henk 'm!

  • Knorrend_varken
  • Registratie: Juni 2000
  • Laatst online: 21:04
In wat voor taal is de/een JVM zelf geschreven? Wordt dat nu ook zoveel mogelijk in Java gedaan?

Acties:
  • 0 Henk 'm!

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

Zodat de VM in een VM draait? :D
Het werkt natuurlijk niet net zoals bij compilers dat je een compiler in z'n eigen taal kunt schrijven. Een compiler produceert een bepaalde output adhv een bepaalde input, en dat kun je in elke taal wel implementeren. Een VM is echter iets wat andere applicaties host, dus als je een VM schrijft in een taal die zo'n VM nodig heeft dan wordt het natuurlijk wat lastig (want waar is de onderliggende VM dan weer in geschreven?).

(Je kunt natuurlijk wel Java naar native machinecode compilen, dan zou het wel kunnen. Maar vziw is dat niet het geval bij de java vm. Daarnaast zit je nog met een hoop OS-specifieke zaken die voor een VM nodig zijn waar je in Java geen toegang toe hebt)

[ Voor 71% gewijzigd door .oisyn op 07-11-2008 14:36 ]

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!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
Snelle HPC code en toch OO gebruiken ? Kijk eens op http://oonumerics.org.

De beste trade-off hier is uiteindelijk C++. Het is numerieker zelfs sneller dan FORTRAN, zie libraries als Blitz++. Aan de andere kant heb je alle standaard OO features: classes, inheritance, polymorfisme, private class members, etc. Een VM is optioneel (zie C++/CLI onder .NET) maar ongebruikelijk, net zoals Garbage Collection (zie Boehm's collector).

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Acties:
  • 0 Henk 'm!

  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

Als je programmeurs hebt die perfecte code schrijven is C++ natuurlijk sneller. Helaas leven we in een wereld waarin om verschillende redenen niet-optimale code geschreven wordt. Soms met opzet, bijvoorbeeld om code simpeler en beter onderhoudbaar te houden, soms omdat de programmeur simpelweg niet weet hoe je snelle code schrijft, of omdat je wel capabele programmeurs hebt, maar die toevallig iets over het hoofd zien (is niet eens zo heel vreemd, gezien de complexiteit van hedendaagse software).

Een managed taal is dan veel vergevingsgezinder. Jij schrijft bijv. een stuk synchronized code en de JIT kan bewijzen dat dit zinloos is, dan haalt hij die gewoon weg. Jij roept (omdat je een OO purist bent) alle properties aan via een getter, dan wordt die call geïnlined.

En dit kan meerdere keren gebeuren in de lifecycle van een applicatie, wanneer de JIT daar zin in heeft.

Dat is meteen ook de reden dat micro benchmarks in Java zinloos zijn. Er gebeurt teveel onder de motorkap om een conclusie te kunnen trekken.

Vergelijk het maar met een projectleider. In principe overhead, maar een goede projectleider zorgt er wel voor dat je als team goed samenwerkt. Een slechte projectleider (Java 1 t/m 1.3) is alleen overhead.

Ps. Met garbage collector friendly programming bedoel ik het programmeren, op een manier dat de GC minder vaak nodig is en/of minder werk heeft bij een run. Lekkere bullshit bingo, maar ik bedoel gewoon de standaard dingen, dus opletten voor loitering objects, geen finalizers gebruiken, etc.

Fat Pizza's pizza, they are big and they are cheezy


Acties:
  • 0 Henk 'm!

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

JKVA schreef op vrijdag 07 november 2008 @ 16:50:
Jij roept (omdat je een OO purist bent) alle properties aan via een getter, dan wordt die call geïnlined.
En dat gebeurt niet in een taal als C++ omdat...?

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!

  • JKVA
  • Registratie: Januari 2004
  • Niet online

JKVA

Design-by-buzzword fanatic

.oisyn schreef op vrijdag 07 november 2008 @ 16:55:
[...]

En dat gebeurt niet in een taal als C++ omdat...?
C++ zal ook vast wel optimaliseren. Zelfs meer dan de Java compiler. Maar een JIT kan op basis van runtime gegevens nog verder optimaliseren.

Weet niet wat er verder nog te optimaliseren valt aan een platgeslagen method call, maar goed...

Het was maar een voorbeeld. Het ging me om het feit dat je @runtime zaken weet die je tijdens compilatie niet wist en daardoor kunt bijsturen als platform.

Fat Pizza's pizza, they are big and they are cheezy


Acties:
  • 0 Henk 'm!

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

En daarom heb je zaken als PGO in native talen :)

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!

  • oeLangOetan
  • Registratie: Maart 2002
  • Laatst online: 06-08 17:19
.oisyn schreef op zaterdag 08 november 2008 @ 14:27:
En daarom heb je zaken als PGO in native talen :)
Ja maar dat profiel is nog steeds statisch waardoor de prestaties afhankelijk zijn van de invoergegevens waarmee het profiel werd gebouwd. De JVM optimaliseert voor het "echte" profiel en dat profiel kan zelf dynamisch aangepast worden.
In volgende versies zal de JVM zelf speculatieve compilatie gebruiken om nog verder te optimaliseren. Soms is het erg moeilijk voor een compiler om te weten welke optimalisatie nu echte voordelen bied, in dat geval zal de JVM beide oplossingen uitproberen & evalueren, degelijke optimalisatie is nooit mogelijk met native compilers.

Acties:
  • 0 Henk 'm!

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

Waarbij bij dat argument voor het gemak altijd maar weer even wordt vergeten dat optimizen op dynamische data ook niet statisch kan en dús van de runtime tijd afgaat (zowel het optimaliseren zelf als het vergaren van de statistieken). Bovendien is het een argument dat al jaren gebruikt wordt, maar waar ik nog nooit resultaat van heb gezien, met uitzondering van wat halfbakken naïef geïmplementeerde voorbeeldjes.

[ Voor 42% gewijzigd door .oisyn op 08-11-2008 22:34 ]

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!

  • oeLangOetan
  • Registratie: Maart 2002
  • Laatst online: 06-08 17:19
.oisyn schreef op zaterdag 08 november 2008 @ 22:30:
Waarbij bij dat argument voor het gemak altijd maar weer even wordt vergeten dat optimizen op dynamische data ook niet statisch kan en dús van de runtime tijd afgaat.
Inderdaad, maar dat valt redelijk goed mee eens de VM "opgewarmd" is. Vooral bij in-order processoren kunnen instructie scheduling problemen op deze manier beter opgelost worden.

Over het algemeen zal door JIT compilatie de applicatie trager zijn maar het verschil is klein genoeg om C en C++ links te laten liggen voor 95% van alle applicaties en het verschil zal in de toekomst nog kleiner worden. (Games zitten in die 5% ;) maar dat is vooral door problemen met native calls naar de GPU & een gebrekkige ondersteuning van SIMD instructies (met uitzondering van mono 2.2 die dergelijke primitieven nu ondersteund))

Java wordt in de HTC wereld gebruikt maar het is niet duidelijk hoeveel het gebruikt wordt. Imho, het verschil tussen het gebruik van native code tov JIT is over het algemeen een constante factor hetgeen eenvoudig opgelost kan worden door het serverpark groter te maken. Het is een afweging tussen het aantal extra manuren dat een ingenieur aan het probleem zal werken als het in c++ geschreven wordt tov. de kost van een server.
Paper: Current State of Java for HPC Het verschil is in deze paper in ieder geval erg klein.

Acties:
  • 0 Henk 'm!

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

.oisyn

Moderator Devschuur®

Demotivational Speaker

oeLangOetan schreef op zaterdag 08 november 2008 @ 23:19:
Over het algemeen zal door JIT compilatie de applicatie trager zijn
Nee, niet door JIT compilatie. Er is niets mis met JIT compilatie an sich. Het probleem is de restricties die Java heeft, wat ik in deze post al aangaf :). In diezelfde post lees je trouwens ook dat ik vind dat het gebruik van een taal als java weldegelijk voordelen heeft (op het gebied van performance bij de "normale" applicaties), waardoor je in feite punten die ik zelf al genoemd heb aan het herhalen ben ter verdediging van je eigen opmerking :P. Ik ben het dan ook helemaal met je eens. Alleen deze subdiscussie ontstond omdat JKVA het had over het inlinen van getters.

Overigens, om even een heel ander punt aan te halen, de reden dat Java desktop applicaties vaak traag aanvoelen is helaas door overabstractie in bepaalde frameworks en in de applicaties zelf. Een gemiddelde Javist is denk ik ook puristischer op OO gebied dan een gemiddelde C++'er. Generiekere code leidt tot een afname van aannames die je kunt maken en daardoor in inefficientere code dat moeilijker geoptimaliseerd kan worden. Heeft natuurlijk niets met de taal / het platform Java zelf te maken.

[ Voor 34% gewijzigd door .oisyn op 08-11-2008 23:45 ]

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.

Pagina: 1