27 мая 2015
Приложения для Android используют только одно ядро процессора: правда или вымысел?
Константин Иванов
По материалам androidauthority.com
Уже с десяток лет в наших компьютерах стоят многоядерные процессоры, и в настоящее время это норма. Вначале ядер стало два, потом четыре, а сегодня компании вроде Intel и AMD предлагают high-end процессоры для настольных компьютеров с 6 или 8 ядрами. Та же история и с процессорами в смартфонах. Двухъядерные энергоэффективные процессоры от ARM появились около 5 лет назад, а вслед за ними и 4, 6 и 8-ядерные процессоры на архитектуре ARM. Между тем, есть разница между 6- и 8-ядерными настольными процессорами от Intel и AMD и 6- и 8-ядерными процессорами, основанными на архитектуре ARM. У большинства относящихся ко второй категории процессоров с больше чем 4 ядрами используются как минимум две различных конструкции ядра.
С некоторыми исключениями, в целом, восьмиядерный ARM процессор использует систему, известную как Heterogeneous Multi-Processing (HMP), в которой «гетерогенность» означает неравноценность ядер. В современном 64-битном процессоре это значит, что кластер с ядрами Cortex-A57 или Cortex-A72 используется в сочетании с кластером ядер Cortex-A53. A72 – высокопроизводительное ядро, в то время как у A53 большая энергоэффективность. Такое сочетание известно как big.LITTLE, поскольку здесь «большие» ядра (Cortex-A72) объединены с «маленькими» Cortex-A53. Это сильно отличается от 6- и 8-ядерных процессоров для ПК от Intel и AMD, поскольку проблема энергопотребления в этом случае не так актуальна, как на мобильном устройстве.
Когда многоядерные процессоры впервые попали на ПК, возникло много вопросов касательно преимуществ двухъядерного процессора перед одноядерным. Двухъядерный 1.6ГГц процессор «лучше» одноядерного 3.2ГГц процессора или нет? А что Windows? Сможет ли она максимально реализовать потенциал двухъядерного процессора? А игры? Они правда идут лучше с двухъядерным процессором? И надо ли при написании приложений делать это особым образом, чтобы они могли использовать дополнительные ядра? И так далее.
О мультипроцессорной обработке
Эти вопросы вполне закономерны, и, конечно, такие же вопросы возникают по поводу многоядерных процессоров в смартфонах. Перед тем, как посмотреть на «взаимоотношения» многоядерных процессоров в смартфонах и Android приложений, давайте немного рассмотрим многоядерную технологию в целом.
Компьютерам отлично удается решение одной задачи. Вам нужно узнать первые сто миллионов простых чисел? Не вопрос, компьютер будет вычислять их целый день, снова и снова. Но тогда, когда вам нужно, чтобы он совершал два действия, например, выявлял те же простые числа с одновременно запущенным графическим интерфейсом, чтобы вы могли одновременно заниматься веб-браузингом, это оказывается несколько сложнее.
Не углубляясь в частности, существует технология, известная как вытесняющая многозадачность, которая позволяет разделять доступное процессорное время между несколькими задачами. «Кусочек» процессорного времени отводится одной задаче, «кусочек» другой и так далее. В основе операционных систем, таких как Linux, Windows, OS X и Android, лежит та часть технологии, что известна как планировщик и определяет, какому процессу достанется следующий «кусочек» процессорного времени.
Планировщики могут писаться по-разному, на сервере планировщик может быть заточен под то, чтобы давать приоритет задачам ввода-вывода вроде записи на диск или считывания из сети, в то время как в настольной версии он будет уделять больше внимания отзывчивости графического интерфейса.
Когда ядер больше одного, планировщик может отвести для одного процесса кусочек времени процессору 0, в то время как другой процесс получает кусочек времени процессора 1. Так планировщик и двухъядерный процессор позволяют двум задачам выполняться одновременно. Чем больше ядер, тем больше процессов могут выполняться одновременно.
Вы уже заметили, что планировщику хорошо удается разделять ресурсы процессора между различными задачами вроде того же вычисления простых чисел, запуска рабочего стола, использования браузера. Однако один процесс, такой как вычисление простых чисел, может быть разделен между несколькими ядрами. Или нет?
Некоторые задачи последовательны сами по себе. Чтобы испечь пирог, вам нужно разбить яйца, добавить муку, замесить тесто и так далее. Нельзя поставить пирог в духовку, пока не готово тесто. Так что даже если у вас на кухне два повара, сэкономить время на одной из задач не выйдет. Есть нерушимый порядок и последовательность действий. Можно решать несколько задач сразу и поручить одному повару пирог, а другому нарезку салата, но задачи с предопределенным порядком действий не выиграют ни от двухъядерного, ни даже от 12-ядерного процессора.
Не все задачи таковы, как описано выше. Многие операции, которые выполняет компьютер, можно разделить на несколько самостоятельных задач. Чтобы это произошло, основной процесс должен создать другой процесс и отдать ему на откуп часть работы. К примеру, если, используя алгоритм для вычисления простых чисел, вы не используете предыдущие результаты, не пользуетесь Решетом Эратосфена, можно разделить работу на две части. Один процесс вычисляет первые 50 млн чисел и второй – вторые 50 млн. Четырехъядерный процессор позволяет поделить работу на 4 части, и так далее.
Но для того, чтобы все это работало, программу надо написать особым образом. Другими словами, она должна быть разработана так, чтобы делить нагрузку на меньшие части, а не делать ее целиком. Для этого есть различные технологии программирования, и вы наверняка слышали слова вроде «однопоточный» или «многопоточный». Эти слова означают программы, которые написаны для выполнения одной задачи (однопоточная, все вместе) или программы с индивидуальными задачами (потоками), которым может быть отдельно назначено свое процессорное время. Подводя краткий итог, однопоточная программа ничего не выиграет от запуска на многоядерном процессоре, а вот многопоточная – напротив.
Итак, мы почти добрались до сути, и прежде чем перейти к Android, нужно еще одно. От того, как написана ОС, зависит то, что некоторые выполняемые программы могут быть изначально многопоточными. Часто отдельные части ОС сами по себе представляют собой независимые задачи, и когда ваша программа осуществляет ввод и вывод информации или выводит что-то на экран, это может быть отдельным процессом в системе. Использование того, что называется non-blocking calls может внести многопоточность в программу, не создавая потоков специально.
Это важный аспект для Android. Одна из задач системного уровня в архитектуре Android – SurfaceFlinger. Это основа процесса вывода графической информации на дисплей в Android. Это отдельная задача, которой должно быть выделено процессорное время. Что означает, что определенные графические операции для выполнения предполагают запуск нового процесса.
Android
Из-за процессов вроде SurfaceFlinger Android выигрывает от многоядерных процессоров без нужды в специальных многопоточных по сути приложениях. И поскольку множество вещей происходит в фоне, вроде синхронизации и виджетов, Android выигрывает от многоядерности и как единое целое. Эта ОС ожидаемо обладает способностью создавать многопоточные приложения. Чтобы узнать больше, посмотрите в раздел Процессы и Потоки в документации Android. Есть также многопоточные примеры от Google, а также имеется интересная статья от Qualcomm о программировании Android приложений для многоядерных процессоров .
Однако остается актуальным вопрос, является ли большинство Android приложений однопоточным и использует ли, таким образом, только одно ядро. Вопрос важный, поскольку если да, то у вас может быть многоядерный монстр из мира смартфонов, а на деле его процессор будет работать, как двухъядерный!
Также может возникнуть вопрос относительно разницы между 4- и 8-ядерным процессором. В ПК или серверах восьмиядерные процессоры построены так, что чип состоит из одинаковых ядер. Для большинства восьмиядерных процессоров с архитектурой ARM существуют высокопроизводительные и энергоэффективные варианты ядер. И смысл в том, что более энергоэффективные ядра служат для выполнения более второстепенных задач, а высокопроизводительные – для работы в тяжелой весовой категории. Однако, как и в настольной версии, эти ядра могут использоваться одновременно.
Основное, что здесь стоит запомнить, это то, что восьмиядерный процессор big.LITTLE обладает восемью ядрами из соображений энергоэффективности, а не производительности.
Тестирование
В Android возможно получить сведения о том, сколько ядер система использовала в процессоре. Для подкованных, это можно посмотреть в файле /proc/stat. Был создан инструмент, который берет информацию об использовании ядер в Android, пока запущено приложение. Чтобы повысить его эффективность и уменьшить падение производительности, сведения собираются, только когда приложение активно. Анализ данных производится офлайн.
Используя этот инструмент, у которого пока нет названия, для теста запускали серии приложений разного типа (игры, веб-браузинг и т.п.) на телефоне с четырехъядерным процессором Qualcomm Snapdragon 801, а затем на телефоне с восьмиядерным Qualcomm Snapdragon 615. При сопоставлении данных получились графики использования процессора. Начнем с простого примера. Вот график работы ядер Snapdragon 801 при использовании браузера Chrome:
График показывает, сколько ядер использовали Android и браузер. Он не демонстрирует, насколько было задействовано ядро, только то, использовалось ли оно в принципе. Если бы Chrome был однопоточным, можно было бы ожидать, что задействуются одно или два ядра, может быть, третье или четвертое по случаю. Но мы этого не видим. Наоборот, задействованы четыре ядра, и только временами количество используемых ядер падает до 2. В тесте с браузингом не читались загруженные страницы, это не повлияло бы на использование процессора. Страницы просто прогружались, и можно было переходить к новым.
Вот график, который показывает, насколько задействовалось каждое ядро. Это усредненный график (в реальном путаницу вносит огромное количество линий). Это значит, что по меньшей мере, показаны пики использования. К примеру, пик на этом графике превышает 90%, однако изначальные данные показывали, что некоторые ядра достигали 100% много раз. Тем не менее, здесь хорошо видно, что происходило.
А что у нас с восьмиядерным процессором? Демонстрирует ли он ту же самую схему? Нет, как видно на графике ниже. Постоянно используется семь ядер, на пиках доходит до 8, иногда опускается до 6 и 4.
Также и средний показатель использования каждого ядра демонстрирует, что планировщик вел себя иначе, поскольку Snapdragon 615 – процессор big.LITTLE.
Можно видеть, что два или три ядра трудятся больше других, но так или иначе задействованы все ядра. Мы видим, как архитектура big.LITTLE может передавать потоки от ядра к ядру в зависимости от загруженности. И не забываем, что смысл дополнительных ядер – это энергоэффективность, а не производительность.
Мы можем спокойно говорить о том, что использование «андроидом» всего одного ядра – это миф. Это было ожидаемо с учетом того, что Chrome, как и Android, был разработан многопоточным, как и для настольных компьютеров.
Другие приложения
Итак, это был разработанный многопоточным Chrome, а что с другими приложениями? Вот, что получилось вкратце
Gmail – на 4-ядерном телефоне получились равные доли использования 2 и 4 ядер. Однако среднее использование ядра не поднималось выше 50% — ожидаемо для относительно легкого приложения. Восьмиядерный процессор давал скачки от 4 к 8 ядрам, но меньшее среднее использование ядра – менее 35%.
YouTube – на 4-ядерном процессоре использовались только 2 ядра, в среднем менее 50% загрузки. На 8-ядерном в основном 4 ядра, временами вырастало до 6 и падало до 3. Загрузка ядер в среднем была всего 30%. Интересно, что планировщик предпочитал большие ядра, а маленькие почти не использовал.
Riptide GP2 – 4 ядра – процессор Qualcomm большую часть времени использовал два ядра, а остальные два – очень мало. А в 8-ядерном варианте последовательно использовались 6-7 ядер, но основную работу выполняли только три.
Templerun 2 – эта игра – более яркий пример проблемы однопоточности, чем другие приложения в тесте. В 8-ядерном варианте задействовались 4-5 ядер последовательно с пиками до 7. И только одно ядро выполняло тяжелую работу. На телефоне с 4-ядерным Qualcomm Snapdragon 801 два ядра делили нагрузку примерно поровну, а двум другим доставалось очень мало. На телефоне с 4-ядерным процессором от MediaTek нагрузка распределялась между всеми четырьмя ядрами. Это показывает, насколько разные планировщики и разные ядра разительно меняют то, как используется процессор.
Вот выборка графиков для наглядности. График бездействия 8-ядерной системы добавлен в качестве отправной точки.
Восьмиядерный аппарат, активный экран, пользователь не совершает никаких действий:
YouTube, запущенный на 4-ядерном аппарате:
YouTube, запущенный на 8-ядерном аппарате:
TempleRun2, запущенный на 4-ядерном аппарате:
TempleRun2, запущенный на 4-ядерном аппарате с процессором MediaTek:
Gmail, запущенный на 4-ядерном аппарате:
Gmail, запущенный на 8-ядерном аппарате:
Riptide GP2, запущенный на 4-ядерном аппарате:
Riptide GP2, запущенный на 8-ядерном аппарате:
Интересный результат получился в AnTuTu на 8-ядерном процессоре.
Как видите, последняя часть теста полностью загружает все ядра. Понятно, что бенчмарк искусственно создает высокую нагрузку, и поскольку все ядра работают на полную, чипсеты с большим количеством ядер выигрывают. С обычными приложениями такого не наблюдалось. Бенчмарки искусственно раздувают преимущество восьмиядерных аппаратов в производительности (больше, чем в энергоэффективности).
Почему легкие приложения используют 8 ядер?
Если вы посмотрите на приложения вроде Gmail, вы заметите интересный феномен. На 4-ядерном аппарате использование ядер поровну распределено между двумя и четырьмя ядрами, а на 8-ядерном – между четырьмя и восемью. Как Gmail может работать на 2 – 4 ядрах на 4-ядерном телефоне, а на 8-ядерном требовать как минимум четырех ядер? Бессмыслица какая-то.
Все дело снова в том, что ядра в телефонах с big.LITTLE неравноценны. В реальности мы видим, что планировщик использует ядра LITTLE, а когда нагрузка повышается, в дело вступают их собратья big. После некоторого времени совместной работы ядра LITTLE отправляются отдыхать. Когда нагрузка снижается, все происходит наоборот. Конечно, все это случается очень быстро, тысячи раз в секунду. Посмотрите на график, где сравнивается использование ядер big и LITTLE в Epic Citadel.
Посмотрите, вначале используются ядра big, а ядра LITTLE неактивны. Затем, около отметки 12 секунд, ядра big начинают использоваться меньше, и просыпаются ядра LITTLE. На 20 секундах big-ядра увеличивают активность снова, и LITTLE снижают ее почти до нуля. Это видно и на отметках 30, 45 и 52 секунды. В этих точках число использованных ядер колеблется. К примеру, в первые 10 с используются только 3 или 4 ядра (это ядра big), и на 12 с это число доходит до 6, затем снова падает до 4 и т.д. Так работает big.LITTLE. Этот процессор построен не так, как процессор для ПК. Дополнительные ядра позволяют планировщику выбирать для разных действий правильные ядра.
Все тесты, которые проводились, показали, что не нашлось ни одного реального приложения, которое использовало бы все 8 ядер на сто процентов. Так и должно было быть.
Подводим итоги
Прежде всего, подчеркнем, что эти тесты не отражают производительности телефонов, а лишь показывают, задействуют ли приложения Android несколько ядер. Не раскрывается преимуществ или недостатков многоядерности или чипсета big.LITTLE, как не сравнивается и работа частей приложения на двух ядрах при их использовании на 25% с использованием одного ядра на 50%, и так далее.
Затем, тесты еще не проводились для схемы Cortex-A53/Cortex-A57 или Cortex-A53/Cortex-A72. У Qualcomm Snapdragon 615 4-ядерный 1.7 ГГц ARM Cortex A53 кластер и четырехъядерный кластер 1.0 ГГц A53.
Интервал сканирования в этой статистике равен примерно трети секунды, т. е. около 330 миллисекунд. Если ядро сигнализирует об использовании на 25% в эти 300 миллисекунд и второе ядро – о том же самом, график покажет, что оба ядра используются на 25% одновременно, при этом одно ядро может задействоваться на 25% в течение 150 миллисекунд, то же и со вторым. Это означает, что ядра использовались последовательно, а не единовременно. В настоящее время меньшего интервала тест не предполагает.
При всем при этом, Android приложения очевидно способны использовать преимущества многоядерных процессоров и процессоры big.LITTLE позволяют планировщику выбрать наилучшую комбинацию ядер для текущей задачи. Поэтому если вы по-прежнему слышите от людей «Но смартфону не нужны 8 ядер!», вам остается только развести руками в отчаянии. Ничего-то эти люди не понимают.
познавательно)
Бред.
Ну, будем считать, что вы представились и отрекомендовались.
Android гораздо больше, чем настольные ОС, подталкивает разработчиков к асинхронности. А это значит, что максимально эффективно будут использоваться дополнительные ядра. Другое дело, что отдельные разработчики сопротивляются и мы видим пресловутые лаги при листании списков.
Асинхронность != параллельность. И насквозь асинхронный JavaScript тому подтверждение.
>> Асинхронность != параллельность.
А вы не запрашивайте асинхронное выполнение через Handler в UI-потоке. Тогда и параллельность начнет работать.
>> И насквозь асинхронный JavaScript тому подтверждение.
Вы пишете под Android на JavaScript?
Нет. JS это только пример неравенства понятий асинхронность и параллельность (многопоточность). Которая лишь реорганизует последовательность выполнения блоков кода, а не распаралеливает их.
То есть мой комментарий касался лишь формулировки «Android гораздо больше, чем настольные ОС, подталкивает разработчиков к ???.»
Хорошая статья.
«С некоторыми исключениями, в целом, восьмиядерный ARM процессор
использует систему, известную как Heterogeneous Multi-Processing (HMP), в
которой «гетерогенность» означает неравноценность ядер.»
Очень узкая трактовка. Неравноценность ядер, а не их скоростей! Даже английская Wiki, по этому поводу говорит «ARM big.LITTLE
is an exception where the ISAs of cores are the same and heterogeneity
refers to the speed of different microarchitectures of the same ISA,
then making it more like a symmetric multiprocessor system (SMP)»
То есть, в БигЛитл неоднородность относится исключительно к скорости и архитектура ближе классической. Условно, чипы AMD (про Интел не знаю), позволяют каждому ядру работать на своей частоте, от 800Мгц до номинальных нескольких ГГц, при своих напряжениях питания от 0.7В (экономный режим) до штатных. Вот вам и БигЛитл в десктопном варианте.
Итак. Статья на вопрос заголовка ответила. Программы используют, планировщик планирует. Это хорошо. Но вот вывод относится совсем к другому, нужны ли смартфону эти ядра. А по этому вопросу исследований не было.
Если софт периодически, и даже регулярно, дергает ядра, это ничуть не говорит о их необходимом количестве и пропорции биг-литл.
Все верно сказал
Теперь, опираясь на результаты этого исследования, хотелось бы видеть тесты конкретно по влиянию многоядерности на производительность.
В принципе, здесь предоставлено много данных для анализа.
Посмотрите на загрузку 4-ядерных процессоров. И представьте, что вместо него оказался 4-ядерный big.LITTLE в режиме 2+2.
Справился бы он с нагрузкой? Без проблем. В редчайших случаях — Хром и TempleRun2 (Mediatek), — задержал выполнение на 1-2 секунду к отраженному на графике 60 секундному промежутку. И то не факт.
То есть, фактически, даже на 2+2 мы получили ту же энергоэффективность от big.LITTLE, как и при 4+4, ничуть не проиграв в производительности обычному 4х.
Вопрос в зависимости между загруженностью ядра и его энергопотреблением. Возможно ваша система 2+2 справляется с задачей за то же время; но при этом система 4+4 нагружена меньше (а то и больше ресурсов выполняется на энергоэффективных ядрах, т.к. их 4, а не 2) и за счёт этого потребляет меньше. Выйгрыш очевиден.