Schneller durch JIT?



  • hustbaer schrieb:

    Zeus schrieb:

    hustbaer schrieb:

    .NET kann soweit ich weiss sowieso (noch) nicht reJITen. *

    *: Bzw. wenn es geht, dann ist es brandneu.

    ReJit ist ab .NET 4.5 drin.
    Quelle: https://blogs.msdn.microsoft.com/davbr/2011/10/12/rejit-a-how-to-guide/

    Boah, da war ich mal wieder ein paar Jahre hinten 😃 Danke.

    ps: Da ist dauernd von Profiler die Rede. Macht die Runtime das auch von selbst zum Zwecke der Optimierung, oder nur per Request wenn ein Profiler im IL Code rumgefummelt hat?

    -.- nur im Profiler Modus, der Rejiter hat zuviele bekannte Problem!

    // #Known issues with REJIT at this time:
    //   NGEN inlined methods will not be properly rejitted
    //   Exception callstacks through rejitted code do not produce correct StackTraces
    //   Live debugging is not supported when rejit is enabled
    //   Rejit leaks rejitted methods, RejitInfos, and SharedRejitInfos until AppDomain unload
    //   Dump debugging doesn't correctly locate RejitInfos that are keyed by MethodDesc
    //   Metadata update creates large memory increase switching to RW (not specifically a rejit issue)
    


  • Na gut, dann bin ich beruhigt. Hab's zwar nicht dazugeschrieben, aber ich dachte schon an praktikables reJITen zur Laufzeit zwecks Optimierung unter "production" Bedingungen. Und da meine ich mich zu erinnern dass auch das bald kommen soll. Hoffentlich 🙂



  • Sehr interessant mit C#. Wen es interessiert das nennt sich dann .NET_Native und für Windows10 Apps soll das wohl schon gehen und soll die Anwendungen bis zu 60% schneller laufen lassen.



  • Mechanics schrieb:

    Artchi schrieb:

    Hier muss man den Overhead der prominenten JIT-Sprachen mit einbeziehen. Z.B. haben Smalltalk, C# und Java sehr viel Objekt-Informationen für Reflection.

    Du vergisst beim Overhead z.B., dass man in Java beim Speicherzugriff immer doppelte Indirektion und schlecht cache locality hat. Allein das kann schon einiges kosten und verbaut grundsätzlich Optimierungsmöglichkeiten.

    Ich kann mir nicht wirklich vorstellen, dass doppelte Indirektion auf modernen x86_64-Maschinen allzu sehr ins Gewicht fällt. Der Standard-Addressierungsmodus im Protected Mode hat da sowieso schon 4-Fache Indirektion auf den "Richtigen" RAM, in einer Virtuellen Maschine mit Nested Paging sogar 6-Fache, und theoretisch kann man beliebigfache haben, siehe https://www.reddit.com/r/programming/comments/18zvoh/x86_mmu_fault_handling_is_turing_complete/ (wenn dieses dumme Forum die URL nicht wieder scrambled).

    Ansonsten: Sobald man eine Runtime bereitstellt geht es immer darum, Rechenleistung gegen Gedankenarbeit einzutauschen. Bereits ein Assembler tauscht gewisse Optimierungsmöglichkeiten (zugegeben, sehr krude) gegen einen menschenlesbaren Befehlssatz ein, ein Compiler tauscht ein genau angepasstes Code-Layout ein gegen einfachere Lesbarkeit und Portabilität, C tauscht ein klares einfaches Memory-Layout aus gegen die Möglichkeit, mittels Zeigern in Objekten statt Zahlen zu denken. Google "Abstraction Optimization Tradeoff". Wenn man nicht gerade auf embedded devices arbeitet, sondern auf einem modernen Rechner, der genug RAM hat, dann will man einfach auf bestimmte Sprachfeatures (zum Beispiel Array-Bounds-Checking) nicht verzichten.

    Die JVM ist auch deutlich besser als ihr Ruf. Der schlechte Ruf der JVM kommt daher, dass SUN Java ursprünglich für RISC-Architekturen wie PPC und SPARC entwickelt hat. Die hatten unter Anderem viel mehr Register, im Gegensatz zu alten x86-processoren, außerdem hatten sie einen schlanken Befehlssatz, sodass der Unterschied zum Bytecode nicht so groß war.

    Aber man sollte sich hier nichts vormachen: Moderne x86_64-Processoren haben effektiv selbst bereits eine virtuelle Maschine (cf Microcode), so von wegen "on the metal". Und es gibt sogar Processoren, die Java Bytecode direkt unterstützen.



  • [quote="Ramelucke"]Ich kann mir nicht wirklich vorstellen, dass doppelte Indirektion auf modernen x86_64-Maschinen allzu sehr ins Gewicht fällt.quote]

    Ist ja schon geklärt, ich war nicht up to date. Ist schon lang umgebaut worden, grade weil das sehr teuer war.

    Ramelucke schrieb:

    sondern auf einem modernen Rechner, der genug RAM hat, dann will man einfach auf bestimmte Sprachfeatures (zum Beispiel Array-Bounds-Checking) nicht verzichten.

    Hä? "Array Bound Checking" ist völlig nutzlos, das will ich ganz sicher nicht haben. Ich hatte noch nie Probleme damit, und ich habe auch noch nie erlebt, dass da irgendjemand Probleme damit gehabt hätte. Das sind absolut triviale Probleme, da will ich nicht ständig Overhead für nichts haben. Und abfangen kann Array Bound Checking auch nicht wirklich was, dann fliegt halt auch nur eine saubere Exception statt UB, kaputt ist dein Programm trotzdem und du musst es richtig schreiben. Und wenn das erstmal richtig ist, bringt dir das "Feature" wieder absolut gar nichts.



  • Mechanics schrieb:

    Hä? "Array Bound Checking" ist völlig nutzlos, das will ich ganz sicher nicht haben. Ich hatte noch nie Probleme damit, und ich habe auch noch nie erlebt, dass da irgendjemand Probleme damit gehabt hätte. Das sind absolut triviale Probleme, da will ich nicht ständig Overhead für nichts haben. Und abfangen kann Array Bound Checking auch nicht wirklich was, dann fliegt halt auch nur eine saubere Exception statt UB, kaputt ist dein Programm trotzdem und du musst es richtig schreiben. Und wenn das erstmal richtig ist, bringt dir das "Feature" wieder absolut gar nichts.

    Waren nicht Pufferüberläufe immernoch eine der häufigsten Ursachen für Sicherheitslücken, erst so langsam eingeholt durch Rassenkonditionen?

    Aber egal, das ist off-topic. Man will halt gerne Late Binding haben, das wird durch JIT halt wirklich schneller, weil man zum Beispiel nachträglich funktionen inlinen kann. Man will Garbage Collection, die wird leichter wenn man Object Introspection hat, und die wird leichter, wenn man genau weiß was wann wo welches Objekt wie aufruft, und das kann man besser optimieren, wenn man JIT benutzt. Generell möchte man sich eigentlich möglichst wenig um den Stack kümmern müssen, und um die Eigenheiten des Systems, und man möchte möglichst leicht Shims injecten können um APIs nachträglich kompatibel nachzubessern; also zumindest sind das doch immer so Standardgründe die Leute angeben, Java statt C++ zu benutzen, wird also wohl was dran sein. You get the idea.

    Das Meiste davon kriegt man im Prinzip auch statisch hin, macht halt nur keiner, ist vmtl auch schwieriger, hat man ja an so Experimenten wie XPCOM gesehen. Und ein hochoptimiertes C-Programm wird sicherlich die meisten JITs schlagen, aber das zu schreiben und stabil hinzubekommen kostet halt einfach mehr, als man für ein paar mehr Server in seinem Rack ausgeben müsste.

    Was man nicht statisch hinkriegt sind so sachen wie Java RMI, die aber meines Wissens inzwischen extrem unpopulär sind, obwohl die Grundidee von RMI, also einen Algorithmus auf viele Knoden in einem heterogenen Netzwerk transparent zu verteilen, ja eigentlich genial ist.



  • @Mechanics
    Bounds-Violations sind ja bloss eine der schlimmsten und grössten Quellen von Exploits überhaupt. Dass das nicht mehr ganz so schlimm ist wie vor 10-15 Jahren liegt hauptsächlich daran dass aktuelle Compiler und Betriebssystem einiges unternehmen um Exploits durch unchecked Buffer zu erschweren bzw. verhindern.



  • Ramelucke schrieb:

    Man will Garbage Collection

    Wer ist man? GC hat ziemlich viel verdorben. Also mir sind Destruktoren und RAII lieber.



  • hustbaer schrieb:

    @Mechanics
    Bounds-Violations sind ja bloss eine der schlimmsten und grössten Quellen von Exploits überhaupt. Dass das nicht mehr ganz so schlimm ist wie vor 10-15 Jahren liegt hauptsächlich daran dass aktuelle Compiler und Betriebssystem einiges unternehmen um Exploits durch unchecked Buffer zu erschweren bzw. verhindern.

    Das ist richtig. Nur würde ich nicht gerade behaupten, dass zusätzliche Prüfungen zur Laufzeit durch die Runtime etwas wären, worauf ich nicht mehr verzichten mag. Ist ja nicht so, dass ich hunderte neue out of bounds Bugs pro Tag produzieren würde, die ich ohne die Runtime Unterstützung nicht im Griff hätte.



  • Du hast "völlig nutzlos" geschreiben.



  • JIT auf Java kann viel bringen, weil die umgebung ziemlich abgekapsel und restriktiv definiert ist, dadurch hast du einen allwissenden compiler. Wenn du neue module reinlaedst, musst das natuerlich neu gemacht werden.
    JIT optimieren eher selten waehrend der laufzeit, weil dadurch die wertvollen CPU-resourcen verbrannt werden wuerden, es ist eher iterativ, bei jedem start kann der JIT die evaluierungen vom letzten lauf nehmen und neu generien. (Es gibt natuerlich manchmal hintergrundscompilierung, aber das ist nicht um die letzten 10% zu holen).

    Kam das in der Praxis schon mal vor?

    Nicht gerade Java, aber ich finde der "geilste" JIT ist Project Denver von NVidia:

    Denver implements an innovative process called Dynamic Code Optimization, which optimizes frequently used software routines at runtime into dense, highly tuned microcode-equivalent routines. These are stored in a dedicated, 128MB main-memory-based optimization cache. After being read into the instruction cache, the optimized micro-ops are executed, re-fetched and executed from the instruction cache as long as needed and capacity allows.

    https://blogs.nvidia.com/blog/2014/08/11/tegra-k1-denver-64-bit-for-android/


Anmelden zum Antworten