2017-08-29 8 views
0

Springのいくつかのタスクのパフォーマンス統計を測定したいと思います。これらのパフォーマンス統計には、データベースクエリに必要な時間を含めるべきではありません。したがって私はDAOメソッドをSpring AOPの側面で傍受します。この方法では、タスクの測定を停止し、データベース呼び出しの測定を開始します。両方の測定が動作します問題は、CPU & ThreadMXBeanによって取得されたユーザー時間は、異なる測定セクションの1つの間に増加しないことがあります。これらのセクションでは、私はA)DBコール前のタスクの測定、B)DBコールの測定、およびC)DBコール後のタスクの測定を意味します。私は各セクションについて合理的な測定値を得ましたが、同時に3つすべてについては測定しませんでした。少なくとも1人(ランダムに見えるように)は、CPU時間の増加を示さないと思われる&ユーザ時間。私は一般的なセットアップがを作品言ったようにAOPを使ってSpringでThreadMXBeanと0のランダムに測定されたCPUとユーザーの時間差

@Api 
@Path("task1") 
@Consumes(MediaType.APPLICATION_JSON) 
@Produces(MediaType.APPLICATION_JSON) 
public class task1Resource { 

    @Autowired 
    private MeasurementService measurementService; 

    @POST 
    public Response startTask(...){ 
     measurementService.start("task1", false); 
     //Transactional service methods with the business logic for task1  
     //are called 
     measurementService.end("task1"); 
     return Response.ok(entity).build(); 
    } 
} 

@Service 
@Transactional 
public class MeasurementService { 

    @Autowired 
    private MeasurementDAO measurementDao 

    public void start(String task, boolean interrupted){ 
     MeasurementObject measurementObj = new MeasurementObject(); 
     ThreadMXBean mxBean = ManagementFactory.getThreadMXBean(); 
     if(interrupted){ 
      //Get the previously persisted measurement object for the task 
      measurementObj = measurementDao.get(task); 
      //Calculate the differences with the values of the previous section 
      measurementObj.calcCpuTimeDifference(mxBean.getCurrentThreadCpuTime(); 
      measurementObj.calcUserTimeDifference(mxBean.getCurrentThreadCpuTime(); 
     }else{ 
      //Initialize 
      measurementObj.setTask(task); 
      Set<DAOMeasurement> daoCalls = new HashSet<DAOMeasurement>(); 
      measurementObj.setDaoCalls(daoCalls); 
      Thread currentThread = Thread.currentThread(); 
      measurementObj.setThread(currentThread); 
      measurementObj.setCpuTime(mxBean.getCurrentThreadCpuTime); 
      measurementObj.setUserTime(mxBean.getCurrenThreadUserTime); 
     } 
     measurementDao.save(measurementObj); 
    } 

    public MeasurementObject end(String task){ 
     //Get the measurement object for the task 
     MeasurementObject measurementObj = measurementDao.get(task); 
     ThreadMXBean mxBean = ManagementFactory.getThreadMXBean(); 
     //Calculate the differences with the values from the start 
     //or the previously calculated differences 
     measurementObj.calcCpuTimeDifference(mxBean.getCurrentThreadCpuTime()); 
     measurementObj.calcUserTimeDifference(mxBean.getCurrentThreadUserTime()); 
     return measurementDao.save(measurementObj); 
    } 
} 

@Aspect 
@Component 
public class daoAspect { 

    @Autowired 
    private MeasurementService measurementService; 

    @Autowired 
    private DAOMeasurementService daoMeasurementService; 

    @Before("daoMethods() && !measurementMethods()") 
    private void start(Joinpoint jopo){ 
     Thread currentThread = Thread.currentThread(); 
     //Get the task measurement object that was started in the same thread 
     MeasurementObject measurementObj = measurementService.byThread(currentThread); 
     measurementObj = measurementService.end(measurementObj.getTask()); 
     //Start the measurement for the DB call 
     DAOMeasurementObject daoMeasurementObj = daoMeasurementService.start(measurementObj); 
    } 

    @After("daoMethods() && !measurementMethods()") 
    private void end(Joinpoint jopo){ 
     Thread currentThread = Thread.currentThread(); 
     /*Please assume here that we only have one dao method 
     * (In my more complex case I query the database for 
     * the correct daoMeasurementObject by using additional parameters)    
     * So here we find the DB call measurement object that was started 
     * in this thread and end it. */ 
     DAOMeasurementObject daoMeasurementObj = daoMeasurementService.byThread(currentThread); 
     daoMeasurementService.end(daoMeasurementObj); 
     //We get the task measurement object for this thread and start it again 
     MeasurementObject measurementObj = measurementService.byThread(currentThread); 
     measurementService.start(measurementObj.getTask(),true); 
    } 

    @Pointcut("execution(* com.foo.bar.dao.*(..))") 
    public void daoMethods(){} 

    @Pointcut("@annotation(Measurement)") 
    public void measurementMethods(){} //I annotated the measurement dao classes with this annotation 
} 

@Service 
@Transactional 
public class DAOMeasurementService { 
    /*This class is identical to the MeasurementService class with the 
    * difference that a DAOMeasurementObject gets a MeasurementObject 
    * reference. But the cpu-&user-times are calculated in the same manner */ 
} 

:以下で

は私の問題のケースを視覚化するいくつかのサンプルコードです。タスク測定は、想定されるように開始および終了し、その間のDAOメソッドはアスペクトによって中断されます。また、私はときどき正しい値を得るので、測定は適切に機能しているようです。 唯一の問題は、しばしばCPU-&ユーザ倍私はさらに0

で算出された差分値をもたらすそれらの端に3つの測定値のセクションの一つまたは二つの先頭から変化しないということですこれらのメソッドのすべてが同じにThread.currentThread()ThreadMXBean.isCurrentThreadCpuTimeSupported()ThreadMXBean.isThreadCpuTimeEnabled()リターンすべての測定点でを持っていることを確認しました。

私は本当にいくつかのヘルプやヒントをお待ちしています!さらにコードや情報が必要な場合は、お気軽にリクエストしてください。

更新:

私が代わりに@Before@After側面の@Around側面とし、複数回実行してシステムをテストしました。結果は変わりません。 ThreadMXBean.getCurrentThreadCpuTimeThreadMXBean.getCurrentThreadUserTimeの値は、測定フェーズの1〜2の間に無作為に増加するのではなく、それらの間で増加します。例:フェーズA)、タスクの開始時の測定値は280801800のCPU時間と265201700のユーザー時間を示し、この測定値がDAOインターセプト中に停止されると、CPU時間280801800とユーザーDAOメソッドの測定の段階では、296401900のCPU時間と280801800のユーザー時間を示します。しかし、DAOメソッド測定の最後には、 296401900の同じCPU時間と280801800の同じユーザー時間。完全なフェーズC)の間、時間はB)と同じままです。

- > ThreadMXBeanは、メソッドが呼び出されたときではなく、ある間隔で統計情報のみを更新することができますか?現時点で測定しようとしているフェーズは比較的短く、LocalDateTimeを使用して1〜10ミリ秒の期間があります。

答えて

0

アップデート2 &答え:

答えがThreadMXBeanアップデート定期的に、私の方法はThreadMXBeanは、その実行時に更新されなかったほど速く走ることということであるようです。

これは、各測定の開始と終了の間にThread.sleep(200);コマンドを挿入することでこれをテストしました。その結果、測定したい各セクションのCPU時間とユーザー時間の値が更新されました。

アップデート3:私はそれはスレッドが測定の間で動作時間の問題だけではないことに気づき、さらに試行後

わかりました。 私は、測定しようとしているフェーズが、ThreadMXBeanによって正しく測定されるのに十分なCPU-&ユーザ時間を消費するようです。 3つのフェーズの中でランダムなデータベースクエリを追加しました。測定はうまくいくように見えますが、ランダムな測定上の問題がありました。私は、より多くの作業負荷(消費されたCPU時間-ユーザ時間)とThread.sleep(X)の組み合わせで最良の測定結果を得ているようです。

しかし、これは本当に満足できるものではありません。 ThreadMXBeanがどれくらい正確に測定されたか、または更新されたかについての詳しい情報は、チャンスを持つ人は誰にもありますか?どのように私はそれを見つけることができる任意のアイデアか?

関連する問題