JVM Advent Calendar:将Kotlin性能与Graal和C2进行比较
首先,让我们谈谈测试方法:
所有 测试 都 在 我的 笔记本 上 运行i7 2.0 Ghz 16 Gb Ubuntu 18.4 和 OpenJdk 11
graal VM 选项:
- Xms6g - Xmx6g - XX:+ UseParallelOldGC - XX:+ UnlockExperimentalVMOptions - XX:+ UseJVMCICompiler
c2 VM 选项:
- Xms6g - Xmx6g - XX:+ UseParallelOldGC
我 运行 一个 测试 称为 PerformanceTest 在 每个 项目中 ,其 执行 一 结束 ,以 结束 标杆 不断。在 这种 方式 的 编译器 不能 优化 的 代码 为 一个 特定的 情况下。于是 我 选择 了 更快的 结果,假设 它 是 在 一个 没有 GC 和 OS 暂停。所有的 测试 均 运行 单- 线程。
以下是结果:
正如你所看到的,Graal使用Kotlin进行编译在小板上的速度明显更快,并且随着大板随机播放的速度稍快一点。
我怀疑这是因为随着更大的主板内存管理,它占用了大量的运行时间。在任何情况下,增量都是受欢迎的,特别是考虑到我通常在较小的板上玩。
为了测试我的理论,我创建了一个新项目,其中包含一些经典算法的实现,以查看性能的差异。你可以在这里找到它。
目前,有两种算法:Mandelbrot Set生成器和Knapsack解算器。
Mandelbrot集
该Mandelbrot集可能是你见过的最有名的分形-即使你不知道这个名字。
在数学上,它被定义为复平面中所有点的集合,其中函数z < - z ^ 2 + c在迭代时不会发散。生成Set迭代复杂平面上某些点的函数并从中创建图像非常容易。
由于这里的目标是性能而不是图形,我使用文本图形保持简单。
让我们从查看Mandelbrot Set的代码开始。
数据 类 Complex(val r:Double,val i:Double){
操作员 欢乐 时光(其他:复杂)=
复杂(
r = 这个。r * 其他。r - 这个。我 * 其他。我,
我 = 这个。我 * 其他。r + 这个。r * 其他。一世
)
操作员 乐趣 加(其他:复杂)=
复杂的(- [R = 此。[R + 等。[R ,我 = 此。我 + 其他。我)
操作员 乐趣 减去(其他:复杂)=
复杂的(- [R = 此。[R - 其他。ř,我 = 此。我 - 其他。我)
fun squared()= this * this
有趣的是 squaredModule()= r * r + i * i
有趣的 双。toComplex()= Complex(r = this,i = 0.0)
}
有趣的 mandelSet(initZ:Complex,c:Complex,maxIter:Int):Int {
var z = initZ
(1.。MAXITER)。forEach {
z = z。平方()+ c
如果(ž。squaredModule()> = 4)
归还 它
}
return maxIter
}
您可以在此处看到如何使用运算符重载和数据类来表示复数,这样可以真正简化代码并使其更易于理解。
一旦我们在Complex类中定义了对复数进行操作的规则,该 mandelSet
函数只需要检查操作z < - z ^ 2 + c是否“转义”,并且万一,经过多次迭代后,它将超过4的门槛。
在这里,您可以在AsciiArt中呈现的输出中看到Mandelbrot Set的特征心形图:
背包问题
该背包问题可以通过多种方式来定义。想象一下,作为一个刚刚闯入手表店的小偷。如果您没有超过背包中可携带的最大重量,您可以偷走任意数量的手表。
作为一个实用的小偷,你绝对想要优化你带来的手表的价值。每只手表都有价格和重量。因此,您需要找到具有给定重量的最大总价的手表组。
实际应用包括优化CNC应用的削减和材料以及分配广告预算的营销策略。
例如,让我们看一下只有三只手表的商店,定义如下:
val shop = 背包。商店(
观察(重量 = 1,价格 = 1),
观察(重量 = 3,价格 = 2),
观看(重量 = 1,价格 = 3)
)
如果我们的最大重量为1,那么我们最好选择第三只手表,而不是第一只手表,因为价值更高。
如果我们的最大权重为3,我们可以选择数字2(价格2)或数字1和3(价格1 + 3)。在这种情况下,最好选择1和3,即使它们的总重量小于最大值。
这些是这个商店的完整解决方案:
assertEquals(3,selectWatches(shop,maxWeight = 1))
assertEquals(4,selectWatches(shop,maxWeight = 2))
assertEquals(4,selectWatches(shop,maxWeight = 3))
assertEquals(5,selectWatches(shop,maxWeight = 4))
assertEquals(6,selectWatches(shop,maxWeight = 5))
如您所见,随着可用手表数量的增加,可能的选择数量变得非常非常快。这是一个经典的NP-Hard问题。
要在合理的时间内解决它,我们需要作弊并使用动态编程。我们可以使用针对每组手表的已经优化的解决方案构建地图,因此,我们可以避免每次重新计算它们。
通用算法基于基于递归的穷举搜索。这是解决它的Kotlin代码,在memoization函数和最大值的递归搜索中分开。
typealias Memoizer = MutableMap < String,Int >
有趣的 priceAddingElement(备忘录:Memoizer,shop:Set < Watch >,选择:Set < Watch >,maxWeight:Int,priceSum:Int):Int =
商店。过滤 { !(它 在 选择中)&& 它。重量 <= maxWeight }
。地图 {
selectWatches(
备忘录,
商店,
maxWeight - 它。重量,
选择 + 它,
priceSum + 它。价格)}
。过滤 { it > priceSum }
。max()?:priceSum
有趣的 selectWatches(备忘录:Memoizer,shop:Set < Watch >,maxWeight:Int,choice:Set < Watch >,priceSum:Int):Int =
memoization(memo,generateKey(choice)){
priceAddingElement(备忘录,商店,选择,maxWeight,priceSum)}
private fun memoization(memo:Memoizer,key:String,f :()- > Int):Int = when(val w = memo [ key ]){
null - > f()。还 { memo [ key ] = it }
否则 - > w
}
我真的很喜欢Kotlin如何让你清楚地表达意图,而不必重复自己。如果您不了解Kotlin,我希望这段代码可以吸引您,并在某一天尝试它。
基准
现在,您正在等待的部分,让我们比较Graal与优秀的'C2编译器'的性能。
让我们记住,Graal是用Java编写的,并且正在利用编译器领域的新研究,但它仍然相对年轻。另一方面,C2非常好地调整和成熟。
第一个惊喜是Mandelbrot的例子:
说实话,我没想到性能会有这么大的差异。Graal比C2快约18%!只是为了确定,我用稍微不同的公式再次尝试并收到了相同的结果。Graal在编写Kotlin的计算时非常精彩。
而现在,更令人惊讶的是,背包测试:
在这里,Graal慢了54%!
做一些分析,我发现我的代码大部分时间都花在了为memoization生成密钥的函数上。
为了确保我是正确的,我订购了套装,然后将其转换为字符串。这是很多不必要的工作,它依赖于 HashSet
Java实现。
所以,我改变了方法来生成密钥:
private fun generateKey(choice:Set < Watch >):String =
选择。sortedBy { “$ {it.price} - $ {it.weight}” }。toString()
对此:
private fun generateKey(choice:Set < Watch >):String =
选择。地图 { 它。hashCode()}。sorted()。joinToString(“”)
新功能更快,因为它对手表的哈希值进行排序,这些哈希值是唯一的,然后将它们连接成一个字符串。
请注意,我们不能简单地使用Set的哈希值,因为可能存在哈希冲突。我实际上尝试过并验证它开始发出错误的结果。
可以为Set创建更安全的散列方法,但这里的目标不是最大限度地优化算法,而是编写高效且清晰的Kotlin代码。
现在,让我们来看看惯用的Kotlin的结果:
在这里,Graal再次明显比C2快,总的来说,新的密钥生成器比以前的实现快得多。
我对这些结果的猜测是,C2经过大量优化(使用内在函数等)用于典型的Java用法,而Graal擅长编译小方法和轻量级对象,这是典型的惯用Kotlin。
我希望这篇文章能激励更多Kotlin开发人员使用Graal!快乐的编码!
JVM Advent Calendar:将Kotlin性能与Graal和C2进行比较相关推荐
- 比较Kotlin性能与Graal和C2
您可能听说过Graal,这是用Java编写的JVM的新JIT编译器. 自Java10开始,它就可以在JDK中使用,将来可能会成为JDK的标准. 如果您有兴趣,可以在这里找到更多信息: https : ...
- kotlin与go性能_比较Kotlin性能与Graal和C2
kotlin与go性能 您可能听说过Graal,这是用Java编写的JVM的新JIT编译器. 自Java10起,它就可以在JDK中使用,将来可能会成为JDK的标准. 如果您有兴趣,可以在这里找到更多信 ...
- Excel Advent Calendar for 2010
Last December, I posted an Excel Advent Calendar, and it was surprisingly popular, throughout the ye ...
- JVM调优全面探讨-性能设计沉思录(1)
为什么要jvm gc可能是java程序猿或非java程序猿讨论最多的话题,到底怎么回事? 本篇内容:内存管理发展史,JVM内存管理分析和实践(基础知识),JVM8调优(内存运行原理和编译优化) :2 ...
- jvm调优工具_JVM性能调优监控工具jps、jstack、jmap、jhat、hprof使用详解
来自:ITeye博客, 作者:Josh_Persistence 链接:https://www.iteye.com/blog/josh-persistence-2161848 现实企业级Java应用开发 ...
- Kotlin 性能优化利器 —— Sqeuence 原理浅析
前言 本文将介绍 Kotlin 中 序列(Sequence)的概念及使用,并介绍该惰性集合操作对集合链式调用性能优化背后的原理. 目录 序列(Sequence) 概念 在使用 Kotlin 集合操作符 ...
- 深入理解JVM虚拟机(三):虚拟机性能监控工具
本博客将讲解Java虚拟机性能监控工具的使用以及对Java虚拟机进行性能监控的实验.Java开发人员需要对虚拟机性能监控工具的使用进行掌握,这是很有必要的. 1.概述 给一个系统定位问题的时候,知识. ...
- Java虚拟机:常见JVM参数配置和GC性能优化
一.常见的JVM参数配置: 1.垃圾回收统计信息: -XX:+PrintGC 打印GC简要信息 -XX:+PrintGCDetails打印GC的详细信息 -XX:+PrintGCTimeSta ...
- jvm 参数_6个提高性能的JVM参数
截止到2020年五月,JVM中仅仅只是关于垃圾回收和内存相关的参数就已经超过600个.如果算上其他方面的参数,JVM相关的总参数能轻松超过1000个.参数太多了,弄得人很懵逼.在这边文章中,我们只选取 ...
最新文章
- 【 FPGA 】状态机,FPGA的灵魂
- 支付接入开发的陷阱有多深?
- 新BOJ 87. 日期
- GDCM:区分音量DiscriminateVolume的测试
- 运算符重载 返回类型说明符后加_Java学习:运算符的使用与注意事项
- dmp文件查看表空间_innoDb文件
- web 前端routine
- QList、QVector、QMap容器类
- java实现英文文件单词搜索系统_java对于目录下文件的单词查找操作代码实现
- 未来语音识别技术的发展趋势会如何
- C语言函数库帮助文档
- SVN同步分支代码到主干
- GMP文件分类与编码管理规程
- Android Studio设置签名密钥
- 【将金令】炒白银,切忌!切忌!
- C# 实现定时/循环任务
- java freemarker转PDF和Word
- MATLAB 彩色图转灰色图处理
- python 之 for 循环
- Someone‘s Acting Sus....
热门文章
- 构建煤矿物联网大数据平台思路(2)-实时数据库与时序数据库
- Java基础篇——字符串处理(String,StringBuffer,StringBuild)
- 23种设计模式(合集)
- wps文档怎么删除空白段,删除空白段的操作方法
- 我的老婆很聪明(一)
- 关于2022年6月青少年等级考试的几点说明:
- CoVOS:无需解码!利用压缩视频比特流的运动矢量和残差进行半监督的VOS加速(CVPR 2022)...
- mysql四舍五入函数取两位小数_MySQL四舍五入函数ROUND(x)、ROUND(x,y)和TRUNCATE(x,y)
- Python 数组截取
- Outlook签名设置不完全指北