Java Micro-Benchmarking:如何编写正确的基准

几个月前,我写了一篇文章比较循环的短索引的性能 。 我问自己关于使用短裤作为循环迭代次数很少的循环的性能。

在Java语言中,所有对整数的操作都是int进行的。 因此,如果我们使用short作为循环索引,则在每次迭代时都将进行类型转换,这实际上比对int的简单影响要重。

我编写该代码来实现我的目标:

package com.wicht.old;public class TestShortInt {public static void main(String[] args){long startTime = System.nanoTime();int resultInt = 0;for (int i = 0; i < 100000; i++){for (int j = 0; j < 32760; j++){resultInt += i * j;}}System.out.println("Temp pour int : " + (System.nanoTime() - startTime) / 1000000 + " ms");startTime = System.nanoTime();int resultShort = 0;for (int k = 0; k < 100000; k++){for (short f = 0; f < 32760; f++){resultShort += k * f;}}System.out.println("Temp pour short : " + (System.nanoTime() - startTime) / 1000000 + " ms");System.out.println(resultInt);System.out.println(resultShort);}
}

结果我发现short比int慢了两倍,直到一周前我才确信这些结果。

这时,一位读者(Jean)批评了我的测试结果,并给了我有关微基准测试的几篇文章的链接。 我阅读了这些文章,并了解了为什么我的结果不正确。

实际上,我的测试没有注意可能改变测试结果的几件事:

  • JVM预热 :由于有几个参数,代码通常通常会很慢,并且随着执行时间的增长直到达到稳态,代码会变得越来越快。
  • 类加载 :第一次启动基准测试时,必须加载所有使用的类,从而增加了执行时间。
  • 即时编译器 :当JVM识别出代码的重要部分时
  • 垃圾收集器 :在基准测试期间可能会发生垃圾收集,并且时间会大大增加。

由于所有这些因素,第一次运行(可能需要运行10秒)比其他运行速度慢,并且会使基准完全错误。

那么,我们如何才能取得良好的基准测试结果呢?

这确实很困难,但是我们可以使用Elliptic Group的软件开发人员Brent Boyer引入的基准框架获得帮助。 该框架照顾了所有先前引入的因素,并制定了良好的基准。

该框架的使用非常简单,您只需创建Benchmark类的新实例,并将其传递给Callable或Runnable即可,然后直接启动测试。 这是在循环索引中测试short和int的示例:

public class ShortIndexesLoop {public static void main(String[] args) {Callable callableInt = new Callable(){public Long call() throws Exception {long result = 0;for (int f = 0; f < 32760; f++){result += 444;}return result;}};Callable callableShort = new Callable(){public Long call() throws Exception {long result = 0;for (short f = 0; f < 32760; f++){result += 444;}return result;}};try {Benchmark intBenchmark = new Benchmark(callableInt);System.out.println("Result with int ");System.out.println(intBenchmark.toString());Benchmark shortBenchmark = new Benchmark(callableShort);System.out.println("Result short ");System.out.println(shortBenchmark.toString());} catch (Exception e) {e.printStackTrace();}}
}

要获得结果,可以使用Benchmark.toString()或Benchmark.toStringFull()获得更多统计信息。 您还可以使用Benchmark.getSd()直接访问某些统计信息(例如标准差),也可以直接使用Benchmark.getStats()获取所有统计信息。

这是前面代码的结果:

结果int first = 807.056 us,平均值= 46.032 us(CI delta:-261.393 ns,+408.932 ns),sd = 230.929 us(CI delta:-68.201 us,+105.262 us)
结果短短优先= 721.912 us,平均值= 48.234 us(CI delta:-198.625 ns,+254.774 ns),sd = 160.196 us(CI delta:-32.764 us,+37.882 us)

如您所见,短版本仅比int慢104.78%。 这表明最初的结果是完全错误的。

这是int版本的完整结果:

动作统计信息:第一个= 807.056 us,平均值= 46.032 us(CI delta:-261.393 ns,+408.932 ns),sd = 230.929 us(CI delta:-68.201 us,+105.262 us)警告:执行时间有极端异常情况,标清值可能不准确---根据块统计信息计算操作统计信息-每个块测量32768个任务执行-用户说任务内部执行m = 1个动作-那么每个块测量的动作数为a = 32768-阻止统计信息:平均值= 1.508 s(CI增量:-8.565毫秒,+ 13.400毫秒),sd = 41.803毫秒(CI增量:-12.346毫秒,+ 19.054毫秒)–用于将阻止统计信息转换为行动统计信息的论坛(均值)假设a / a为1 / s,则sd缩放为1 / sqrt(a))假定操作执行时间为iid — —每个置信区间(CI)被报告为点估计的+-增量或封闭点间隔([x,y])–每个置信区间的置信度为0.95 — —-–执行时间显示在外边的情况–使用箱线图确定 中位数= 1.498 s,interquantileRange = 34.127 ms的算法– 3是极度(偏高):#57 = 1.621 s,#58 = 1.647 s,#59 = 1.688 s –2是温和的(偏高): #55 = 1.570 s,#56 = 1.582 s ———-阻止sd值可能无法反映任务的内在变化–猜测:环境噪声至少解释了所测量sd的55.89418621876822%———- –动作sd值几乎完全相同由离群值填充–根据等值离群值模型,它们至少导致了98.95646276911543%的已测量方差–模型数量:a = 32768.0,muB = 1.5083895562166663,sigmaB = 0.04180264914581472,muA = 4.603239612477619E-5,sigmaA = 2.3092919283255957E- 4,tMin = 0.0,muGMin = 2.3016198062388096E-5,sigmaG = 5.754049515597024E-6,cMax1 = 1252,cMax2 = 322,cMax = 322,cOutMin = 322,varOutMin = 0.0017292260645147487,muG(cOutMin)= 2.3034259031465023E-5, U(cOutMin)= 0.002363416110812895

就像您在使用此框架时可能看到的那样,当您举例说明您存在极端异常值可能使标准偏差完全错误时,它会向您发出一些警告。

您可以在Elliptic Group的网页上下载此框架。 我发现它非常强大且易于使用,并且每次需要进行基准测试时都会使用它。

总而言之,我还必须说,即使您使用那种框架,如果您没有测试代码的正确部分,也可能会导致非常糟糕的基准测试。 这是来自Brent Boyer的两篇非常有趣的文章:

  • 健壮的Java基准测试,第1部分:问题
  • 强大的Java基准测试,第2部分:统计信息和解决方案

参考: 如何通过 @Blog(“ Baptiste Wicht”)的 JCG合作伙伴 Baptiste Wicht 编写正确的基准 。

相关文章 :
  • 绩效焦虑–关于绩效不可预测性,度量和基准
  • 改善Java应用程序性能的快速技巧
  • 如何在Java中获得类似于C的性能
  • Java中的低GC:使用原语而不是包装器
  • 如何在不到1ms的延迟内完成100K TPS

翻译自: https://www.javacodegeeks.com/2011/09/java-micro-benchmarking-how-to-write.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/374196.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

新唐M031学习笔记(一)定时器基础计数应用

先上代码 void Hw_Timer0_Init(void) {//20:100ms 200:10ms 2000:1ms 20000:100us 200000:10us TIMER_Open(TIMER0, TIMER_PERIODIC_MODE, 200000);/* Update prescale to set proper resolution. */TIMER_SET_PRESCALE_VALUE(TIMER0, 1); /* Enable Timer0 interrupt */TI…

java三元操作符注意

/* 三元操作符的类型务必一致 */ public class proposal_3 {public static void main(String[] args) {int i80;String sString.valueOf(i<90?90:100);String s1String.valueOf(i<90?90:100.0);if(s.equals(s1))System.out.println("s和s1相等&#xff01;"…

缓解口臭可以喝一种水

河南中医学院第一附属医院耳鼻喉科主任医师梅祥胜点评&#xff1a;通常情况下&#xff0c;口臭跟脾胃湿热有关。中医讲&#xff1a;“胃主受纳&#xff0c;脾主运化&#xff1b;胃气主降&#xff0c;使饮食物及 其糟粕得以下行&#xff0c;脾气主升&#xff0c;则饮食物之精华得…

asp.net+mvc+easyui+sqlite 简单用户系统学习之旅(二)—— easyui的简单实用

下面开始在UserManager.Web中利用easyUI构建web。 1. 先删除自带的controllers、models和views&#xff08;里面的shared和web.config可以保存&#xff09;下面的文件 2. 要利用easyUI&#xff0c;首先去网上下载jquery-easyui-1.3.2.zip&#xff0c;同时下载一份EasyUI-1.3.2.…

adc如何获取周期_LOL:千珏拥有ADC最需要的位移和无敌能力,为什么没人用她打下路?...

— 点击蓝字 关注我们 —英雄联盟自国服上线以来&#xff0c;已经陪伴玩家走过了9个年头&#xff0c;目前英雄联盟中的英雄数量已经达到了151位&#xff0c;每一位都各具特色。千珏是一位深受玩家们喜爱的英雄&#xff0c;其在官方英雄的定位中&#xff0c;属于打野英雄&#x…

航顺HK32F030MF4P6 RST作GPIO SWCLK作EXTI5 SWDIO作ADC_AIN0

老习惯&#xff0c;先上代码 void Hw_Input_Chage_Init(void) {GPIO_InitTypeDef GPIO_InitStructure;RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_IOMUX, ENABLE);GPIOMUX->NRST_PIN_KEY (uint32_t)(0x00005AE1); //KEY…

centos7.2下编译安装git

centos最新的7.2版本&#xff0c;git居然是1.8&#xff0c;而最新的git版本是2.9 差的太多了&#xff0c;何况git2.0后有大更新。于是&#xff0c;我决定编译安装。中间有一点小破折&#xff0c;记录一下&#xff0c;备忘。 1&#xff0c;下载最新的源码&#xff0c;网址&#…

java务必让常量的值在运行期保持不变

/* 常量就是常量&#xff0c;在编译期就必须确定其值&#xff0c;不应该在运行期更改&#xff0c;否则程序的可读性会非常差 */public class proposal_2 {interface Const{public static final int RAND_CONSTnew Random().nextInt();}public static void main(String[] arg…

Java并发教程–信号量

这是我们将要进行的Java并发系列的第一部分。 具体来说&#xff0c;我们将深入探讨Java 1.5及更高版本中内置的并发工具。 我们假设您对同步和易失性关键字有基本的了解。 第一篇文章将介绍信号量-特别是对信号量进行计数 。 信号量是用于限制对资源访问的经常被误解和使用不足…

android surfaceview 大小_Android 使用Camera2 API采集视频数据

Android 视频数据采集系列的最后一篇出炉了&#xff0c;和前两篇文章想比&#xff0c;这篇文章从系统API层面进行一些探索&#xff0c;涉及到的细节更多。初次接触 Camera2 API 会觉得它的使用有些繁琐&#xff0c;涉及到的类有些多&#xff0c;不过就像第一次使用Activity, Fr…

java生成随机字符串

学习java comparable特性时候&#xff0c;定义如下Student类&#xff0c;需要需要随机添加学生姓名以及学号和成绩&#xff0c;这是java如何随机生成名字&#xff0c;根据我的查询&#xff0c;我找到目前java库支持两种方法。 1. org.apache.commons.lang3.RandomStringUtils类…

使用SharedPreferenes存取数据

//使用SharedPreference存储数据 public void on(View view){     //获取用户名和密码     String nameeditText1.getText().toString();     String numbereditText2.getText().toString();     //判断checkBox是否为勾选      CheckBox box(CheckBox…

使用Java VisualVM分析您的应用程序

当您需要发现应用程序的哪个部分消耗更多的CPU或内存时&#xff0c;必须使用探查器执行此操作。 默认情况下&#xff0c;Sun JDK中附带的一个探查器是Java VisualVM。 这个事件探查器非常简单易用&#xff0c;功能强大。 在这篇文章中&#xff0c;我们将看到如何安装它并使用它…

ArcSDE for SQL Server安装及在ArcMap中创建ArcSDE连接

ArcSDE for SQL Server安装及在ArcMap中创建ArcSDE连接 原文:ArcSDE for SQL Server安装及在ArcMap中创建ArcSDE连接安装ArcSDE for SQL Server&#xff0c;最后一步成功后的界面如下&#xff1a;在ArcMap中创建ArcSDE连接&#xff0c;截图如下&#xff1a;posted on 2016-08-0…

java反射main方法参数注意

public class ReflectMethodMain {public static void main(String[] args) throws Exception {Method methodMainTestArgument.class.getMethod("main", String[].class);/*jdk 1.4之前的版本不支持可变参数&#xff0c;对组类的参数会自动拆包然后用来匹配数据参数…

python调用c函数传字符串参数_Python使用ctypes模块调用DLL函数之传递数值、指针与字符串参数...

在Python语言中&#xff0c;可以使用ctypes模块调用其它如C语言编写的动态链接库DLL文件中的函数&#xff0c;在提高软件运行效率的同时&#xff0c;也可以充分利用目前市面上各种第三方的DLL库函数&#xff0c;以扩充Python软件的功能及应用领域&#xff0c;减少重复编写代码、…

沁恒CH554 KEIL环境搭建

首先下载WCHISPTool_Setup.exe http://www.wch.cn/products/CH554.html 123这三个可下载的都下吧&#xff0c;后面开发都要用的 安装好后运行&#xff0c;菜单栏上&#xff0c;功能->添加WCH MCU到KEIL器件库 这时候在KEIL安装目录里面的UV4文件夹下可以看到wch.cdb的文件…

【CV论文阅读】Rank Pooling for Action Recognition

这是期刊论文的版本&#xff0c;不是会议论文的版本。看了论文之后&#xff0c;只能说&#xff0c;太TM聪明了。膜拜~~ 视频的表示方法有很多&#xff0c;一般是把它看作帧的序列。论文提出一种新的方法去表示视频&#xff0c;用ranking function的参数编码视频的帧序列。它使用…

java不要在常量和变量中出现易混淆的字母

public class proposal {public static void main(String[] args) {long i1l; System.out.println("i的两倍是&#xff1a;"(ii));System.out.println("i的两倍是&#xff1a;"ii); //注意此处和上面的有很大的区别} }输出&#xff1a;211/** 注意:* …

VS2019 WPF制作OTA上位机(一)新建工程

首先创建新项目&#xff0c;文件 -> 新建 -> 项目 下拉菜单选择C#和Window&#xff0c;选择WPF应用程序&#xff0c;下一步 输入项目名&#xff0c;下一步 这里选择.NET 5.0&#xff0c;也可以选择其他的&#xff0c;个人习惯.NET&#xff0c;点击创建 这时候出现初始…