C++에서는 잘 만들어 썼었는데, Java 프로그래밍을 하면서도 비슷한 모듈이 있으면 좋겠다는 생각에 만들어 보았습니다.




아래 코드를 보면 코드 실행의 흐름을 판단하기 쉬우며, doSomething이라는 메소드가 각각 수행되는데 걸리는 시간도 어려지 않게 예측할 수 있습니다.


public class Main
{
	static void doSomething(long millis)
	{
		try { Thread.sleep(millis); } catch(Exception e) {}
	}
	
	public static void main(String[] args)
	{
		for (int i = 0; i < 10; i++)
		{
			doSomething(10);
			doSomething(20);
			doSomething(30);
			doSomething(40);
		}
	}
}




하지만, 코드의 양도 많아 지고 분기도 복잡하 지고 하다 보면, 나중에 가서는 어느 부분에서 시간이 많이 걸리는지 코드상으로는 판별하기 어려워 질 수가 있죠. 프로그래머는 어느 부분에서 시간이 많이 걸리는지를 알고 싶어 합니다. 이러한 경우 Performance라는 클래스를 이용하여 코드의 중간중간 수행 시간을 알아 낼 수 있습니다.


1. Performance 클래스의 오브젝트를 생성한다.

2. 코드의 중간중간에 check(int milestone) 메소드를 호출하여 이정표를 남겨 놓는다.

3. 나중에 결과를 알고 싶을 때 report() 메소드를 호출하여 결과를 본다.




상기 코드에서 Performance 클래스를 이용해서 중간중간에 코드를 삽입합니다(빨간색입니다).


public class Main
{
	static void doSomething(long millis)
	{
		try { Thread.sleep(millis); } catch(Exception e) {}
	}
	
	public static void main(String[] args)
	{
		Performance pf = new Performance(); // Performace 객체 생성
		for (int i = 0; i < 10; i++)
		{
			pf.check(1); // 코드 중간중간에 milestone을 남겨 놓음
			doSomething(10);
			pf.check(2); // 코드 중간중간에 milestone을 남겨 놓음
			doSomething(20);
			pf.check(3); // 코드 중간중간에 milestone을 남겨 놓음
doSomething(30); pf.check(4); // 코드 중간중간에 milestone을 남겨 놓음
doSomething(40); } pf.report(); // 마지막에 실행 결과를 출력 } }




실행 결과입니다.


beg end count duration

1 2 10 100371975 // 대략 100 msec (10번 * 10 msec)

4 1 9 360059588 // 대략 360 msec (9번  * 40 msec)

2 3 10 200130182 // 대략 200 msec (10번 * 20 msec)

3 4 10 300004752 // 대략 300 msec (10번 * 30 msec)


1, 2, 3, 4 라는 이정표들 사이에 지나간 횟수와 걸린 시간을 알 수가 있습니다.



verbose 옵션을 true로 해 주면 나중에 무지막지한 결과를 볼 수 있습니다.

Performance pf = new Performance();
pf.verbose = true;
...


beg end duration
1 2 10468510
2 3 20147882
3 4 29898003
4 1 39938107
1 2 10047436
2 3 19971044
3 4 29990334
4 1 39956056
1 2 10048274
2 3 20000517
3 4 29998994
4 1 39990837
1 2 10066363
2 3 19978517
3 4 29979299
4 1 40066894
1 2 9962998
2 3 19980473
3 4 30024765
4 1 40017167
1 2 9967538
2 3 20008130
3 4 30024346
4 1 39947466
1 2 10037309
2 3 19993742
3 4 30041737
4 1 39967510
1 2 10011678
2 3 19966923
3 4 30032727
4 1 40053834
1 2 9994916
2 3 20041793
3 4 29701610
4 1 40233605
1 2 10003087
2 3 20028663
3 4 29999692


이상 허접 클래스 소개를 마칩니다. ^^



[Performance.java 소스 코드]

// ----------------------------------------------------------------------------
//
// VDream Component Suite version 8.0
//
// http://www.gilgil.net
//
// Copyright (c) Gilbert Lee All rights reserved
//
// ----------------------------------------------------------------------------

import java.util.ArrayList;
import java.util.HashMap;

// ----------------------------------------------------------------------------
// PerformanceVerbose
// ----------------------------------------------------------------------------
class PerformanceVerbose
{
	public int  begMilestone;
	public int  endMilestone;
	public long duration;	
}

//----------------------------------------------------------------------------
// PerformanceVerboseList
//----------------------------------------------------------------------------
class PerformanceVerboseList extends ArrayList<PerformanceVerbose>
{
	private static final long serialVersionUID = 1L;
}

//----------------------------------------------------------------------------
// PerformanceReportKey
//----------------------------------------------------------------------------
class PerformanceReportKey
{
	public int begMilestone;
	public int endMileseone;
	
	public int hashCode()
	{
	   return begMilestone + endMileseone;
	}
	
	public boolean equals(Object obj)
	{
		if (obj == null) return false;
		if (obj == this) return true;
		if (!(obj instanceof PerformanceReportKey)) return false;
		
		PerformanceReportKey rhs = (PerformanceReportKey)obj;
		if (this.begMilestone != rhs.begMilestone) return false;
		if (this.endMileseone != rhs.endMileseone) return false;
		
		return true;
	}
}

//----------------------------------------------------------------------------
// PerformanceReportData
//----------------------------------------------------------------------------
class PerformanceReportData
{
	public int  count;
	public long totalDuration;
}

//----------------------------------------------------------------------------
// PerformanceReportMap
//----------------------------------------------------------------------------
class PerformanceReportMap extends HashMap<PerformanceReportKey, PerformanceReportData>
{
	private static final long serialVersionUID = 1L;
}

//----------------------------------------------------------------------------
// Performance
//----------------------------------------------------------------------------
public class Performance
{
	public boolean verbose;
	
	public PerformanceVerboseList  verboseList;
	public PerformanceReportMap    reportMap;
	
	protected int                  lastMilestone;
	protected long                 lastTick;	
	
	public Performance()
	{
		verbose     = false;
		verboseList = new PerformanceVerboseList();
		reportMap   = new PerformanceReportMap();
		clear();
	}
		
	public void report()
	{
		if (verbose)
		{
			System.out.println("beg\tend\tduration");
			for (PerformanceVerbose verbose : verboseList)
			{
				if (verbose.begMilestone == 0) continue;
				System.out.println(String.format("%d\t%d\t%d", verbose.begMilestone, verbose.endMilestone, verbose.duration));
			} 
		} else
		{
			System.out.println("beg\tend\tcount\tduration");
			
			for (PerformanceReportKey key : reportMap.keySet())
			{
				if (key.begMilestone == 0) continue;
				PerformanceReportData data = reportMap.get(key);
				System.out.println(String.format("%d\t%d\t%d\t%d", key.begMilestone, key.endMileseone, data.count, data.totalDuration));
			}
		}
	}
	
	public void clear()
	{
		verboseList.clear();
		reportMap.clear();
		lastMilestone = 0;
		lastTick      = System.nanoTime();
	}
	
	public void check(int milestone)
	{
		check(milestone, System.nanoTime());
	}
	
	public void check(int milestone, long now)
	{
		if (verbose)
		{
			PerformanceVerbose verbose = new PerformanceVerbose();
			verbose.begMilestone = lastMilestone;
			verbose.endMilestone = milestone;
			verbose.duration     = now - lastTick;
			verboseList.add(verbose);
		} else
		{
			PerformanceReportKey key = new PerformanceReportKey();
			key.begMilestone = lastMilestone;
			key.endMileseone = milestone;

			PerformanceReportData data = reportMap.get(key);
			if (data == null)
			{
				data = new PerformanceReportData();
				reportMap.put(key, data);
			}
			data.count++;
			data.totalDuration += now - lastTick;
		}
		lastMilestone = milestone;
		lastTick      = now;
	}
}




[다운로드]