问题标签 [microbenchmark]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
java - 循环习语的奇怪 JIT 悲观化
在分析这里最近一个问题的结果时,我遇到了一个非常奇怪的现象:显然,HotSpot 的 JIT 优化的额外层实际上会减慢我机器上的执行速度。
这是我用于测量的代码:
代码非常微妙,所以让我指出重要的部分:
- “正常索引”变体使用直接变量
i
作为数组索引。HotSpot 可以轻松确定i
整个循环的范围并消除数组边界检查; - “屏蔽索引”变体索引为
j
,实际上等于i
,但这一事实通过 AND 屏蔽操作从 HotSpot 中“隐藏”了; - “带出口点”变体引入了显式循环出口点。下面将解释这一点的重要性。
循环展开和重新排序
观察边界以两种重要方式检查数字:
- 它具有与之相关的运行时开销(比较后跟条件分支);
- 它构成了一个循环退出点,可以在任何步骤中中断循环。事实证明,这对适用的 JIT 优化产生了重要影响。
通过检查上述四种方法发出的机器代码,我注意到以下几点:
- 在所有情况下,循环都是展开的;
- 在 的情况下
normalIndex
,它被区分为唯一没有过早循环退出点的情况,所有展开步骤的操作都被重新排序,以便首先执行所有数组获取,然后将所有值异或到累加器中。
预期和实际测量结果
现在我们可以根据讨论的特征对这四种方法进行分类:
normalIndex
没有边界检查,也没有循环退出点;normalWithExitPoint
没有边界检查和 1 个退出点;maskedIndex
有 1 个边界检查和 1 个出口点;maskedWithExitPoint
有 1 个边界检查和 2 个出口点。
显而易见的期望是,上面的列表应该按性能降序排列方法;但是,这些是我的实际结果:
normalWithExitPoint
和maskedIndex
是相同的模测量误差,即使只有后者有边界检查;- 观察到的最大异常
normalIndex
应该是最快的,但明显慢于,除了多了一行代码,即引入退出点的代码之外normalWithExitPoint
,在各方面都与它相同。
由于normalIndex
是唯一对其应用了额外的重新排序“优化”的方法,因此得出的结论是,这是导致速度下降的原因。
我正在测试:
Java HotSpot(TM) 64-Bit Server VM (build 24.0-b56, mixed mode)
(Java 7 更新 40)- OS X 版本 10.9.1
- 2.66 GHz 英特尔酷睿 i7
我也成功地在 Java 8 EA b118 上重现了结果。
我的问题:
上述现象是否可以在其他类似机器上重现?从一开始提到的问题中,我已经暗示至少有些机器不会重现它,所以同一个 CPU 的另一个结果会很有趣。
更新 1:更多测量灵感来自maaartinus的发现
我收集了下表,它将执行时间与-XX:LoopUnrollLimit
命令行参数相关联。在这里,我只关注两个变体,有和没有if (entry == 0) break;
线:
可以观察到以下突然变化:
在从 14 到 15 的过渡中,该
withoutExitPoint
变体接受了有益的 LCM 1转换并显着加快了速度。由于循环展开限制,所有加载的值都适合寄存器;在 18->19 上,
withExitPoint
变体获得了加速,小于上述值;在 22->23 上,
withoutExitPoint
变体变慢了。在这一点上,我看到溢出到堆栈位置,如maaartinus的回答中所述,开始发生。
我的设置的默认loopUnrollLimit
值为 60,因此我在最后一列中展示了它的结果。
1 LCM = 本地代码运动。正是这种转换导致所有数组访问都发生在顶部,然后处理加载的值。
更新 2:这实际上是一个已知的,报告的问题
https://bugs.openjdk.java.net/browse/JDK-7101232
normalIndex
附录:机器码中的展开和重新排序的循环
java - 为什么调用函数比不调用函数快?
我尝试了以下代码:
控制台的输出是:
似乎第二个循环比第一个循环花费的时间更少!我不明白为什么会这样。谢谢你的帮助。
更新:我交换了两个循环,现在循环一个需要更少的时间!!
c++ - 在 C++ 中获得准确的执行时间(微秒)
我想在用 C++ 实现的程序的微秒内获得准确的执行时间。我试图用clock_t 获得执行时间,但它不准确。
(请注意,微基准测试很难。准确的计时器只是在短时间区域获得有意义的结果所必需的一小部分。请参阅 Idiomatic way of performance evaluation?了解一些更一般的警告)
java - Java 内存基准测试
我目前正在用 Java 开发自己的宠物项目,其中包含自定义数据结构。为了测量性能,我选择了 Google Caliper 框架,但是为了测量数据结构的内存使用情况,我应该每次使用 VisuamVm(转储堆并等待计算对象保留大小)来测量它,以获得有效的结果。我想做某种“内存基准”测试。
所以,问题是:
是否有任何类似于Caliper或JunitBenchmarks的 Java 框架允许进行测试以测量我的数据结构的内存消耗?
r - 在 R 中有效地转换为向量
谁能帮我让这个 R 代码更有效率?
我正在尝试编写一个函数,将字符串列表更改为字符串向量,或将数字列表更改为数字向量,将类型化元素列表更改为特定类型的向量。
如果它们具有以下属性,我希望能够将列表更改为特定类型的向量:
它们是同质类型的。列表中的每个元素都是“字符”或“复杂”等类型。
列表的每个元素都是长度为一的。
/li>
例如,
上面的代码工作正常,但速度很慢,我看不出有任何方法可以在不改变函数行为的情况下优化它。重要的是函数“as_atomic”的行为方式。我无法切换到我熟悉的基本函数(例如 unlist),因为我需要为坏列表抛出错误。
在我的(相当快的)机器上,基准的频率约为 40Hz,所以这个函数在我的代码中几乎总是速率限制。vapply 控制基准的频率约为 1650Hz,仍然相当慢。
有什么方法可以显着提高此操作的效率吗?任何建议表示赞赏。
如果需要任何澄清或编辑,请在下面发表评论。
编辑:
大家好,
很抱歉很晚才回复;在我可以尝试重新实施之前,我需要参加一些考试。
谢谢大家的性能提示。我使用纯 R 代码将性能从糟糕的 40hz 提高到更可接受的 600hz。
最大的加速来自使用 typeof 或 mode 而不是 is;这确实加快了紧密的内部检查循环。
不过,我可能不得不硬着头皮在 rcpp 中重写它以使其真正发挥作用。
java - Scala 中隐藏的性能成本?
我遇到了这个老问题,并用 scala 2.10.3 做了以下实验。
我重写了 Scala 版本以使用显式尾递归:
并将其与以下 Java 版本进行比较。为了与 Scala 进行公平比较,我有意识地将函数设为非静态函数:
以下是我电脑上的结果:
这是 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_51) 上的 scala 2.10.3。
我的问题是 scala 版本的隐藏成本是多少?
非常感谢。
php - 在 PHP 中创建函数会使用更多资源?
真的很简单的问题。由于纯粹的好奇,或多或少是另一个微型基准问题!
但是,在 PHP 中创建函数是否会使用更多资源(内存和/或 CPU)?
这是一个例子:
对比
这也让我想到了第二个思考!包含局部变量也会有什么影响吗?
例子:
对比
对比
microbenchmark - Filebench 错误:当我尝试将 $nfiles 设置为一个非常大的数字(大约 1000000)时,共享内存不足
当我使用 filebench 测试我的文件系统时,当我尝试将 $nfiles 设置为一个非常大的数字(大约 1000000)时,进程崩溃了。并且在官方网站的方式不工作!
这是官方网站上的解决方案
第二个警告通知 Filebench 无法增加共享内存区域的大小。您可以: * 以 root 身份运行 Filebench * 将共享内存区域大小增加到 256MB (sudo echo 268435456 > /proc/sys/kernel/randomize_va_space) 并忽略此警告
java - Java 并行流性能
在玩弄新的 Java 流时,我注意到与并行流的性能有关的一些奇怪的东西。我使用了一个简单的程序,它从文本文件中读取单词并计算长度大于 5 的单词(测试文件有 30000 个单词):
这会在我的机器上生成以下输出(我只提到第一次和最后 5 次循环迭代):
为什么第一个处理比其他处理慢 100 倍?为什么并行流在第一次迭代中比顺序流慢,但在最后一次迭代中快两倍?为什么顺序流和并行流都会随着时间的推移变得更快?这与循环优化有关吗?
稍后编辑:在 Luigi 的建议下,我使用JUnitBenchmarks实现了基准测试:
我还将测试文件中的字数增加到 300000。新的结果是:
Benchmark.sequentialTest:[测量 105 轮中的 100 轮,线程:1(顺序)]
round:0.08 [+- 0.04],round.block:0.00 [+- 0.00],round.gc:0.00 [+- 0.00],GC.calls:62,GC.time:1.53,time.total:8.65,时间.warmup:0.81,time.bench:7.85
Benchmark.parallelTest:[测量 105 轮中的 100 轮,线程:1(顺序)]
round:0.06 [+- 0.02],round.block:0.00 [+- 0.00],round.gc:0.00 [+- 0.00],GC.calls:32,GC.time:0.79,time.total:6.82,时间.warmup:0.39,time.bench:6.43
所以看起来最初的结果是由错误的微基准配置引起的......
scala - 如何将 JMH 与 sbt 一起用于 Scala 基准测试?
我曾尝试将jmh与sbt一起使用,但到目前为止,我还没有设法正确设置它,以便基于 .scala 的基准测试工作。
由于基于 sbt + .java 的组合基准测试有效,我尝试从该基础开始。我正在使用 sbt 0.13.1。
使用 sbt 的基于 .java 的基准测试
构建.sbt
最后要获得一个“胖”罐子,需要sbt-assembly插件:
项目/程序集.sbt
一个简单的基准:
src/main/java/app/benchmark/java/benchmark2/Benchmark2.java
运行sbt assembly
给出以下输出:
$ sbt assembly
[...]
[info] 将 2 个 Scala 源和 2 个 Java 源编译为 ...
[warn] 警告:来自注释处理器 'org.openjdk.jmh.generators.GenerateMicroBenchmarkProcessor' 的支持的源版本 'RELEASE_6' 小于-source '1.8'
[warn] 1 warning
[info] 包括:jmh-java-benchmark-archetype-0.5.5.jar
[info] 包括:jmh-generator-bytecode-0.5.5.jar
[info] 包括:jopt -simple-4.6.jar
[info] 包括:jmh-generator-reflection-0.5.5.jar
[info] 包括:jmh-generator-annprocess-0.5.5.jar
[info] 包括:asm-4.2.jar
[info ] 包括:commons-math3-3.2.jar
[信息] 包括:jmh-core-0.5.5.jar
[info] 包括:scala-library.jar
[...]
[info] 打包 /home/scala-2.10/vc/rhaag/scala/scala-benchmark/target/scala-2.10/microbenchmarks.jar ...
结果microbenchmarks.jar
包含运行基准测试所需的一切:
到目前为止,一切都很好。
使用 sbt 进行 Scala 基准测试
从那个基础我尝试切换到基于 .scala 的基准测试:
构建.sbt
用 Scala 替换 Java 原型
不起作用,因为下载失败。
这有效:
另一个简单的基准:
src/main/scala/app/benchmark/scala/benchmark2/Benchmark2.scala
现在sbt assembly
创建 jar 文件,但target/scala-2.10/microbenchmarks.jar#META-INF/MicroBenchmarks
没有列出 Scala 基准,并且这些也没有显示java -jar target/scala-2.10/microbenchmarks.jar -l
。
资源:
如何为 Scala 集成(基于字节码的)JMH 处理器?或者从另一个角度来看:为什么(基于注释的)JMH 处理器会自动启动并生成基于 Java 的基准测试?