Я только что сделал сравнительный тест для сравнения производительности локальных переменных, переменных-членов, переменных-членов других объектов и наборов-получателей. Эталонный показатель увеличивает переменную в цикле с 10-миллионными итерациями. Вот выход:Производительность переменной доступа для Android (Dalvik)
ЭТАЛОН: местный 101, член +1697, иностранный член 151, геттер сеттер 268
Это было сделано на планшете Motorola Xoom и Android 3.2. Цифры - миллисекунды времени выполнения. Может ли кто-нибудь объяснить отклонение переменной-члена мне? Особенно по сравнению с переменными-членами другого объекта. На основе этих цифр представляется целесообразным копировать переменные-члены в локальные переменные перед использованием их значений в вычислениях. Кстати, я сделал тот же тест на HTC One X и Android 4.1, и он показал те же отклонения.
Являются ли эти цифры разумными или есть систематическая ошибка, которую я пропустил?
Вот тест функции:
private int mID;
public void testMemberAccess() {
// compare access times for local variables, members, members of other classes
// and getter/setter functions
final int numIterations = 10000000;
final Item item = new Item();
int i = 0;
long start = SystemClock.elapsedRealtime();
for (int k = 0; k < numIterations; k++) {
mID++;
}
long member = SystemClock.elapsedRealtime() - start;
start = SystemClock.elapsedRealtime();
for (int k = 0; k < numIterations; k++) {
item.mID++;
}
long foreignMember = SystemClock.elapsedRealtime() - start;
start = SystemClock.elapsedRealtime();
for (int k = 0; k < numIterations; k++) {
item.setID(item.getID() + 1);
}
long getterSetter = SystemClock.elapsedRealtime() - start;
start = SystemClock.elapsedRealtime();
for (int k = 0; k < numIterations; k++) {
i++;
}
long local = SystemClock.elapsedRealtime() - start;
// just make sure nothing loops aren't optimized away?
final int dummy = item.mID + i + mID;
Log.d(Game.ENGINE_NAME, String.format("BENCHMARK: local %d, member %d, foreign member %d, getter setter %d, dummy %d",
local, member, foreignMember, getterSetter, dummy));
}
Edit:
Я ставлю каждый цикл в функции и назвал их 100 раз в случайном порядке. Результат: BENCHMARK: местный 100, участник 168, иностранный член 190, геттер сеттер 271 Выглядит хорошо, thx. Посторонний объект был создан как конечный член класса, а не внутри функций.
Вы должны запускать каждый тест по-своему, чтобы избежать помех оптимизации, и вы должны попытаться изменить порядок их запуска. В идеале вы также должны контролировать GC. – assylias
+1 Хороший вопрос! Заставляет вас думать. –
Умный компилятор может устранить цикл и заменить его на 'i + = numIterations'. Это может даже распространиться на геттеры/сеттеры, объявленные в одном классе. Я подозреваю, что в основном это делается, чтобы сделать такие тесты, как этот отчет, абсурдно хорошими. :-) Одной из причин использования большого количества итераций является то, что JIT ничего не скомпилирует, пока код не станет «горячим», т. Е. Он много работает; вы должны, вероятно, запустить весь этот метод дважды. На вас также могут влиять настройки частоты процессора (для экономии энергии или терморегулирования). – fadden