2014-11-10 7 views
2

다차원 배열 클래스의 두 가지 구현 아이디어를 프로파일 링하려고합니다.프로파일 러에 시간이 많이 걸리는 방법 중 하나가 표시되는 이유는 무엇입니까?

아래 코드에서 응용 프로그램은 Array1, Array2 및 일반 3 개의 클래스로 구성된 거대한 다차원 배열을 만듭니다.

응용 프로그램은 먼저 측정되지 않는 배열을 만듭니다. 그런 다음 각 배열을 채우고 각 배열을 순서대로 읽습니다. 시간 측정은 프로그래밍 방식으로나 프로파일 러에 의해 수행됩니다.

불행히도 섹션 타이밍이 일치하지 않습니다. 예를 들어 거의 절반의 시간을 소비하는 메서드 또는 클래스 Array2는 프로파일 러에 전혀 나열되지 않습니다.

왜?

주 코드 :

package tests; 

public class Runner01 { 

    private static final int[] dims = {400, 100, 20, 300}; 
    static private double[] data; 

    static private Array1 array1; 
    static private Array2 array2; 
    static private double[][][][] array3; 

    public static interface MyRunnable { 

     public void run(int ii, int i, int j, int k, int l); 
    } 

    public static long test(MyRunnable runnable) { 
     long start = System.nanoTime(); 
     int ii = 0; 
     for (int i = 0; i < dims[0]; ++i) { 
      for (int j = 0; j < dims[1]; ++j) { 
       for (int k = 0; k < dims[2]; ++k) { 
        for (int l = 0; l < dims[3]; ++l) { 
         runnable.run(ii, i, j, k, l); 
         ii++; 
        } 
       } 
      } 
     } 
     long end = System.nanoTime(); 
     System.out.println("Done in " + (double) (end - start)/1000000000 + " seconds"); 
     return end - start; 
    } 

    public static void main(String[] args) { 

     int ii; 
     long start, end, elapsed; 

     start = System.nanoTime(); 

     System.out.println("Filling..."); 

     int size = 1; 
     for (int i = 0; i < dims.length; ++i) { 
      size *= dims[i]; 
     } 

     data = new double[size]; 
     for (int i = 0; i < data.length; ++i) { 
      data[i] = Math.random(); 
     } 

     array1 = new Array1(dims); 
     array2 = new Array2(dims); 
     array3 = new double[dims[0]][dims[1]][dims[2]][dims[3]]; 

     System.out.println("Done."); 

     System.out.println("Writing array1..."); 
     test(new MyRunnable() { 
      @Override 
      public void run(int ii, int i, int j, int k, int l) { 
       array1.set(data[ii], i, j, k, l); 
      } 
     }); 

     System.out.println("Writing array2..."); 
     test(new MyRunnable() { 
      @Override 
      public void run(int ii, int i, int j, int k, int l) { 
       array2.set(data[ii], i, j, k, l); 
      } 
     }); 

     System.out.println("Writing array3..."); 
     test(new MyRunnable() { 
      @Override 
      public void run(int ii, int i, int j, int k, int l) { 
       array3[i][j][k][l] = data[ii]; 
      } 
     }); 

     System.out.println("Reading array1..."); 
     test(new MyRunnable() { 
      @Override 
      public void run(int ii, int i, int j, int k, int l) { 
       assert (data[ii] == array1.get(i, j, k, l)); 
      } 
     }); 

     System.out.println("Reading array2..."); 
     test(new MyRunnable() { 
      @Override 
      public void run(int ii, int i, int j, int k, int l) { 
       assert (data[ii] == array2.get(i, j, k, l)); 
      } 
     }); 

     System.out.println("Reading array3..."); 
     test(new MyRunnable() { 
      @Override 
      public void run(int ii, int i, int j, int k, int l) { 
       assert (array3[i][j][k][l] == data[ii]); 
      } 
     }); 

     end = System.nanoTime(); 
     elapsed = end - start; 

     System.out.println("Total application time is " + (double) (end - start)/1000000000 + " seconds"); 

    } 

} 

배열 1 코드 :

package tests; 

public class Array1 { 

    private Object delegate; 

    private Object allocate(Object delegate, int[] is, int pos) { 
     if (pos < is.length) { 
      delegate = new Object[is[pos]]; 
      for (int k = 0; k < is[pos]; ++k) { 
       ((Object[]) delegate)[k] = allocate(((Object[]) delegate)[k], is, pos + 1); 
      } 
     } 
     return delegate; 
    } 

    private Object get(Object delegate, int[] is, int pos) { 
     if (pos < is.length) { 
      Object subdelegate = ((Object[]) delegate)[is[pos]]; 
      return get(subdelegate, is, pos + 1); 
     } else { 
      return delegate; 
     } 
    } 

    private void set(Object delegate, int[] is, int pos, double value) { 
     if (pos < is.length - 1) { 
      Object subdelegate = ((Object[]) delegate)[is[pos]]; 
      set(subdelegate, is, pos + 1, value); 
     } else { 
      ((Object[]) delegate)[is[pos]] = value; 
     } 
    } 

    public Array1(int... is) { 
     delegate = allocate(delegate, is, 0); 
    } 

    public double get(int... is) { 
     return (double) get(delegate, is, 0); 
    } 

    public void set(double value, int... is) { 
     set(delegate, is, 0, value); 
    } 

} 

배열 2 코드 :

package tests; 

public class Array2 { 

    private double[] delegate; 
    private int[] pows; 

    public Array2(int... is) { 

     pows = new int[is.length]; 

     int size = 1; 
     for (int k = 0; k < is.length; ++k) { 
      pows[k] = size; 
      size *= is[k]; 
     } 

     delegate = new double[size]; 
    } 

    public double get(int... is) { 
     int pos = 0; 

     for (int k = 0; k < is.length; ++k) { 
      pos += is[k] * pows[k]; 
     } 

     return delegate[pos]; 
    } 

    public void set(double value, int... is) { 
     int pos = 0; 

     for (int k = 0; k < is.length; ++k) { 
      pos += is[k] * pows[k]; 
     } 

     delegate[pos] = value; 
    } 

} 

그 결과

enter image description here

답변

0

첫 번째 및 네 번째 실행에 대한 하위 호출 프로필, 두 번째 및 다섯 번째 실행에 대한 단일 호출 프로필 및 세 번째 및 여섯 번째 실행에 대한 호출이없는 것 같습니다. 이는 Array1, Array2 및 내장 배열 배열 액세스에 해당합니다. ($ 1.run, $ 2.run, $ 4.run 및 $ 5.run은 호출했지만 $ 3.run 및 $ 6.run은 호출하지 않음)

세 가지 경우에 대해 첫 번째 호출에는 인라인 호출이 없음을 알 수 있습니다. 두 번째는 runnable에 대한 호출보다 아래의 모든 것을 인라인하고, 세 번째는 runnable 내부에서 간단한 코드 만 보게되므로 테스트 아래의 모든 것을 인라인으로 나타냅니다 (인쇄 된 시간의 합계 101.36s는 프로파일 러의 101,373ms와 일치 함).

this answer에 대한 좋은 조언과 함께 Java를 마이크로 벤치마킹 할 때 워밍업 결과를 무시하는 일반적인 방법이 있습니다.

+0

"서브 콜 프로파일"이란 무엇이며, 서브 콜 프로파일이란 무엇일까요? –

+0

스크린 샷에서 해당 통화에 대한 프로필 (총 시간/%)을 보여주는 트리가 있고 그 중 일부는 $ 1.run과 같이 호출 할 때 부차적 인 통화에 대한 프로필을 가지고 있습니다. 반면에 $ 2.run 그런 부차적 인 전화 프로파일이 없다. –