Сравнение байт-кода цикла Android - PullRequest
2 голосов
/ 20 марта 2012

Я провел несколько экспериментов с циклами в Android и был озадачен результатами.

В прошлом я где-то читал, что (в C ++ ??), если перевести этот цикл:

for(int i = 0; i != Integer.MAX_VALUE; i++)
{
   // Do something
}

... в этот цикл:

for(int i = threshold; --i >= 0; )
{
    // Do the same
}

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

Я хотел посмотреть, так ли это в Android, поэтому я начал с написания кода и использовал DEX, чтобы посмотреть на сгенерированный байт-код Dalvik, чтобы убедиться, что оптимизация компилятора не происходит.

Действительно, это были результаты:

0003dc: 1201                                   |000e: const/4 v1, #int 0 // #0  
0003de: 1402 ffff ff7f                         |000f: const v2, #float NaN // #7fffffff 
0003e4: 3321 5000                              |0012: if-ne v1, v2, 0062 // +0050 

000434: 1401 ffff ff7f                         |003a: const v1, #float NaN // #7fffffff
00043a: d801 01ff                              |003d: add-int/lit8 v1, v1, #int -1 // #ff 
00043e: 3b01 2800                              |003f: if-gez v1, 0067 // +0028 

(в данном случае это не имеет значения код 0062 и 0067, так как я просто обеспокоен тем, что сам цикл).

Хорошо, но мы можем ясно видеть, что компилятор / транслятор не вводит оптимизацию, поскольку оба синтаксиса цикла имеют разный сгенерированный байт-код.

Теперь, когда контекст установлен и я доказал, что было бы полезно продолжить тестирование, пришло время для вопроса:

«После того, как я профилировал приведенный выше код и выяснил, что независимо от порядка выполнения цикла первый всегда занимает больше времени, чем второй, чего мне здесь не хватает?»

Что-то вроде JIT-компиляции делает некоторую оптимизацию для меня?

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

Большое спасибо за любые усилия, чтобы просветить меня по этому вопросу.

Ответы [ 2 ]

2 голосов
/ 20 марта 2012

У меня есть следующие мысли. Прежде всего, байт-код dalvik не выполняется непосредственно на процессоре - это все же байт-код, и его следует преобразовать в собственный код.

Во-вторых, давайте рассмотрим, почему второй случай в C ++ (платформа x86) будет быстрее первого:

  1. Итак, в первом случае у вас будет такой код: inc (i), затем сравнить два значения процессор вычтет первое значение из второй и проверьте, равен ли результат 0 (используя инструкцию jz или что-то в этом роде).
  2. Во втором случае процессор выдаст dec (i), а затем значение результата сравнится с 0 (с использованием jz).

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

1 голос
/ 20 марта 2012

В первой сборке инструкция if-ne сравнивает два значения (v1 и v2) и переходит на основе результата.Это медленнее, чем просто сравнивать одно значение с нулем, как это делает инструкция if-gez во втором случае.Но, возможно, я неправильно понял ваш вопрос, вы имеете в виду, что оба цикла выполняются в одно и то же время?Это не ясно из вашего вопроса.Какие сроки вы получаете?

...