달력

52024  이전 다음

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

드뎌 등록됐습니다. 

http://visualvm.java.net/docindex.html


이젠 틈틈히 나머지 페이지들 번역하는 일만 남았네요. ^^




Posted by fromm0
|

오늘 아침에 회신이 왔네요. 

visualvm.java.net에 올려줄수 있는데 한국어를 나타내는 작은 이미지 아이콘을 달라고 합니다. 

Hi DongGuk,

thanks for your contribution! We can copy the translated pages to visualvm.java.net.

Can you please provide an image for the translated version similar to the Japanese and Chinese ones displayed athttp://visualvm.java.net/docindex.html? I mean http://visualvm.java.net/ja/images/japanese.png or http://visualvm.java.net/zh_CN/images/simplified_chinese.png. It doesn't have to look exactly the same, we just need an image to make sure it displays correctly in all browsers.

Thanks,
Jiri


그래서 함께 일하시는 분에게 부탁해서 급조했습니다. 

조만간 등록되면 나머지도 시간날때 하나씩 해서 등록해달라고 해야 겠네요.. 

영작은 참 어려워요.. T.T











Posted by fromm0
|

요즘 성능얘기 많이 쓰게 되네요. ^^

오늘 너무 꿀꿀한 기분에 그냥 정신없이 할일을 찾다보니 어느새 또 번역질을 하고 있더군요.

양이 많지 않구요. 

VisualVM홈페이지에 있는 소개하기와 시작하기 문서입니다. 


2월 25일

Posted by fromm0
|

1) 아파치 서버 설정

<IfModule mod_deflate.c>

AddOutputFilterByType DEFLATE application/json application/javascript

</IfModule>


2) 성능결과


TPS기준으로 하면 2~3개 정도 gzip적용한게 좋다. 

대신 gzip을 해서 컨텐츠를 압축하는 만큼 CPU사용량은 월등이 gzip적용한게 높다. 

대신 네트워크 사용량은 또 그만큼 gzip적용한게 적게 사용한다. 

서버를 최대한 활용하기 위해서는 gzip을 최대한 활용하는게 좋다. 


'성능' 카테고리의 다른 글

[성능] VisualVM 한글문서(일부)  (0) 2013.02.25
[성능] JProfiler 사용법 정리  (0) 2013.02.19
[성능] VisualVM 플러그인 이야기  (0) 2009.01.18
[성능] VisualVM  (2) 2009.01.18
[일상][작성중] Jennifer 4.0 사용기  (0) 2008.12.30
Posted by fromm0
|
# 테스트 환경
1. jdk1.6.0_23
2. 프로파일러 : JProfiler v.5.2.4

# 케이스별 테스트 소스와 프로파일링 결과
1. 모델의 setter메서드로 셋팅
public static JaxbMessage validateUrlParam(BindingResult result) {
    if (result.hasErrors()) {
        JaxbMessage message = getDefaultMessage();
        LOGGER.info("바인딩결과 : {} ", result);

        JaxbError error = new JaxbError();
        final String errorCode = result.getFieldErrors().get(0).getDefaultMessage();
        error.setCode(errorCode);
        error.setMsg(ValidationErrorMessageAccessor.getMessages().get(errorCode));

        LOGGER.info("{}", error);

        message.setError(error);
        return message;
    }
    return null;
}


20번 호출에 15,653us 소요됨

2. Spring의 BeanUtils.getPropertyDescriptors() 메서드와 Java의 리플렉션 사용
public M validateUrlParamOld(M message, E error, String service, String type, String version, BindingResult result) {
    if (result.hasErrors()) {
        LOGGER.info("바인딩결과 : {} ", result);

        final String errorCode = result.getFieldErrors().get(0).getDefaultMessage();
        try {
            PropertyDescriptor[] errorPds = BeanUtils.getPropertyDescriptors(error.getClass());
            for (PropertyDescriptor desc : errorPds) {
                if ("code".equals(desc.getName())) {
                    Method setter = desc.getWriteMethod();
                    setter.invoke(error, errorCode);
                }
                if ("msg".equals(desc.getName())) {
                    Method setter = desc.getWriteMethod();
                    setter.invoke(error, ValidationErrorMessageAccessor.getMessages().get(errorCode));
                }
            }

            PropertyDescriptor[] messagePds = BeanUtils.getPropertyDescriptors(message.getClass());
            for (PropertyDescriptor desc : messagePds) {
                if ("error".equals(desc.getName())) {
                    Method setter = desc.getWriteMethod();
                    setter.invoke(message, error);
                }
                if ("service".equals(desc.getName())) {
                    Method setter = desc.getWriteMethod();
                    setter.invoke(message, service);
                }
                if ("type".equals(desc.getName())) {
                    Method setter = desc.getWriteMethod();
                    setter.invoke(message, type);
                }
                if ("version".equals(desc.getName())) {
                    Method setter = desc.getWriteMethod();
                    setter.invoke(message, version);
                }
            }
        } catch (IllegalArgumentException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }

        return message;
    }
    return null;
}


20번 호출에 21,372us 소요됨

3. Spring의 ReflectionUtils 사용
public M validateUrlParam(M message, E error, String service, String type, String version, BindingResult result) {
    if (result.hasErrors()) {
        LOGGER.info("바인딩결과 : {} ", result);

        final String errorCode = result.getFieldErrors().get(0).getDefaultMessage();
        try {
            ReflectionUtils.invokeMethod(ReflectionUtils.findMethod(error.getClass(), "setCode", String.class), error, errorCode);
            ReflectionUtils.invokeMethod(ReflectionUtils.findMethod(error.getClass(), "setMsg", String.class), error,
                ValidationErrorMessageAccessor.getMessages().get(errorCode));

            ReflectionUtils.invokeMethod(ReflectionUtils.findMethod(message.getClass(), "setError", error.getClass()), message, error);
            ReflectionUtils.invokeMethod(ReflectionUtils.findMethod(message.getClass(), "setService", String.class), message, service);
            ReflectionUtils.invokeMethod(ReflectionUtils.findMethod(message.getClass(), "setType", String.class), message, type);
            ReflectionUtils.invokeMethod(ReflectionUtils.findMethod(message.getClass(), "setVersion", String.class), message, version);
        } catch (IllegalArgumentException e) {
            throw new RuntimeException(e);
        }

        return message;
    }
    return null;
}


20번 호출에 13,008us 소요됨

# 정리
1. 순수하게 JDK의 리플렉션을 사용한 테스트 수치는 없음
2. Spring
ReflectionUtils < 모델 setter 메서드 < Spring의 BeanUtils.getPropertyDescriptors() 메서드와 Java의 리플렉션 순으로 소요시간이 적음
3. 모델 setter 메서드 방식이 가장 빠를 것으로 짐작했으나, 예상과 다른 결과가 나타남. 좀더 테스트가 필요할 것으로 생각됨
Posted by fromm0
|
# 테스트 환경
1. jdk1.6.0_23
2. 프로파일링 옵션 : -Xrunhprof:cpu=samples,file=d:/cpu1.txt,depth=3
runhprof 옵션은 jdk 가 제공하는 기본 프로파일링 기능으로 자세한 내용은 "java -Xrunhprof:help" 명령어를 통해 확인할 수 있음
3. 테스트 항목
- StopWatch 를 사용한 메서드 시작과 종료 직전의 시각을 측정
- runhprof 옵션을 통한 cpu 타임 샘플링

# 테스트 케이스 및 테스트 소스와 소요시간(단위 밀리세컨드)
1. 문자열 연산(O), 10만번, slf4j - 5번 테스트해서 평균 산정
@Test
public void test() {
    StopWatch watch = new StopWatch();
    watch.start();
    for (int i = 0; i < 100000; i++) {
        LOGGER.info("a" + "b" + "c" + "d");
    }
    watch.stop();
    LOGGER.info(String.valueOf(watch.getTotalTimeMillis()));
}

total time, cpu time : 7839, 1170
total time, cpu time : 8288, 1146
total time, cpu time : 8123, 1129
total time, cpu time : 8228, 1180
total time, cpu time : 8093, 1222

2. 문자열 연산(X), 10만번, slf4j - 5번 테스트해서 평균 산정
@Test
public void test() {
    StopWatch watch = new StopWatch();
    watch.start();
    for (int i = 0; i < 100000; i++) {
        LOGGER.info("abcd");
    }
    watch.stop();
    LOGGER.info(String.valueOf(watch.getTotalTimeMillis()));
}

total time, cpu time : 7854, 1132
total time, cpu time : 7920, 1169
total time, cpu time : 8078, 1226
total time, cpu time : 7931, 1153
total time, cpu time : 8072, 1118

# JDK 가 처리하는 문자열 처리 방식이 나뉘네요.
두분이 댓글 달아주신것처럼 추가로 확인해봤습니다. (2011년1월3일 추가)


3. 로그레벨 체크, 10만번, slf4j - 5번 테스트해서 평균 산정
 @Test
public void test() {
    StopWatch watch = new StopWatch();
    watch.start();
    for (int i = 0; i < 100000; i++) {
        if (LOGGER.isInfoEnabled()) {

        }
    }
    watch.stop();
    LOGGER.info(String.valueOf(watch.getTotalTimeMillis()));
}

total time, cpu time : 3, 104
total time, cpu time : 3, 107
total time, cpu time : 4, 103
total time, cpu time : 3, 107
total time, cpu time : 2, 106

4. 로그레벨보다 하위레벨로 로깅(실제로는 찍히지 않는 형태), 10만번, slf4j - 5번 테스트해서 평균 산정
 @Test
public void test() {
    StopWatch watch = new StopWatch();
    watch.start();
    for (int i = 0; i < 100000; i++) {
        LOGGER.debug("abcd");
    }
    watch.stop();
    LOGGER.info(String.valueOf(watch.getTotalTimeMillis()));
}

total time, cpu time : 3, 106
total time, cpu time : 4, 104
total time, cpu time : 3, 105
total time, cpu time : 3, 106
total time, cpu time : 3, 104

5. 문자열 연산(O), 100만번, log4j - 1번 테스트해서 평균 산정
 @Test
public void test() {
    StopWatch watch = new StopWatch();
    watch.start();
    for (int i = 0; i < 1000000; i++) {
        LOGGER.info("a" + "b" + "c" + "d");
    }
    watch.stop();
    LOGGER.info(String.valueOf(watch.getTotalTimeMillis()));
}

total time, cpu time : 74702, 11390

5. 문자열 연산(O), 100만번, slf4j - 1번 테스트해서 평균 산정
 @Test
public void test() {
    StopWatch watch = new StopWatch();
    watch.start();
    for (int i = 0; i < 1000000; i++) {
        LOGGER.info("{}{}{}{}", new Object[] {"a", "b", "c", "d"});
    }
    watch.stop();
    LOGGER.info(String.valueOf(watch.getTotalTimeMillis()));
}

total time, cpu time : 76899, 11532

6. ReflectionToStringBuilder 연산, 10만번, slf4j - 1번 테스트해서 평균 산정
 @Test
public void test() {
    StopWatch watch = new StopWatch();
    watch.start();
    for (int i = 0; i < 100000; i++) {
        LOGGER.debug(ReflectionToStringBuilder.toString(article, ToStringStyle.MULTI_LINE_STYLE));
    }
    watch.stop();
    LOGGER.info(String.valueOf(watch.getTotalTimeMillis()));
}

total time, cpu time : 12985, 2656

# ReflectionToStringBuilder.toString() 처리를 해당 모델 클래스의 toString() 을 오버라이딩하면서 처리하는 것으로 배봤습니다. (2011년1월3일 추가)

# 평균수치(단위 밀리세컨드)
1. 문자열 연산(O), 10만번, slf4j
total time, cpu time : 8114.2, 1169.4

2. 문자열 연산(X), 10만번, slf4j
total time, cpu time : 7971, 1159.6

3. 로그레벨 체크, 10만번, slf4j
total time, cpu time : 3, 105.4

4. 로그레벨보다 하위레벨로 로깅(실제로는 찍히지 않는 형태), 10만번, slf4j
total time, cpu time : 3.2, 105

5. 문자열 연산(O), 100만번, log4j
total time, cpu time : 74702, 11390

5. 문자열 연산(O), 100만번, slf4j
total time, cpu time : 76899, 11532

6. ReflectionToStringBuilder 연산, 10만번, slf4j
total time, cpu time : 12985, 2656

# 정리
- 1, 2번 경우를 볼때, 문자열 연산으로 인한 차이(8114, 7971)가 크지 않은 것 같다.
- 1, 2번 경우는 JDK 컴파일 과정의 최적화 작업으로 성능테스트 결과 차이가 없다.
- Logger로 찍어주는 문자열 자체가 연산에 의해 생성될 경우 LOGGER.isInfoEnabled() 형태로 체크하는 것이 성능상 좋을 수 있다.
- Logger로 찍어주는 문자열 자체가 특별한 연산에 의해 생성되는 경우가 아닐 경우, Logger 자체가 로그 레벨 체크 후 로깅 여부를 판단하는데 LOGGER.isInfoEnabled() 형태로 체크하지 않아도 특별한 성능상의 차이가 발생하지 않을 것으로 보인다.
- 5, 6번 경우를 볼때, log4j와 slf4j의 성능차가 크다고 보기는 어렵다.
- ReflectionToStringBuilder.toString() 처럼 문자열을 생성하는 연산의 비용이 클 경우 LOGGER.isInfoEnabled() 를 사용해서 체크하거나 해당 모델 클래스의 toString을 오버라이드 하고 slf4j 의 파라미터 인자로 처리하면 성능의 이점이 있다.

Posted by fromm0
|

[링크모음] 성능

링크모음 2009. 1. 30. 09:47

'링크모음' 카테고리의 다른 글

[메모] NoSQL  (0) 2010.08.14
[링크모음] Java SE  (0) 2008.11.02
[링크모음] Web Service(SOAP, REST 등)  (0) 2008.11.02
Posted by fromm0
|