微基准测试 r_在您的构建过程中添加微基准测试

微基准测试 r

介绍

作为一个行业,我们正在采用更高的透明度和更可预测的构建过程,以降低构建软件的风险。 持续交付的核心原则之一是通过反馈循环收集反馈。 在Dev9中 ,我们采用了与CD原则一致的“ 先知道 ”原则,这意味着我们(开发团队)希望成为第一个知道何时出现故障,性能下降或任何与之不符的结果的人。业务目标。

Maven和其他构建工具为开发人员提供了标准化的工具和生态系统,可在其中建立和交流反馈。 虽然单元测试,功能,构建验收,数据库迁移,性能测试和代码分析工具已成为开发流程中的主要内容,但基准测试基本上仍处于过程之外。 这可能是由于缺乏开源的,低成本的工具或轻量级的库,这些库增加了最小的复杂性。

现有的工具通常需要将外部工具与运行时工件集成在一起,从而使复杂性更加复杂,并且测试未保存在同一源存储库中,甚至没有存储在源存储库中。 本地开发人员无法毫不费力地运行基准测试,因此测试会很快失去其价值。 除了主流的解决方案问题外,基准测试通常不是在课堂上讲授的,并且通常在没有必要的隔离才能获得可靠结果的情况下实施。 这使得所有有关基准测试结果的博客或帖子成为巨魔的成熟目标。

综上所述,围绕代码库的关键区域进行某种基准覆盖仍然很重要。 积累有关代码关键部分的历史知识可以帮助影响优化工作,向团队通报技术欠债,在性能阈值更改已提交时发出警报并比较算法的先前版本或新版本。 现在的问题是,如何找到基准并轻松添加到我的新项目或现有项目中。 在此博客中,我们将专注于Java项目(1.7+)。 该示例代码将利用Maven,尽管Gradle的工作原理非常相似。 我在整个博客中提出了一些建议,这些建议是基于过去项目的经验得出的。

JHM简介

在对基准Java代码进行基准测试时,有很多强大的选择,但是它们大多数都有缺点,包括许可证费用,额外的工具,字节代码操纵和/或Java代理,使用非基于Java的代码概述的测试以及高度复杂的配置设置。 我喜欢使测试尽可能接近被测代码,以减少脆性,降低内聚力并减少耦合。 我认为我以前使用过的大多数基准测试解决方案太麻烦了,或者运行测试的代码不够孤立(完全集成在代码中),或者包含在远离源代码的辅助解决方案中。

该博客的目的是演示如何在构建管道中添加轻量级基准测试工具,因此我将不详细介绍如何使用JMH,以下博客是学习的绝佳资源:

  • http://jmhwiki.blogspot.com
  • http://java-performance.info/jmh/
  • http://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/src/main/java/org/openjdk/jmh/samples/

基准测试模式

关于模式和评分,我想指出一小部分,因为它们在基本配置的设置中起着重要的作用。 在基本级别上,JMH有两种主要的度量类型:吞吐量和基于时间的度量。

吞吐量测量

吞吐量是每单位时间可以完成的操作量。 随着框架增加测试的负载量,JMH会维护成功和失败操作的集合。 注意:确保方法或测试完全隔离,并且诸如测试对象创建之类的依赖项是在方法之外或在设置方法中进行预测试的。 使用“吞吐量”,该值越高,越好,因为它表明可以在单位时间内运行更多的操作。

基于时间的测量

基于时间的测量是吞吐量的反伙伴。 基于时间的测量的目标是确定特定操作每单位时间运行多长时间。

平均时间

最常见的基于时间的度量是“ AverageTime”,用于计算操作的平均时间。 JMH还将产生“ 得分错误 ”,以帮助确定对产生得分的信心。 “ 得分误差 ”通常是置信区间的1/2,它表示结果与平均时间的偏离程度。 结果越低,表明每次操作的平均运行时间越短越好。

采样时间

SampleTime与AverageTime相似,但是JMH尝试增加更多的负载并查找失败,从而产生失败百分比矩阵。 使用AverageTime时,数字越小越好,这些百分比对于确定由于吞吐量和时间长度而导致失败的位置很有用。

SingleShotTime

最后也是最不常用的模式是SingleShotTime。 该模式实际上是一次运行,可用于冷测方法或测试您的测试。 如果在运行基准测试时作为参数传递SingleShotTime,可能会很有用,但会减少运行测试所需的时间(尽管这样做会减少测试的价值并可能使它们自重)。 与其他基于时间的测量一样,值越低越好。

将JMH添加到Java项目

目标:本部分将显示如何创建可重复使用的工具,该工具可在不增加代码开销或代码重复的情况下添加新测试。 注意,依赖项在“测试”范围内,以避免将JMH添加到最终工件中。 我创建了一个在使用Protobuf替代REST for Microservices时使用JMH的github存储库。 可以在这里找到代码: https : //github.com/mike-ensor/protobuf-serialization

1)首先将依赖项添加到项目中:

<dependencies>
<!-- Other libraries left out for brevity -->
<!-- jmh.version is the lastest version of JMH. Find by visitinghttp://search.maven.org --><dependency><groupId>org.openjdk.jmh</groupId><artifactId>jmh-core</artifactId><version>${jmh.version}</version><scope>test</scope></dependency><dependency><groupId>org.openjdk.jmh</groupId><artifactId>jmh-generator-annprocess</artifactId><version>${jmh.version}</version><scope>test</scope></dependency>
<!-- Other libraries left out for brevity -->
</dependencies>

2)JMH建议将基准测试和工件包装在同一uber jar中。 有几种方法可以实现uber jar,显式地使用made的“ shade”插件或隐式地使用Spring Boot,Dropwizard或具有类似结果的某些框架。 出于本博客文章的目的,我使用了Spring Boot应用程序。

3)添加具有主条目类和全局配置的测试工具。 在此步骤中,在项目的测试区域中创建一个入口点(用#1表示)。 目的是避免将基准代码与主要工件打包在一起。

3.1)添加BenchmarkBase文件(在#2上方指示)。 该文件将用作基准测试的入口点,并包含测试的所有全局配置。 我编写的类正在寻找一个包含配置属性的“ benchmark.properties”文件(上面在#3中指示)。 JMH可以选择输出文件结果,并且此配置是为JSON设置的。 结果与您的持续集成工具一起使用,可以(应该)存储以供历史使用。

此代码段是Maven运行的Benchmark流程的基本工具和入口点(在下面的步骤5中进行设置)。此时,项目应该能够运行基准测试,因此让我们添加一个测试用例。

@SpringBootApplication
public class BenchmarkBase {public static void main(String[] args) throws RunnerException, IOException {Properties properties = PropertiesLoaderUtils.loadAllProperties("benchmark.properties");int warmup = Integer.parseInt(properties.getProperty("benchmark.warmup.iterations", "5"));int iterations = Integer.parseInt(properties.getProperty("benchmark.test.iterations", "5"));int forks = Integer.parseInt(properties.getProperty("benchmark.test.forks", "1"));int threads = Integer.parseInt(properties.getProperty("benchmark.test.threads", "1"));String testClassRegExPattern = properties.getProperty("benchmark.global.testclassregexpattern", ".*Benchmark.*");String resultFilePrefix = properties.getProperty("benchmark.global.resultfileprefix", "jmh-");ResultFormatType resultsFileOutputType = ResultFormatType.JSON;Options opt = new OptionsBuilder().include(testClassRegExPattern).warmupIterations(warmup).measurementIterations(iterations).forks(forks).threads(threads).shouldDoGC(true).shouldFailOnError(true).resultFormat(resultsFileOutputType).result(buildResultsFileName(resultFilePrefix, resultsFileOutputType)).shouldFailOnError(true).jvmArgs("-server").build();new Runner(opt).run();}private static String buildResultsFileName(String resultFilePrefix, ResultFormatType resultType) {LocalDateTime date = LocalDateTime.now();DateTimeFormatter formatter = DateTimeFormatter.ofPattern("mm-dd-yyyy-hh-mm-ss");String suffix;switch (resultType) {case CSV:suffix = ".csv";break;case SCSV:// Semi-colon separated valuessuffix = ".scsv";break;case LATEX:suffix = ".tex";break;case JSON:default:suffix = ".json";break;}return String.format("target/%s%s%s", resultFilePrefix, date.format(formatter), suffix);}}

4)创建一个类来对操作进行基准测试。 请记住,基准测试将针对整个方法主体进行,包括日志记录,文件读取,外部资源等。请注意要进行基准测试并减少或删除依赖项,以便隔离主题代码以确保对结果的信心更高。 在此示例中,在

@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public class SerializationBenchmark {private RecipeService service;private Recipe recipe;private byte[] protoRecipe;private String recipeAsJSON;@Setup(Level.Trial)public void setup() {IngredientUsed jalepenoUsed = new IngredientUsed(new Ingredient("Jalepeno", "Spicy Pepper"), MeasurementType.ITEM, 1);IngredientUsed cheeseUsed = new IngredientUsed(new Ingredient("Cheese", "Creamy Cheese"), MeasurementType.OUNCE, 4);recipe = RecipeTestUtil.createRecipe("My Recipe", "Some spicy recipe using a few items", ImmutableList.of(jalepenoUsed, cheeseUsed));service = new RecipeService(new ObjectMapper());protoRecipe = service.recipeAsProto(recipe).toByteArray();recipeAsJSON = service.recipeAsJSON(recipe);}@Benchmarkpublic Messages.Recipe serialize_recipe_object_to_protobuf() {return service.recipeAsProto(recipe);}@Benchmarkpublic String serialize_recipe_object_to_JSON() {return service.recipeAsJSON(recipe);}@Benchmarkpublic Recipe deserialize_protobuf_to_recipe_object() {return service.getRecipe(protoRecipe);}@Benchmarkpublic Recipe deserialize_json_to_recipe_object() {return service.getRecipe(recipeAsJSON);}}

标题:该要点是从Protobuf序列化中提取的示例基准测试用例

现在,当您执行测试jar时,所有* Benchmark..java测试类都将运行,但这通常并不理想,因为该过程没有隔离,并且对基准测试的时间和方式进行一些控制对于保持构建时间很重要下。

让我们构建一个Maven配置文件来控制何时运行基准测试并可能启动应用程序。 注意,为了显示Maven集成测试启动/停止服务器的目的,我已将其包含在博客文章中。 我会警告需要启动或停止应用程序服务器,因为这可能会带来资源获取(REST调用)的成本,而这并不是很孤立。

5)概念是创建一个Maven配置文件以独立运行所有基准测试(即,没有单元测试或功能测试)。 这将使基准测试可以与其余构建管道并行运行。 请注意,该代码使用“ exec”插件并运行uber jar,以查找到主类的完整类路径路径。 此外,可执行文件范围仅限于“测试”源,以避免将基准代码放入最终工件中。

<profile><id>benchmark</id><properties><maven.test.ITests>true</maven.test.ITests></properties><build><plugins><!-- Start application for benchmarks to test against --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><executions><execution><id>pre-integration-test</id><goals><goal>start</goal></goals></execution><execution><id>post-integration-test</id><goals><goal>stop</goal></goals></execution></executions></plugin><!-- Turn off unit tests --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><configuration><excludes><exclude>**/*Tests.java</exclude><exclude>**/*Test.java</exclude></excludes></configuration></plugin><plugin><groupId>org.codehaus.mojo</groupId><artifactId>exec-maven-plugin</artifactId><version>1.5.0</version><executions><execution><goals><goal>exec</goal></goals><phase>integration-test</phase></execution></executions><configuration><executable>java</executable><classpathScope>test</classpathScope><arguments><argument>-classpath</argument><classpath /><argument>com.dev9.benchmark.BenchmarkBase</argument><argument>.*</argument></arguments></configuration></plugin></plugins></build>
</profile>

此代码段显示了一个仅运行基准测试的maven配置文件示例。

6)最后,可选项目是在“持续集成”构建管道中创建一个可运行的构建步骤。 为了独立运行基准测试,您或您的CI可以运行:

mvn clean verify -Pbenchmark

结论

如果您使用的是基于Java的项目,则相对容易地将JMH添加到您的项目和管道中。 与项目关键区域相关的历史分类帐的好处对于保持较高的质量水平非常有用。 将JMH添加到您的管道还遵循持续交付原则,包括反馈循环,自动化,可重复和不断改进。 考虑将JMH线束和一些测试添加到解决方案的关键区域。

翻译自: https://www.javacodegeeks.com/2016/12/adding-microbenchmarking-build-process.html

微基准测试 r

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

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

相关文章

HH SaaS电商系统服务商品在移动端下单结算的交互设计

服务商品只能单独下单购买&#xff0c;不允许加入购物车我们知道服务商品有三种形式&#xff1a;线上服务、到店服务、上门服务&#xff0c;因为不同服务形式买家和卖家所需的信息不同&#xff0c;所以交互界面也会不同&#xff0c;前端需要判断当前服务商品的服务形式&#xf…

linux 远程备份mysql数据库_使用脚本自动化远程备份MySQL数据库

通常情况下、MySQL都需要备份&#xff0c;备份的方法有很多种。下面是我用脚本配合计划任务完成的自动备份远程的数据库。一、 确认备份方案&#xff1a;备份机&#xff1a;ip192.168.8.51数据库服务器&#xff1a;ip192.168.8.46备份的内容&#xff1a;对mysql的studydb、cour…

javafx动画_JavaFX动画工具

javafx动画好的&#xff0c;我想是时候让您讲一个小秘密了。 最近三个月左右&#xff0c;我从事一个私人项目&#xff0c;目标是创建一个工具&#xff0c;使我可以轻松地为Java桌面应用程序创建动画。 JavaFX在API级别上提供了出色的动画支持&#xff0c;但对于初学者甚至中级程…

HH SaaS电商系统的商品类目设计

文章目录商品的基础类目创建基础类目编辑基础类目删除基础类目启用/禁用基础类目商城的营销类目新增商城营销类目编辑商城营销类目营销类目关联商品店铺的营销类目新增营销类目营销类目关联商品编辑店铺营销类目类目启用规则&#xff08;适用于全部类目&#xff09;商品类目分为…

HH SaaS电商系统的品牌模块设计

品牌和商品基础类目属于多对多的关系创建品牌时必须关联商品基础类目&#xff0c;且只能关联三级类目&#xff0c;至少关联一种品牌只能由租户统一进行维护管理&#xff0c;供应商、商家、商城可以申请新品牌&#xff0c;但是由租户进行审核品牌被删除或者停用后&#xff0c;关…

chameleon 算法_为了简单起见,Arquillian Chameleon

chameleon 算法使用Arquillian时&#xff0c;您需要做的一件事情就是定义要在哪个容器下执行所有测试。 这是通过在适配器的类路径中添加依赖项并取决于所使用的模式&#xff08;嵌入式&#xff0c;托管或远程&#xff09;来下载的来完成的。 他是应用程序服务器。 例如&…

HH SaaS电商系统管理后台的商品规格编辑

类目规格删除或者新增 类目原来已有的规格被删除或者新增&#xff0c;那么原先的SKU全部需要重新生成&#xff0c;所以编辑时SKU信息无需展示&#xff0c;保留的规格信息也不必显示。 提交商品数据后&#xff0c;后端根据规格值名称进行匹配&#xff0c;如果匹配成功则更新SKU…

flink和kafka区别_Apache Flink和Kafka入门

flink和kafka区别介绍 Apache Flink是用于分布式流和批处理数据处理的开源平台。 Flink是具有多个API的流数据流引擎&#xff0c;用于创建面向数据流的应用程序。 Flink应用程序通常使用Apache Kafka进行数据输入和输出。 本文将指导您逐步使用Apache Flink和Kafka。 先决条件…

solr cloud 更新 solrconfig 配置_Solr各版本新特性「4.x,5.x,6.x,7.x」

一.Solr4.x新特性1.近实时搜索Solr的近实时搜索【Near Real-Time&#xff0c;NRT】功能实现了文档添加到搜索的快速进行&#xff0c;以应对搜索快速变化的数据。2.原子更新与乐观并发原子更新功能允许客户端应用对已有文档上进行添加、更新、删除和对字段增值等操作&#xff0c…

junit数据驱动测试_使用Junit和Easytest进行数据驱动的测试

junit数据驱动测试在本文中&#xff0c;我们将看到如何使用Junit进行数据驱动的测试。 为此&#xff0c;我将使用一个名为EasyTest的库。 我们知道&#xff0c;对于TestNG&#xff0c;它已内置了数据提供程序。 通过简单的测试&#xff0c;我们可以使用Junit进行数据驱动的测试…

HH SaaS电商系统的出库功能模块设计

文章目录出库单业务流程基本流程扩展流程找不到符合条件的仓库&#xff0c;要求部分退款&#xff08;未生成出库单时&#xff09;找不到符合条件的仓库&#xff0c;全部退款&#xff08;未生成出库单时&#xff09;找不到符合条件的仓库&#xff0c;等待库存补足&#xff08;未…

java 拼图_拼图项目的诅咒:为什么Java 9一遍又一遍地延迟?

java 拼图JDK 9发行日期推迟到2017年7月 距JDK 9发行不到200天&#xff0c;它又被推迟了 。 新的发布日期已更新为2017年7月&#xff0c;比之前推迟的日期晚了四个月。 推迟日期 9月13日&#xff0c;Oracle Java平台小组的首席架构师Mark Reinhold发表了他的建议&#xff0c;…

mysql数据库增删改查关键字_mysql数据库的增删改查

数据库基本操作&#xff1a;增删改查#DML语言/*数据操作语言&#xff1a;插入&#xff1a;insert修改&#xff1a;update删除&#xff1a;delete*/1.增插入语句的方式一表已经存在啦&#xff0c;我们需要往里面插入数据/*语法&#xff1a;insert into 表名(列名,…) values(值1…

HH SaaS电商系统的采购功能模块设计

文章目录如何生成采购单系统生成采购单的流程基本流程扩展流程找不到符合条件的供应商&#xff0c;要求部分退款&#xff08;初次生成采购单时&#xff09;找不到符合条件的供应商&#xff0c;要求全部退款&#xff08;初次生成采购单时&#xff09;指定供应商的库存不足&#…

HH SaaS电商系统的入库功能模块设计

文章目录创建入库单的场景创建入库单的业务流程商品直接入库内部仓退货入库&#xff08;内部仓&#xff09;换货入库&#xff08;内部仓&#xff09;退货入库&#xff08;外部仓&#xff09;换货入库&#xff08;外部仓&#xff09;备货入库&#xff08;内部仓&#xff09;备货…

接口方法javadoc注释_继承Javadoc方法注释

接口方法javadoc注释尽管用于javadoc工具的JDK工具和实用程序页面通过实现和继承方法来描述Javadoc方法注释重用的规则&#xff0c;但是当实际上不需要使用{inheritDoc}时&#xff0c;很容易不必要地显式描述注释继承&#xff0c;因为会使用相同的注释隐式继承。 Java 8 javado…

redis java 监听_从零手写实现redis(四)添加监听器

前言java从零手写实现redis&#xff08;一&#xff09;如何实现固定大小的缓存&#xff1f;java从零手写实现redis&#xff08;三&#xff09;redis expire 过期原理java从零手写实现redis&#xff08;三&#xff09;内存数据如何重启不丢失&#xff1f;本节&#xff0c;让我们…

drill apache_如何指南:Apache Drill入门

drill apacheApache Drill是一个引擎&#xff0c;可以连接到许多不同的数据源&#xff0c;并为它们提供SQL接口。 它不仅是遍历任何复杂事物SQL界面&#xff0c;而且是功能强大的界面&#xff0c; 其中包括对许多内置函数和窗口函数的支持。 尽管它可以连接到可以使用SQL进行查…

mac mysql 重设密码_Mac下忘记mysql密码重新设置密码的图文教程

MySQL 文件在路径/usr/local/mysql下1&#xff0c; 在系统偏好设置中关闭 mysql &#xff1a; Stop MySQL Server2 &#xff0c;打开终端进入路径  /usr/local/mysql/bin输入命令 sudo su&#xff0c; 然后输入开机密码。然后输入命令&#xff1a;./mysqld_safe –skip-grant-…

activiti 变量_如何在Activiti中使用瞬态变量

activiti 变量我们昨天发布的Activiti v6 Beta3中已经加入了很多需要的功能-临时变量。 在这篇文章中&#xff0c;我将向您展示一个示例&#xff0c;说明如何使用瞬态变量来覆盖一些以前不可能&#xff08;或最佳&#xff09;的高级用例。 到目前为止&#xff0c;Activiti中的…