타사 라이브러리에서 데이터를 가져 오는 시간에 민감한 응용 프로그램이 있습니다. 내 애플리케이션에 적합한 인터페이스로 오브젝트를 래핑하는 것과 관련된 성능 적중률은 무엇입니까?오브젝트를 래핑 할 때 실제 오버 헤드는 얼마입니까?
참고 : 여기에 답변을 게시하고 있습니다 (Q & A 스타일). 틀렸을 경우 나에게 수정하십시오.
타사 라이브러리에서 데이터를 가져 오는 시간에 민감한 응용 프로그램이 있습니다. 내 애플리케이션에 적합한 인터페이스로 오브젝트를 래핑하는 것과 관련된 성능 적중률은 무엇입니까?오브젝트를 래핑 할 때 실제 오버 헤드는 얼마입니까?
참고 : 여기에 답변을 게시하고 있습니다 (Q & A 스타일). 틀렸을 경우 나에게 수정하십시오.
이 있어요 - 여기에 결과 모든 실제로 일치하지 않는, 여기에서 실제로 느려질 것을 풀어왔다이다 간접비가있는 일부 오버 헤드가 있지만 측정하기가 어렵습니다. OP의 벤치 마크는 반복 당 약 4 ns가 소요되는 반면, 광산은 약 1 ns (가장 빠른 실험을 위해)가 필요합니다. 이것은 가상 호출 오버 헤드와 함께 대부분 ArrayList
, Iterator
및 cycle
의 오버 헤드를 측정하고 있음을 의미합니다.
측정 할 오버 헤드가 너무 작기 때문에 배열을 사용하고 내부 루프를 추가하거나 액세스 할 때 마스킹을 사용해야합니다.
내 benchmark의 results은 인터페이스와 간접 지정을 사용하여 측정 가능한 오버 헤드가 있음을 보여줍니다. 이 오버 헤드는 아마도 20 %에서 50 %까지 다양합니다. 그러나 중요한 부분은의 20-50 % 입니다. 이것은 코드를 실행하는 것 외에 특별히 제작 된 벤치 마크의 일부분입니다. 현실적인 조각 코드에서 상대 오버 헤드는 10 배, 100 배 또는 1000 배 낮아집니다.
아주 기본적인 작업과 빠른 작업을 수행하는 고성능 라이브러리를 디자인하지 않는 한 잊어 버리십시오. 간접 사용과 인터페이스를 마음대로 사용하고 좋은 디자인에 집중하십시오. 성능이 중요하더라도 더 많이 얻을 수있는 다른 장소가있을 것입니다.
나는 오버 헤드가 절대적인 것보다는 백분율 이상으로 중요하다고 생각한다. 마지막 단락에서 이유를 설명합니다. 제 답변에 동의 해 주셔서 감사합니다. 내 응용 프로그램에서 성능이 매우 중요하지만 중요한 성능 손실이 걱정없이 데이터 피드를 래핑하지 않아서 벽을 상대로 머리를 때리는 것을 멈출 수 있다는 것을 알게되어 기쁩니다. – durron597
몇 달 동안 수업을 진행 하려다가 오늘 시험을보기로 결심했습니다. 어떤 오버 헤드라도 추가하지 않는 것 같습니다.
0% Scenario{vm=java, trial=0, benchmark=Unwrapped} 3.96 ns; ?=0.02 ns @ 3 trials
33% Scenario{vm=java, trial=0, benchmark=Copy} 3.93 ns; ?=0.01 ns @ 3 trials
67% Scenario{vm=java, trial=0, benchmark=Backing} 3.94 ns; ?=0.01 ns @ 3 trials
benchmark ns linear runtime
Unwrapped 3.96 ==============================
Copy 3.93 =============================
Backing 3.94 =============================
vm: java
trial: 0
소스 코드 (캘리퍼스 0.5 RC1, 구아바 2.0 이상) :
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import com.google.caliper.Runner;
import com.google.caliper.SimpleBenchmark;
import com.google.common.collect.Iterables;
public class WrapperTest {
public static class Unwrapped {
private int inner;
public Unwrapped(int inner) {
this.inner = inner;
}
public int getInner() {
return inner;
}
}
public static interface Outer {
public int getOuter();
}
public static class CopyOuter implements Outer {
private int outer;
public CopyOuter(int outer) {
this.outer = outer;
}
public int getOuter() {
return outer;
}
}
public static class BackingOuter implements Outer {
private Unwrapped inner;
public BackingOuter(Unwrapped inner) {
this.inner = inner;
}
public int getOuter() {
return inner.getInner();
}
}
public static class TestBenchmark extends SimpleBenchmark {
private Iterable<Unwrapped> cycle;
@Override
protected void setUp() {
List<Unwrapped> backing = new ArrayList<Unwrapped>(16384);
Random r = new Random();
for(int i = 0; i < 16384; i++) {
backing.add(new Unwrapped(Math.abs(r.nextInt())));
}
cycle = Iterables.cycle(backing);
}
public long timeUnwrapped(int reps) {
long total = 0;
Iterator<Unwrapped> iter = cycle.iterator();
for(int i = 0; i < reps; i++) {
total += iter.next().getInner();
}
return total;
}
public long timeCopy(int reps) {
long total = 0;
Iterator<Unwrapped> iter = cycle.iterator();
for(int i = 0; i < reps; i++) {
total += new CopyOuter(iter.next().getInner()).getOuter();
}
return total;
}
public long timeBacking(int reps) {
long total = 0;
Iterator<Unwrapped> iter = cycle.iterator();
for(int i = 0; i < reps; i++) {
total += new BackingOuter(iter.next()).getOuter();
}
return total;
}
}
public static void main(String[] args) {
Runner.main(TestBenchmark.class, new String[0]);
}
}
나는 벤치 마크가 너무 정확해서 3.93이 3.96보다 실제로 빠르다고 말할 수 없다고 생각한다. 나는 측정 오류가 일반적으로 5 % 정도이고 아마도 '주기'와 같은 것이 실행 시간을 지배하기 때문에 귀하의 경우에 더 많은 것 같아요. 또한 마이크로 벤치 마크에서의 성능과 실제 애플리케이션에서의 성능 간의 차이가 더 커질 수 있습니다. – maaartinus
여러 번 실행되는 사소한 메서드를 래핑하지 않는 한 래핑하는 데 신경 쓰지 않을 것입니다. 나는 JIT가 비용의 상당 부분을 최적화 할 수 있다고 생각한다. – maaartinus
@maaartinus 답장을 보내 주셔서 감사합니다. 네, 3.93이 3.96과 거의 같다고 생각합니다. 주기적인 iterable 생성은'setUp'에서 일어나므로 실행 시간에는 영향을 미치지 않습니다. 나는 단지 IndexOutOfBounds 예외가 없도록하기 위해 그것을했다. – durron597
이는 포장의 종류에 따라 달라집니다. – Raedwald