Android: Сколько накладных расходов генерируется бегом пустой метод?

StackOverflow https://stackoverflow.com/questions/4345845

Вопрос

Я создал класс, чтобы обрабатывать свои выходы отладки, чтобы мне не нужно раскрывать все мои выходы журнала до выпуска.

public class Debug {
    public static void debug( String module, String message) {
        if( Release.DEBUG )
            Log.d(module, message);
    }
}

Прочитав другой вопрос, я узнал, что содержимое утверждения IF не скомпилировано, если константы Release.debug является ложным.

То, что я хочу знать, сколько накладных расходов генерируется, запустив этот пустой метод? (После того, как пункт IF будет удален, в способе не остается кода). Это будет какое-либо влияние на мое приложение? Очевидно, что производительность - это большая проблема при написании мобильных телефонов = P

Спасибо

Барас

Это было полезно?

Решение

Измерения, сделанные на Nexus S с Android 2.3.2:

10^6 iterations of 1000 calls to an empty static void function: 21s  <==> 21ns/call
10^6 iterations of 1000 calls to an empty non-static void function: 65s  <==> 65ns/call

10^6 iterations of 500 calls to an empty static void function: 3.5s  <==> 7ns/call
10^6 iterations of 500 calls to an empty non-static void function: 28s  <==> 56ns/call

10^6 iterations of 100 calls to an empty static void function: 2.4s  <==> 24ns/call
10^6 iterations of 100 calls to an empty non-static void function: 2.9s  <==> 29ns/call

контроль:

10^6 iterations of an empty loop: 41ms <==> 41ns/iteration
10^7 iterations of an empty loop: 560ms <==> 56ns/iteration
10^9 iterations of an empty loop: 9300ms <==> 9.3ns/iteration

Я повторил измерения несколько раз. Никаких существенных отклонений не найдено. Вы можете видеть, что стоимость каждого звонка может сильно варьироваться в зависимости от рабочей нагрузки (возможно, из-за составления JIT), но можно нарисовать 3 вывода:

  1. Dalvik / Java отстой в оптимизации мертвого кода

  2. Статические вызовы функций могут быть оптимизированы намного лучше, чем нестатические (нестатические функции являются виртуальными и должны смотреть в виртуальную таблицу)

  3. Стоимость на Nexus S не превышает 70ns / Call (вот ~ 70 циклов ЦП) и сопоставима со стоимостью одного пустого для итерации петли (то есть одному приращению и одному контролю на локальной переменной)

Соблюдайте, что в вашем случае строковый аргумент всегда будет оценен. Если вы делаете строковые конкатенации, это включает создание промежуточных строк. Это будет очень дорого и включает много GC. Например, выполнение функции:

void empty(String string){
}

называется аргументами, такими как

empty("Hello " + 42 + " this is a string " + count );

10 ^ 4 итерации 100 таких звонков занимают 10. Это 10US / CALL, т.е. ~ 1000 раз медленнее, чем просто пустой звонок. Это также производит огромное количество активности GC. Единственный способ избежать этого - вручную вписать функцию, то есть используйте оператор >>, если << вместо вызова функции отладки. Это безобразно, но единственный способ сделать это работать.

Другие советы

Если вы не назовите это из глубоко вложенного цикла, я бы не беспокоился об этом.

Хороший компилятор удаляет весь пустой метод, что приведет к отсутствию накладных расходов. Я не уверен, что компилятор Dalvik уже делает это, но я подозреваю, что вполне вероятно, по крайней мере, по прибытии состоится со временного компилятора с Froyo.

Смотрите также: Встроенная экспансия

С точки зрения производительности накладные расходы генерации сообщений, которые передаются в функцию отладки, будут намного серьезнее, так как его вероятно, что они делают ассигнования памяти, например,

Debug.debug(mymodule, "My error message" + myerrorcode);

Что все еще произойдет даже через сообщение. К сожалению, вам действительно нужен «если (Release.Debug)» вокруг вызовов к этой функции, а не внутри самой функции, если ваша цель - производительность, и вы увидите это во многих Android Code.

Это интересный вопрос, и мне нравится @misiu_mp Анализ, поэтому я подумал, что я буду обновлять его с тестом на 2016 год на Nexus 7 Runing Android 6.0.1. Вот тестовый код:

public void runSpeedTest() {
    long startTime;
    long[] times = new long[100000];
    long[] staticTimes = new long[100000];
    for (int i = 0; i < times.length; i++) {
        startTime = System.nanoTime();
        for (int j = 0; j < 1000; j++) {
            emptyMethod();
        }
        times[i] = (System.nanoTime() - startTime) / 1000;
        startTime = System.nanoTime();
        for (int j = 0; j < 1000; j++) {
            emptyStaticMethod();
        }
        staticTimes[i] = (System.nanoTime() - startTime) / 1000;
    }
    int timesSum = 0;
    for (int i = 0; i < times.length; i++) { timesSum += times[i]; Log.d("status", "time," + times[i]); sleep(); }
    int timesStaticSum = 0;
    for (int i = 0; i < times.length; i++) { timesStaticSum += staticTimes[i]; Log.d("status", "statictime," + staticTimes[i]); sleep(); }
    sleep();
    Log.d("status", "final speed = " + (timesSum / times.length));
    Log.d("status", "final static speed = " + (timesStaticSum / times.length));
}

private void sleep() {
    try {
        Thread.sleep(10);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

private void emptyMethod() { }
private static void emptyStaticMethod() { }

То sleep() был добавлен, чтобы предотвратить переполнение Log.d буфер.

Я играл с ним много раз, и результаты были довольно согласованы с @misiu_mp:

10^5 iterations of 1000 calls to an empty static void function: 29ns/call
10^5 iterations of 1000 calls to an empty non-static void function: 34ns/call

Вызов статического метода всегда был немного быстрее, чем нестатический вызов метода, но казалось бы, что а) разрыв значительно закрылся, поскольку Android 2.3.2 и B) все еще есть затраты для создания вызовов в пустой метод, статический или нет.

Глядя на гистограмму раз раскрывает что-то интересное. Большинство звонков, будь то статические или нет, взять на 30-40 нс, и внимательно смотрите на данные, которые они практически все 30ns.

enter image description here

Запуск того же кода с пустыми петлями (комментирование вызовов метода) создает среднюю скорость 8ns, однако около 3/4 измеренного времени составляет 0ns, в то время как остальные имеют ровно 30ns.

Я не уверен, как объяснить эти данные, но я не уверен, что выводы ISIU_MP все еще держатся. Разница между пустыми статическими и нестатическими методами незначительна, а преобладание измерений составляют ровно 30ns. Это, как говорят, появилось бы, что есть еще некоторая ненулевая стоимость для работы пустых методов.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top