为啥探查器看不到一种耗时的方法?
Posted
技术标签:
【中文标题】为啥探查器看不到一种耗时的方法?【英文标题】:Why doesn't profiler see one of time-consuming methods?为什么探查器看不到一种耗时的方法? 【发布时间】:2014-11-10 09:07:44 【问题描述】:我正在尝试剖析多维数组类的两种实现思路。
在下面的代码中,应用程序创建了三个类的巨大多维数组:Array1
、Array2
和常规。
应用程序首先创建数组,这是不被测量的。然后它填充每个数组并按顺序读取每个数组。时间测量以编程方式和通过分析器进行。
很遗憾,部分时间不一致。比如 Array2 中消耗近一半时间的方法或类,在 profiler 中根本就没有列出来。
为什么?
主要代码:
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");
Array1 代码:
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);
Array2 代码:
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;
结果:
【问题讨论】:
【参考方案1】:您似乎有第一次和第四次运行的子呼叫配置文件,第二次和第五次运行的单个呼叫配置文件,第三次和第六次运行没有呼叫;这些对应于 Array1、Array2 和内置数组的数组访问。 (您可以调用 $1.run、$2.run、$4.run 和 $5.run,但没有调用 $3.run 和 $6.run)
所以对于你的三个案例,我猜第一个没有内联调用,第二个它内联了对 runnable 的调用下面的所有内容,第三次它只看到 runnable 中的简单代码,所以它内联了下面的所有内容 test (您的打印时间总计 101.36s 与 profiler 在测试中的 101,373ms 一致)。
在对 java 进行微基准测试时,有一些常见的方法可以忽略预热结果,this answer 中有一些很好的建议。
【讨论】:
抱歉什么是“子呼叫配置文件”以及如何拥有或不拥有它们? 在您的屏幕截图中,您有显示该呼叫的配置文件(总时间/%)的树,在其中一些下,例如 $1.run,您有在该呼叫中进行的下属呼叫的配置文件,而对于 $2.run,您没有此类从属呼叫配置文件。以上是关于为啥探查器看不到一种耗时的方法?的主要内容,如果未能解决你的问题,请参考以下文章
当我不创建任何 char[] 实例时,为啥探查器会显示大量实例?