Android: Сколько накладных расходов генерируется при запуске пустого метода? - PullRequest
7 голосов
/ 03 декабря 2010

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

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

После прочтения другого вопроса я узнал, что содержимоеоператора if не компилируется, если константа Release.DEBUG имеет значение false.

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

Спасибо

Гари

Ответы [ 5 ]

14 голосов
/ 16 февраля 2011

Измерения выполнены на 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 не превышает 70 нс / вызов (то есть ~ 70 циклов процессора) и сравним со стоимостью одного пустого для итерации цикла (то есть один инкремент и одна проверка условия для локальной переменной)

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

void empty(String string){
}

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

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

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

2 голосов
/ 03 декабря 2010

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

См. Также: Встроенное расширение

2 голосов
/ 03 декабря 2010

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

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

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

2 голосов
/ 03 декабря 2010

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

1 голос
/ 06 апреля 2016

Это интересный вопрос, и мне нравится анализ @misiu_mp, поэтому я подумал, что обновлю его тестом 2016 года на Nexus 7 под управлением 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 и б) все еще естьстоимость вызова пустого метода, статического или нет.

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

enter image description here

Выполнение того же кода с пустыми циклами (комментирование вызовов методов) приводит к средней скорости 8 нс, однако около 3/4 измеренного времени равно 0 нс, а остальные - ровно 30 нс.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...