使用JMH进行微基准测试

JMH是一个用于java或者其他JVM语言的,提供构建,运行和分析(按照多种基准:纳秒,微妙、毫秒、宏)的工具。

应用实例

相信很多人和我一样,在使用了多个日志框架之后,肯定见过下面这些调试日志:

logger.debug("Concatenating strings " + x + y + z);

logger.debug("Using variable arguments {} {} {}", x, y, z);

if (logger.isDebugEnabled())
  logger.debug("Using the if debug enabled {} {} {}", x, y, z);

在一般的应用中,日志输出级别都是INFO或者WARNING。即使使用了WARNING级别,上面这几断代码都可以正常输出调试信息。但是,调试日志可以却可以影响应用的表现(性能)。为了证明这一点,我们将使用微基准测试来测试以上三种代码的性能,这里使用Java微基准测试工具(JMH)。上面的三种代码分别可以概括为:使用字符串连接、使用变量参数和使用If进行debug可用检测。

JMH设置

通过maven archtype我们可以很快的创建一个JMH工程。

 

mvn archetype:generate -DinteractiveMode=false -DarchetypeGroupId=org.openjdk.jmh 
-DarchetypeArtifactId=jmh-java-benchmark-archetype -DarchetypeVersion=1.4.1 
-DgroupId=org.agoncal.sample.jmh -DartifactId=zjgloggingtest -Dversion=1.0

 

将工程导入Eclipse,向pom文件中增加依赖:

<dependency>
  <groupId>org.slf4j</groupId>
  <artifactId>slf4j-api</artifactId>
  <version>1.7.7</version>
</dependency>
<dependency>
  <groupId>ch.qos.logback</groupId>
  <artifactId>logback-classic</artifactId>
  <version>1.0.11</version>
</dependency>

然后我们增加一个logback.xml配置文件,并设置日志输出级别为INFO

<configuration>
  <property name="LOG_HOME" value="D:/myGit/zjgtest/log" />
  
  <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%highlight(%d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n)</pattern>
    </encoder>
  </appender>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder><pattern>%msg%n</pattern></encoder>
  </appender>
  
   <!-- 按照每天生成日志文件 -->   
    <appender name="FILE"  class="ch.qos.logback.core.rolling.RollingFileAppender">   
        <Encoding>UTF-8</Encoding>   
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--日志文件输出的文件名-->
            <FileNamePattern>${LOG_HOME}/myApp.log.%d{yyyy-MM-dd}.log</FileNamePattern>   
            <MaxHistory>30</MaxHistory>
        </rollingPolicy>   
        <layout class="ch.qos.logback.classic.PatternLayout">  
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--> 
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n   
            </pattern>   
       </layout> 
        <!--日志文件最大的大小-->
       <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
         <MaxFileSize>10MB</MaxFileSize>
       </triggeringPolicy>
    </appender>
    
  <!-- 日志输出级别 -->
  <root level="INFO">
    <!-- <appender-ref ref="CONSOLE" /> -->
    <appender-ref ref="FILE" /> 
  </root>
</configuration>

工程目录如下:

image

MyBenchmark.java:

 

/*
 * Copyright (c) 2014, Oracle America, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 *  * Neither the name of Oracle nor the names of its contributors may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.agoncal.sample.jmh;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Threads;
import org.openjdk.jmh.annotations.Warmup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

//@BenchmarkMode(Mode.All)
@Warmup(iterations=5)
@Measurement(iterations=5)
@Threads(10)
public class MyBenchmark {

  private static final Logger logger = LoggerFactory.getLogger(MyBenchmark.class);

  @Benchmark
  public void testConcatenatingStrings() {

    String x = "", y = "", z = "";

    for (int i = 0; i < 100; i++) {
      x += i; y += i; z += i;

      logger.debug("Concatenating strings " + x + y + z);
    }
  }
  
  @Benchmark
  public void testVariableArguments() {

    String x = "", y = "", z = "";

    for (int i = 0; i < 100; i++) {
      x += i; y += i; z += i;

      logger.debug("Variable arguments {} {} {}", x, y, z);
    }
  }
  
  @Benchmark
  public void testIfDebugEnabled() {

    String x = "", y = "", z = "";

    for (int i = 0; i < 100; i++) {
      x += i; y += i; z += i;

      if (logger.isDebugEnabled())
        logger.debug("If debug enabled {} {} {}", x, y, z);
    }
  }
}

 

JMH使用

使用maven命令打包就能生成一个benchmarks.jar

 mvn clean install
 java -jar target/benchmarks.jar

当我们使用以上命令运行这个jar时,我们就可以在控制台上看到一些有趣的内容输出:JMH进入循环、预热JVM,执行@Benchmark注解的空方法,并给出每秒操作的数量。

image

参考:

使用JMH进行微基准测试:不要猜,要测试!

转载于:https://my.oschina.net/zjg23/blog/833273

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值