Интерпретация многоуровневой трассировки производительности (Eclipse/Android)
Я работаю над Android-игрой, и я начал замечать небольшую медлительность во время разработки, поэтому я хотел попытаться использовать многопоточность для удовольствия и обучения.
Мое приложение имеет 3 потока:
- поток пользовательского интерфейса (должен быть в основном неактивным)
- Игровая логическая тема
- Графическая тема
Я минимизировал критический раздел между потоками 2 и 3, насколько мог, с идеей, что логика игры может обновляться независимо от потока рендеринга, а затем в конце обоих потоков я мог бы иметь как можно более короткое окно, где Я выталкиваю все графические обновления из логического потока в игровой цикл. Это должно позволить двум нитям работать независимо в течение большей части времени. В теории звучит как победа в производительности.
Однако, как только я добрался до реализации, моя работа заняла большое место. Это намного хуже, чем раньше, один цикл обновления и рендеринга занимает примерно 50 мс (20 кадров в секунду), поэтому он выглядит как мусор. Это всего лишь рендеринг примерно 20 треугольников и, возможно, 20 текстурированных квадратов, действительно простая рабочая нагрузка (я боюсь думать о том, что будет, когда я реализую правильную графику).
В любом случае я взял трассировку DDMS в андроиде в профиль, где дела идут неправильно или могут быть улучшены.
http://i.stack.imgur.com/DDUYE.png
Это примерно 3 кадра моей игры. Пока что, похоже, примерно то, что я ожидал. Части, выделенные синим цветом, представляют собой заблокированную секцию, которая выглядит правильно (держит glThread в основном, ожидая, пока он заблокирован). Однако как только я разблокирую его, я должен видеть, что оба потока работают одновременно, и похоже, что они есть, но если я посмотрю ближе:
http://i.stack.imgur.com/vukXQ.png
Я занимаюсь разработкой на двухъядерном телефоне, но если я правильно понимаю трассировку, это не похоже на то, что он когда-либо делал что-либо параллельно, и что хуже, по-видимому, переключает активную нить сотни раз за миллисекунды! (если я не интерпретирую это неправильно). Все это переключение контекста, похоже, было бы ужасно для производительности, поэтому я не уверен, почему он хотел бы переключаться туда и обратно так быстро.
Итак, после моего долгого объяснения, мне интересно несколько вещей:
- Насколько я понимаю, что заполненные прямоугольники в трассировке являются активными потоками, а цветные линии - спящими потоками? В противном случае, что они означают?
- Почему я не вижу, чтобы мои потоки выполнялись одновременно на якобы двухъядерном телефоне?
- Почему это так быстро переключает активные потоки?
- В DDMS я получаю предупреждение "ПРЕДУПРЕЖДЕНИЕ: активен отладчик, результаты отслеживания методов будут искажены". О чем это беспокоиться? Как я могу избавиться от этого предупреждения? (Я запускал приложение через Run, а не через Debug, если это имеет значение)
Ответы
Ответ 1
Очень хороший вопрос, позвольте мне начать с ответов:
- Вы перепутали потоки/методы/activeMethod. Каждая строка в traceview представляет собой поток (и если вы назвали свои потоки, вы увидите это имя на левой стороне, например, "GL Thread", "main" и т.д.). Прямоугольники (цветные) представляют активные методы выполнения внутри каждого потока, в то время как цветные линии представляют собой "приостановленные" методы внутри потока. Под "приостановленным" я подразумеваю, что "метод все еще выполняется, но контекст был переключен на какой-то другой поток, и когда контекст снова переключился на этот поток, этот метод будет продолжать работать. В терминологии, которую вы использовали в своем вопросе, линии - это методы спящего потока, а прямоугольник - активный метод выполнения потока. Вы можете найти дополнительную информацию о отслеживании DDMS здесь.
- Распределение потоков между ядрами - это еще одна история и в значительной степени зависит от основных механизмов ОС Android. Прежде всего, убедитесь, что целевая ОС Android запущена с опцией SMP (Symmetric Multi-Processing), которая по умолчанию используется для многоядерных телефонов, я думаю:), но я не разбираюсь в этих вещах. Несколько слов о SMP вы можете найти здесь.
- Переключение потоков зависит от OS Thread/Process scheduler, приоритета потока и т.д. Подробнее об этом можно найти в этих ответах.
- Даже если вы запустили приложение в режиме без отладки, когда вы подключаетесь к DDMS и выполняете такие функции, как профилирование методов, вы активируете отладочные части davlik vm. Подробнее об отладке здесь, раздел "Реализация".
Надеюсь, этот ответ вам поможет.
Ответ 2
Спасибо за вопрос. Мне тоже будет полезен полный ответ инсайдера. Я скажу то, что знаю.
-
Некоторые (все?) телефоны имеют возможность включить/отключить второе ядро. Вы проверили, что ваш включен?
-
В моем собственном приложении я заметил, что просто переход из одного потока в два (по одному ядру) без изменения общей работы, вызванной фактором замедления в 1,5 раза, поэтому очень важно, чтобы потоковая передача имела стоимость.
-
Именно в новостях Intel обращается к Google с плохой реализацией многоядерной потоковой передачи:
http://www.pcworld.com/article/257307/dual_core_processors_wasted_on_android_intel_claims.html
Ваши результаты подтверждают это.
-
Еще одна вещь, о которой нужно помнить, заключается в том, что многоядерный процессор не является многопроцессорным. Вы используете пропускную способность кэша и контроллера памяти между ядрами. Можно остановиться, пока он ждет, пока другой закончит с общим ресурсом, в частности, для записи в общих строках кэша. Однако этот эффект не должен учитывать однопоточность, которую вы видите.