我继续在我的编译器类的C#编译器上工作.目前我已经完成了教科书中关于编译器优化的章节.
在大多数情况下,我的教科书在编写时没有考虑到及时编译,我对C#编译器执行的静态,预jit优化的种类与JIT过程中的执行情况感到好奇?
当我与人们谈论有关CLR的编译时,我通常会听到类似的事情,"大多数优化都是由JIT完成的".
是循环展开,常量折叠/传播,C#编译器在Jit之前完成指令交织还是由抖动处理?如果它们不是由抖动处理的,那么抖动对于即时编译器所做的那种优化是什么?
到目前为止,大多数主流浏览器已经开始将优化JIT编译器集成到他们的JavaScript解释器/虚拟机中.这对每个人都有好处.现在,我很难确切地知道他们确实执行了哪些优化以及如何最好地利用它们.每个主要JavaScript引擎的优化参考是什么?
背景:
我正在研究一种从更高级别和更安全的语言生成JavaScript的编译器(无耻的插件:它叫做OPA,而且非常酷),考虑到我正在生成的应用程序的大小,我想要我的JavaScript代码尽可能快和内存效率.我可以处理高级优化,但我需要了解更多关于执行哪些运行时转换的信息,以便了解哪些低级代码将产生最佳结果.
一个例子,从我的脑海中开始:我正在编写的语言将很快整合对懒惰的支持.JIT引擎在惰性函数定义中表现良好吗?
我理解为什么解释开销很昂贵,但为什么JITted Python实现(Psyco和PyPy)仍然比C#和Java等其他JITted语言慢得多?
编辑:我也明白一切都是对象,动态类型代价高昂等等.但是,对于可以推断出类型的函数,我不确定为什么这很重要.
是否有CLR编译器/ JIT执行的转义分析?例如,在Java中,似乎循环变量是在循环中分配的不会转义循环的对象在堆栈而不是堆上分配(请参阅Java中的Escape分析).
为了澄清,在下面的示例中,编译器会优化掉堆分配,foo因为它永远不会从循环中逃脱.
class Foo
{
int number;
Foo(int number) { this.number = number; }
public override string ToString() { return number.ToString(); }
}
for (int i = 0; i < 10000000; i++)
{
Foo foo = new Foo(i);
Console.WriteLine(foo.ToString());
}
Run Code Online (Sandbox Code Playgroud) 我正在尝试优化我的应用程序,以便它在启动后立即运行良好.目前,它的发行版包含304个二进制文件(包括外部依赖项),总计57兆字节.它是一个主要进行数据库访问的WPF应用程序,没有任何重要的计算.
我发现Debug配置为大多数操作提供了更好的(~5倍增益)时间,因为它们是在应用程序进程的生命周期中第一次执行.例如,在应用程序中打开特定屏幕,NGENed Debug需要0.3秒,JITted Debug需要0.5秒,NGENed Release需要1.5秒,JITted Release需要2.5秒.
我知道JIT编译时间的差距是由JIT编译器对Release二进制文件应用更积极的优化引起的.从我可以告诉,调试和发布配置由不同/p:DebugType并/p:Optimize传递给C#编译器开关,但我看到,即使我建立与应用程序相同的性能差距/p:Configuration=Release /p:DebugType=full /p:Optimize=false-也就是说,相同的图像调试选项中/p:Configuration=Debug.
我确认通过查看DebuggableAttribute应用于生成的程序集来应用选项.观察NGEN输出,我看到<debug>添加到正在编译的一些程序集的名称 - NGEN如何区分调试和非调试程序集?正在测试的操作使用动态代码生成 - 动态代码应用了什么级别的优化?
注意:由于外部依赖性,我使用的是32位框架.我应该期待x64有不同的结果吗?
注意:我也不使用条件编译.因此,两种配置的编译源都是相同的.
我们最近有一种情况,我们的一个生产JVM会随机冻结.Java进程正在烧毁CPU,但所有可见活动都将停止:没有日志输出,没有写入GC日志,没有响应任何网络请求等.进程将保持此状态直到重新启动.
原来,该org.mozilla.javascript.DToA类,某些输入调用时,会感到困惑,并呼吁BigInteger.pow着巨大的值(例如5 ^ 2147483647),这会触发JVM冻结.我的猜测是,一些大循环,可能是在java.math.BigInteger.multiplyToLen中,在循环中没有安全点检查的情况下进行了JIT.下次JVM需要暂停进行垃圾收集时,它会冻结,因为运行BigInteger代码的线程很长时间都不会达到安全点.
我的问题:将来,我如何诊断这样的安全点问题?杀-3没有产生任何输出; 我认为它依赖于安全点来生成准确的堆栈.是否有任何生产安全的工具可以从正在运行的JVM中提取堆栈而无需等待安全点?(在这种情况下,我真的很幸运,并设法抓住一组堆叠的痕迹BigInteger.pow被调用刚过,但在此之前它的工作它的方式到足够大的输入完全楔入JVM,没有运气中风,我我不确定我们怎么会诊断出这个问题.)
编辑:以下代码说明了问题.
// Spawn a background thread to compute an enormous number.
new Thread(){ @Override public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
}
BigInteger.valueOf(5).pow(100000000);
}}.start();
// Loop, allocating memory and periodically logging progress, so illustrate GC pause times.
byte[] b;
for (int outer = 0; ; outer++) {
long startMs = System.currentTimeMillis();
for (int inner = 0; inner < 100000; inner++) {
b = new byte[1000];
}
System.out.println("Iteration " …Run Code Online (Sandbox Code Playgroud) 这个问题与android系统有关. Dalvik VM使用JIT概念,这意味着当您第一次运行应用程序时,Dalvik VM会将其编译并加载到RAM中,只要它可以保留在那里.我理解这个概念.但是名为ART的新虚拟机使用了AOT方法.ART在安装后编译应用程序(或安装时?).这意味着什么?由编译的应用程序ART是相同的已编译的应用程序(如C的应用程序),但在从操作系统的其余部分分离的分离工艺运行?有人可以更彻底地向我解释这个概念.我必须做一些介绍,这是在那里提到的,但是我不明白这个概念,如果有人问我这个问题,我不想看起来很蠢:)抱歉因为英语不好,如果有人会很好可以编辑一下问题.
我正在使用numbas @jit装饰器在python中添加两个numpy数组.如果我使用@jit相比,性能是如此之高python.
但是,即使我传入,也没有使用所有CPU内核@numba.jit(nopython = True, parallel = True, nogil = True).
有没有办法利用numba的所有CPU内核@jit.
这是我的代码:
import time
import numpy as np
import numba
SIZE = 2147483648 * 6
a = np.full(SIZE, 1, dtype = np.int32)
b = np.full(SIZE, 1, dtype = np.int32)
c = np.ndarray(SIZE, dtype = np.int32)
@numba.jit(nopython = True, parallel = True, nogil = True)
def add(a, b, c):
for i in range(SIZE):
c[i] = a[i] + b[i]
start = …Run Code Online (Sandbox Code Playgroud) (注意:正确答案必须超越复制).
在数百万次调用之后,quicksort1肯定比quicksort2更快,除了这个额外的arg之外,它们具有相同的代码.
代码在帖子的末尾.Spoiler:我还发现jit代码比224字节更胖,即使它实际上应该更简单(如字节代码大小告诉;请参阅下面的最后更新).
即使试图用一些微基准线束(JMH)来解决这种影响,性能差异仍然存在.
我在问:为什么生成的本机代码存在这样的差异,它在做什么?
通过向方法添加参数,它使它更快......!我知道gc/jit/warmup/etc效果.您可以按原样运行代码,也可以使用更大/更小的迭代计数.实际上,你甚至应该注释掉一个然后另一个性能测试并在不同的jvm实例中运行它们,只是为了证明它不是彼此之间的干扰.
字节码没有显示出太大的区别,除了明显的getstatic为sleft/sright,还有一个奇怪的'iload 4'而不是"iload_3"(和istore 4/istore_3)
到底他妈发生了什么?iload_3/istore_3真的比iload 4/istore 4慢吗?即使添加的getstatic调用仍然没有让它变慢,那要慢得多?我猜测静态字段是未使用的,因此jit可能只是跳过它.
无论如何,我的方面没有任何歧义,因为它总是可重复的,我正在寻找解释为什么javac/jit做了他们所做的,以及为什么性能受到如此大的影响.这些是相同的递归算法,具有相同的数据,相同的内存流失等等...如果我愿意,我无法进行更加孤立的更改,以显示可重复的运行时差异.
ENV:
java version "1.8.0_161"
Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)
(also tried and reproduced on java9)
on a 4 core i5 laptop 8GB ram.
windows 10 with the meltdown/specter patch.
Run Code Online (Sandbox Code Playgroud)
使用-verbose:gc -XX:+ PrintCompilation,没有gc和jit编译在C2(第4层)中已经稳定.
n = 20000时:
main]: qs1: 1561.3336199999999 ms (res=null)
main]: qs2: 1749.748416 ms (res=null)
main]: qs1: 1422.0767509999998 ms (res=null)
main]: qs2: 1700.4858689999999 ms (res=null)
main]: qs1: …Run Code Online (Sandbox Code Playgroud) 该属性System.Runtime.CompilerServices.MethodImplAttribute可用于向JIT编译器提供有关如何处理修饰方法的提示.特别是,该选项MethodImplOptions.AggressiveInlining指示编译器在可能的情况下内联受影响的方法.不幸的是,F#编译器在生成IL时似乎只是忽略了这个属性.
示例:以下C#代码
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Inc(int x) => x + 1;
Run Code Online (Sandbox Code Playgroud)
被翻译成
.method public hidebysig static int32 Inc(int32 x) cil managed aggressiveinlining
{
.maxstack 8
IL_0000: ldarg.0
IL_0001: ldc.i4.1
IL_0002: add
IL_0003: ret
}
Run Code Online (Sandbox Code Playgroud)
请注意"aggressiveinlining"标志.
但是这个F#代码
[<MethodImpl(MethodImplOptions.AggressiveInlining)>]
let inc x = x + 1
Run Code Online (Sandbox Code Playgroud)
变
.method public static int32 inc(int32 x) cil managed
{
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldc.i4.1
IL_0003: add
IL_0004: ret
}
Run Code Online (Sandbox Code Playgroud)
没有"积极主动".我还尝试将该属性应用于适当类(type ...)的静态和非静态方法,但结果是相同的.
但是,如果我将它应用于自定义索引器,就像这样
type Dummy = …Run Code Online (Sandbox Code Playgroud) jit ×10
c# ×4
.net ×2
clr ×2
java ×2
optimization ×2
performance ×2
python ×2
ajax ×1
android ×1
bytecode ×1
cil ×1
compilation ×1
f# ×1
freeze ×1
hotspot ×1
inlining ×1
javascript ×1
jvm ×1
jvm-hotspot ×1
multicore ×1
ngen ×1
numba ×1
numpy ×1
stack-trace ×1