繁体   English   中英

为什么探查器看不到其中一种耗时的方法?

[英]Why doesn't profiler see one of time-consuming methods?

我正在尝试剖析多维数组类的两个实现思想。

在下面的代码中,应用程序创建了一个巨大的多维数组,该数组包含三个类: Array1Array2和常规。

应用程序首先创建未测量的数组。 然后,它填充每个数组并按顺序读取每个数组。 时间测量既可以通过编程方式进行,也可以通过探查器进行。

不幸的是,节的时间安排不是一致的。 例如,在探查器中根本没有列出消耗将近一半时间的方法或类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");

    }

}

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;
    }

}

结果:

在此处输入图片说明

您似乎具有第一和第四次运行的子呼叫配置文件,第二和第五次运行的单个呼叫配置文件,第三和第六次运行没有任何呼叫; 这些对应于Array1,Array2和内置的数组数组访问。 (您可以调用$ 1.run,$ 2.run,$ 4.run和$ 5.run,但没有$ 3.run和$ 6.run)

因此,对于您的三种情况,我猜第一种情况没有内联调用,第二种情况是对可运行对象的调用下的所有内容进行内联,第三种情况是在可运行对象内部仅看到简单的代码,因此它对测试下的所有内容进行内联(总计的打印时间中的101.36s与测试中分析器的101,373ms一致)。

有一些常见的方法可以在对Java进行微基准测试时忽略预热结果,并在此答案中提供了一些好的建议。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM