初探BTrace指令碼 - 看看持續整合哪個環節比較慢

iteye_18961發表於2011-07-30

需求

    這幾天發現持續整合環境的執行效率比較低,所以想到用BTrace來看看是什麼原因造成的,哪些環節比較慢。

 

    持續整合環境的服務端是hudson,裡面跑的主要是各個應用的單元測試,由maven管理執行。

 

獲取資源

    從BTrace官方下載它的工具包 http://kenai.com/projects/btrace/downloads/directory/releases

    我這邊下載的是 release-1.2 目錄下的1.2版本。

 

    簡單的使用說明,可以參考使用者手冊:http://kenai.com/projects/btrace/pages/UserGuide

 

hudson中執行的是

    hudson中跑的是單元測試程式碼內容類似如下:

 

package com.hugehard......test;

......
public class SomeBizServiceTest extends JTester {

......

    @Test
    public void testXX() {
        ...
    }

    @Test
    public void testOO() {
        ...
    }
    ...
}
 

    所以我們需要監控的是單元測試類,這些類處於名稱包含hugehard的包路徑中。

    我們希望知道testXX, testOO這樣的方法的執行時間。

編寫監控指令碼

 

package hudson;

import static com.sun.btrace.BTraceUtils.print;
import static com.sun.btrace.BTraceUtils.println;

import com.sun.btrace.BTraceUtils.Time;
import com.sun.btrace.annotations.BTrace;
import com.sun.btrace.annotations.Kind;
import com.sun.btrace.annotations.Location;
import com.sun.btrace.annotations.OnMethod;
import com.sun.btrace.annotations.ProbeClassName;
import com.sun.btrace.annotations.ProbeMethodName;
import com.sun.btrace.annotations.TLS;

/**
 * BtraceHudson.java
 * 
 * @author caesar 2011-7-30 AM11:23:17
 */
@BTrace
public class BtraceHudson {

    @TLS
    static long starttime = 0;

    @OnMethod(clazz = "/.*hugehard.*/", method = "/test.*/")
    public static void startMethod(@ProbeClassName String probeClass, 
                                                 @ProbeMethodName String probeMethodName) {
        print("probeClass: ");
        print(probeClass);
        print("  ");
        print("probeMethodName: ");
        print(probeMethodName);
        print("  start time: ");
        starttime = Time.nanos();
        println(starttime);
    }

    @OnMethod(clazz = "/.*hugehard.*/", method = "/test.*/",  
                        location = @Location(Kind.RETURN))
    public static void collectTestMethodExecutionEnd(@ProbeClassName String probeClass,
                                                     @ProbeMethodName String probeMethodName) {
        print("probeClass: ");
        print(probeClass);
        print("  ");
        print("probeMethodName: ");
        print(probeMethodName);
        print("  execute time: ");
        long executeTime = Time.nanos() - starttime;
        println(executeTime);
    }
}

 

    上面這段程式碼是參考博文 http://jarit.iteye.com/blog/1010908 中的內容,所以這裡就不贅述它的原理了。

 

maven不能btrace?

    我在自己的工程根目錄下,執行“mvn clean test”。

    通過“jps -l”拿到maven的PID。

    而後通過“btrace <PID> BtraceHudson.java”,期望能夠獲得每個測試方法的執行時間。

    但是沒有獲得任何的資訊。

 

 

    後來把標註 @OnMethod 中的clazz和method限定都放到最寬泛的程度,才發現,裡面拿到的方法執行資訊,根本與單元測試類毫無關聯,而都是來自maven的程式碼類。

    這時候想起來,maven在執行每個工程的單元測試的時候,它會建立獨立的執行緒去執行它們pom.xml中定義的內容。

    所以我這裡拿到PID,僅僅是maven自身的執行緒資訊,根本拿不到具體工程的執行緒中的方法執行資訊。

 

javaagent模式

    根目錄的pom.xml中我們定義了jmockit的javaagent,用於執行test階段的單元測試mock程式碼之用。配置如下:

 

<project>
    <dependencies>
          ......
    </dependencies>

    <build>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.4.2</version>
          <configuration>
            <argLine>-javaagent:"${settings.localRepository}/com/hugehard/external/test.jmockit/0.997/test.jmockit-0.997.jar"</argLine>
            <junitArtifactName>com.alibaba.external:test.junit</junitArtifactName>
            <testNGArtifactName>com.alibaba.external:test.testng.jdk15</testNGArtifactName>
          </configuration>
          <executions>
            <execution>
              <goals>
                <goal>test</goal>
              </goals>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </build>
</project>
 

 

    這讓我想起來,btrace也是有agent模式的,可以讓它和應用一起啟動。

    這樣每次maven建立新執行緒來執行單元測試的時候,會否也讓btrace一起啟動了呢?

 

    參考官方文件,修改argLine配置如下:

<argLine>-javaagent:"${settings.localRepository}/com/hugehard/external/test.jmockit/0.997/test.jmockit-0.997.jar" -javaagent:/tmp/hudson-optimize/credit-shared-1/btrace-agent.jar=script=/tmp/hudson-optimize/BtraceHudson.class,scriptOutputFile=/tmp/hudson-optimize/btrace.${pom.artifactId}</argLine>
 

    這裡需要說明一下:

1、javaagent模式下,需要預編譯btrace類

(詳細請參考 http://kenai.com/projects/btrace/pages/UserGuide#precompile

 

  所以我們需要用如下指令先編譯我們們的BtraceHudson.java

 

/work/ide/btrace/btrace-bin/bin/btracec -cp . BtraceHudson.java
 

而後會得到編譯好的類 BtraceHudson.class。

 

2、javaagent中,請確保給出的btrace-agent.jar所在的目錄中也包括了btrace-boot.jar, btrace-client.jar這兩個包。

 

3、我們可以在scriptOutputFile中指定btrace的輸出結果重定向到我們希望拿到報告的位置。

 

4、另外,這裡使用的${pom.artifactId} 是為了每個pom.xml對應的工程在執行單元測試的時候,它們所生成的btrace報告不會互相覆蓋。

 

接著像我們往常一樣,執行“mvn clean test”指令,就能在我們們指定的目錄中檢視btrace報告,而後對它進行分析,找出執行效率低下的單元測試了。

 

== 全文完 ==

相關文章