Изучаем Android. Ядро (Kernel) — что это такое.
Многие владельцы Android устройств на различных форумах и сайтах часто встречают упоминание о чем-то непонятном, что называют ядром, или по-английски kernel. Его можно поменять и упоминание о нем встречается в меню настроек устройства, в разделе «О планшете (телефоне)».
Если копнуть поглубже, то окажется, что ядро – это часть операционной системы, и оно есть не только у Android, но и у других операционных систем: Windows, iOS, MacOS и прочих. Но нас будет интересовать ядро Android, и что это такое я попытаюсь объяснить на уровне начинающих пользователей.
Вы, наверное, знаете, что любая операционная система, и Android в том числе – это, по большому счету, набор программ, которые управляют работой всего устройства, и отвечают за запуск пользовательских приложений, таких как игры, менеджеры файлов, веб-браузеры и прочие.
А ядро Android является, практически, самой главной частью операционной системы, которая отвечает за взаимодействие между всем «железом» и программной частью системы. Ядро состоит из набора драйверов всего имеющегося в устройстве оборудования и подсистемы управления памятью, сетью, безопасностью, и прочих основных функций операционной системы.
Например, когда вы касаетесь экрана, чтобы запустить какое-либо приложение, драйвер сенсорной панели экрана определяет место, в котором произошло нажатие и сообщает координаты другим программам, которые опять же с помощью ядра найдут в памяти устройства нужное приложение и запустят его. Это конечно, очень упрощенная модель, но суть работы операционной системы она отражает.
Таким образом, мы выяснили, что когда любое программное обеспечение нуждается в том, чтобы оборудование планшета или телефона что-нибудь сделало, оно обращается за этим к ядру операционной системы.
Ядро управляет абсолютно всем оборудованием: Wi-Fi, Bluetooth, GPS, памятью и прочими устройствами. Не является исключением и «сердце» устройства – его процессор. Ядро может управлять его частотой и энергоснабжением.
Ядро операционной системы Android, позаимствовано ее разработчиками, компанией Google, у операционной системы Linux.
Так как ядро управляет всем оборудованием, а оборудование у всех планшетов и телефонов разное, базовое ядро Android дорабатывается производителем для каждого устройства отдельно.
Как и прошивки, ядра бывают стоковыми (заводскими) и кастомными – альтернативными, созданные независимыми разработчиками.
Зачем нужны кастомные ядра? Стоковое ядро максимально оптимизируется производителем для конкретного устройства, но в нем обычно заблокированы такие важные функции ядра, как, например, управление частотой процессора. И если вам понадобится разогнать процессор своего планшета, вам нужно будет сменить ядро на кастомное, в котором функция управления частотой процессора разблокирована.
Кроме того, кастомные ядра, обычно основаны на более свежих версиях Linux ядер. Вот примерный перечень возможностей, которые нам дают кастомные ядра:
- Изменение частоты процессора в широких пределах;
- Разгон графической подсистемы (GPU);
- Снижение частоты и напряжения питания процессора, что позволяет достичь более длительного времени работы от батареи;
- Более свежие и качественные драйверы, например, ускоряющие работу GPS или добавляющие новые функции;
- Широкие возможности по настройки и конфигурации звука и цветовой гаммы экрана;
- Поддержка альтернативных файловых систем (XFS, ReiserFS и прочих).
Так как альтернативные ядра создаются независимыми разработчиками, нет никакой гарантии, что после установки кастомного ядра ваш планшет или телефон будут работать без сбоев. Поэтому перед прошивкой нового ядра желательно сделать полную резервную копию системы.
Есть ли польза от кастомных ядер
Тесты
Arch Linux
Начнем с теста Arch Linux на нетбуке.
Результаты теста UnixBench на стандартном ядре (3.0-ARCH):
Test | Score | Unit | Time | Iters. | Baseline | Index |
---|---|---|---|---|---|---|
Dhrystone 2 using register variables | 3432673.5 | lps | 10.0 s | 7 | 116700.0 | 294.1 |
Double-Precision Whetstone | 821.7 | MWIPS | 10.2 s | 7 | 55.0 | 149.4 |
Execl Throughput | 1048.3 | lps | 29.7 s | 2 | 43.0 | 243.8 |
File Copy 1024 bufsize 2000 maxblocks | 120834.3 | KBps | 30.0 s | 2 | 3960.0 | 305.1 |
File Copy 256 bufsize 500 maxblocks | 36417.8 | KBps | 30.0 s | 2 | 1655.0 | 220.0 |
File Copy 4096 bufsize 8000 maxblocks | 290993.0 | KBps | 30.0 s | 2 | 5800.0 | 501.7 |
Pipe Throughput | 240124.9 | lps | 10.0 s | 7 | 12440.0 | 193.0 |
Pipe-based Context Switching | 21672.7 | lps | 10.0 s | 7 | 4000.0 | 54.2 |
Process Creation | 2885.9 | lps | 30.0 s | 2 | 126.0 | 229.0 |
Shell Scripts (1 concurrent) | 738.5 | lpm | 60.0 s | 2 | 42.4 | 174.2 |
Shell Scripts (8 concurrent) | 135.6 | lpm | 60.4 s | 2 | 6.0 | 226.1 |
System Call Overhead | 600176.7 | lps | 10.0 s | 7 | 15000.0 | 400.1 |
System Benchmarks Index Score: | 221.1 |
А вот тот же тест на pf-kernel (3.0-pf):
Test | Score | Unit | Time | Iters. | Baseline | Index |
---|---|---|---|---|---|---|
Dhrystone 2 using register variables | 3700926.6 | lps | 10.0 s | 7 | 116700.0 | 317.1 |
Double-Precision Whetstone | 846.1 | MWIPS | 10.2 s | 7 | 55.0 | 153.8 |
Execl Throughput | 1343.2 | lps | 29.6 s | 2 | 43.0 | 312.4 |
File Copy 1024 bufsize 2000 maxblocks | 127468.0 | KBps | 30.0 s | 2 | 3960.0 | 321.9 |
File Copy 256 bufsize 500 maxblocks | 37622.9 | KBps | 30.0 s | 2 | 1655.0 | 227.3 |
File Copy 4096 bufsize 8000 maxblocks | 342606.2 | KBps | 30.0 s | 2 | 5800.0 | 590.7 |
Pipe Throughput | 296672.7 | lps | 10.0 s | 7 | 12440.0 | 238.5 |
Pipe-based Context Switching | 41227.5 | lps | 10.0 s | 7 | 4000.0 | 103.1 |
Process Creation | 3969.3 | lps | 30.0 s | 2 | 126.0 | 315.0 |
Shell Scripts (1 concurrent) | 861.1 | lpm | 60.1 s | 2 | 42.4 | 203.1 |
Shell Scripts (8 concurrent) | 159.4 | lpm | 60.2 s | 2 | 6.0 | 265.6 |
System Call Overhead | 642005.3 | lps | 10.0 s | 7 | 15000.0 | 428.0 |
System Benchmarks Index Score: | 264.6 |
Как видно, общий прирост производительности составил 20%.
Ubuntu
Теперь результаты этих же тестов, но у же для Ubuntu.
На стандартном ядре (2.6.38-11-generic):
Test | Score | Unit | Time | Iters. | Baseline | Index |
---|---|---|---|---|---|---|
Dhrystone 2 using register variables | 39162082.2 | lps | 10.0 s | 7 | 116700.0 | 3355.8 |
Double-Precision Whetstone | 9143.1 | MWIPS | 9.9 s | 7 | 55.0 | 1662.4 |
Execl Throughput | 11472.2 | lps | 29.8 s | 2 | 43.0 | 2668.0 |
File Copy 1024 bufsize 2000 maxblocks | 1041722.3 | KBps | 30.0 s | 2 | 3960.0 | 2630.6 |
File Copy 256 bufsize 500 maxblocks | 327345.4 | KBps | 30.0 s | 2 | 1655.0 | 1977.9 |
File Copy 4096 bufsize 8000 maxblocks | 1730411.9 | KBps | 30.0 s | 2 | 5800.0 | 2983.5 |
Pipe Throughput | 4204868.3 | lps | 10.0 s | 7 | 12440.0 | 3380.1 |
Pipe-based Context Switching | 738528.0 | lps | 10.0 s | 7 | 4000.0 | 1846.3 |
Process Creation | 32309.9 | lps | 30.0 s | 2 | 126.0 | 2564.3 |
Shell Scripts (1 concurrent) | 11023.5 | lpm | 60.0 s | 2 | 42.4 | 2599.9 |
Shell Scripts (8 concurrent) | 1425.4 | lpm | 60.0 s | 2 | 6.0 | 2375.7 |
System Call Overhead | 5723850.3 | lps | 10.0 s | 7 | 15000.0 | 3815.9 |
System Benchmarks Index Score: | 2580.4 |
На pf ядре (2.6.38-pf8):
Test | Score | Unit | Time | Iters. | Baseline | Index |
---|---|---|---|---|---|---|
Dhrystone 2 using register variables | 71269301.5 | lps | 10.0 s | 7 | 116700.0 | 6107.1 |
Double-Precision Whetstone | 9175.2 | MWIPS | 9.9 s | 7 | 55.0 | 1668.2 |
Execl Throughput | 12014.6 | lps | 30.0 s | 2 | 43.0 | 2794.1 |
File Copy 1024 bufsize 2000 maxblocks | 1580881.5 | KBps | 30.0 s | 2 | 3960.0 | 3992.1 |
File Copy 256 bufsize 500 maxblocks | 428842.2 | KBps | 30.0 s | 2 | 1655.0 | 2591.2 |
File Copy 4096 bufsize 8000 maxblocks | 2315055.5 | KBps | 30.0 s | 2 | 5800.0 | 3991.5 |
Pipe Throughput | 4389021.4 | lps | 10.0 s | 7 | 12440.0 | 3528.2 |
Pipe-based Context Switching | 831655.8 | lps | 10.0 s | 7 | 4000.0 | 2079.1 |
Process Creation | 34789.6 | lps | 30.0 s | 2 | 126.0 | 2761.1 |
Shell Scripts (1 concurrent) | 11890.9 | lpm | 60.0 s | 2 | 42.4 | 2804.5 |
Shell Scripts (8 concurrent) | 1506.4 | lpm | 60.0 s | 2 | 6.0 | 2510.7 |
System Call Overhead | 5815793.6 | lps | 10.0 s | 7 | 15000.0 | 3877.2 |
System Benchmarks Index Score: | 3050.7 |
Прирост составил 18%, что на мой взгляд довольно ощутимо. Почему второй тест выдал чуть меньший результат? Скорее всего, дело в том, что тест проводился на x86_64 и в стандартном ядре было больше оптимизаций под архитектуру процессора, чем при ядре собранном под Pentium Pro на Intel Atom (SSE и прочие).
Как из этого всего видно, смысл в сборке своего ядра есть. Результаты примерно одинаковые на двух довольно разных процессорах: Intel Atom N270 и Core 2 Duo E8500.
Описывать процесс установки ядра для ARCH я не буду, он максимально прост. Я уверен, что для его пользователей это не составит труда.
Как писать свой процессор или расширяем функционал в NiFi
Все большую популярность набирает NiFi и с каждым новым релизом он получает все больше инструментов для работы с данными. Тем не менее, может появиться необходимость в собственном инструменте для решения какой-то специфичной задачи.
Apache Nifi имеет в базовой поставке более 300 процессоров.
NiFi Processor это основной строительный блок для создания dataflow в экосистеме NiFi. Процессоры предоставляют интерфейс, через который NiFi обеспечивает доступ к flowfile, его атрибутам и содержимому. Собственный кастомный процессор позволит сэкономить силы, время и внимание пользователей, так как вместо множества простейших элементов-процессоров будет отображаться в интерфейсе и выполняться всего один (ну или сколько напишете). Так же, как и стандартные процессоры, кастомный процессор позволяет выполнять различные операции и обрабатывать содержимое flowfile. Сегодня мы поговорим о стандартных инструментах для расширения функционала.
ExecuteScript
ExecuteScript – это универсальный процессор, который предназначен для реализации бизнес- логики на языке программирования (Groovy, Jython, Javascript, JRuby). Такой подход позволяет быстро получить нужную функциональность. Для обеспечения доступа к компонентам NiFi в скрипте есть возможность использовать следующие переменные:
Session: переменная типа org.apache.nifi.processor.ProcessSession. Переменная позволяет выполнять операции с flowfile, такими как create(), putAttribute() и Transfer(), а также read() и write().
Context: org.apache.nifi.processor.ProcessContext. Его можно использовать для получения свойств процессора, отношений, служб контроллера и StateManager.
REL_SUCCESS: Отношение «успех».
REL_FAILURE: Отношение «сбой»
Dynamic Properties: Динамические свойства, определенные в ExecuteScript, передаются механизму сценариев в виде переменных, установленные как объект PropertyValue. Это позволяет получить значение свойства, привести значение к соответствующему типу данных, например, логическому и т. д.
Для использования достаточно выбрать Script Engine и указать расположение файла Script File с нашим скриптом или сам скрипт Script Body .
Рассмотрим парочку примеров:
получить один файл потока из очереди
Сгенерировать новый FlowFile
Добавить атрибут к FlowFile
Извлечь и обработать все атрибуты.
В ExecuteScript есть можно использовать расширенные возможности, подробнее об этом можно почитать в статье ExecuteScript Cookbook.
ExecuteGroovyScript
ExecuteGroovyScript имеет такой же функционал, что и ExecuteScript, но вместо зоопарка допустимых языков можно использовать только один – groovy. Главное преимущество этого процессора – это более удобное использование служб сервисов. Помимо стандартного набора переменных Session, Context и т.д. можно определить динамические свойства с префиксом CTL и SQL. Начиная с версии 1.11 появилась поддержка RecordReader и Record Writer. Все свойства представляют собой HashMap, у которого в качестве ключа используется «Имя сервиса», а значение – это конкретный объект в зависимости от свойства:
Данная информация уже облегчает жизнь, т.к. мы можем заглянуть в исходники или найти документацию по конкретному классу.
Работа с базой данных
Если определить свойство SQL.DB и связать DBCPService, то мы получим доступ к свойству из кода SQL.DB.rows(‘select * from table’)
Процессор автоматически принимает соединение от службы dbcp перед выполнением и обрабатывает транзакцию. Транзакции базы данных автоматически откатываются при возникновении ошибки и фиксируются в случае успеха. В ExecuteGroovyScript можно перехватывать события start и stop, реализовав соответствующие статические методы.
InvokeScriptedProcessor
Еще один интересный процессор. Для его использования нужно объявить класс, который реализовывает интерфейс implements, и определить переменную processor. Можно определить любые PropertyDescriptor или Relationship, также получить доступ к родительскому ComponentLog’у и определить методы void onScheduled(ProcessContext context) и void onStopped(ProcessContext context). Эти методы будут вызваны при наступлении события запуска по расписанию в NiFi (onScheduled) и при остановке (onScheduled).
Логику надо реализовать в методе void onTrigger(ProcessContext context, ProcessSessionFactory sessionFactory)
Описывать все методы, декларированные в интерфейсе излишне, так что обойдемся одним абстрактным классом, в котором объявим следующий метод:
Метод мы будем вызывать в
Теперь объявим класс-наследник BaseGroovyProcessor и опишем наш executeScript, также добавим Relationship RELSUCCESS и RELFAILURE.
В конец кода добавим processor = new InvokeScripted()
Такой подход похож на создание кастомного процессора.
Заключение
Создание кастомного процессора не самая простая вещь – в первый раз придется поднапрячься, чтобы разобраться, зато польза от этого действия неоспорима.
Пост подготовлен Командой управления данными Ростелекома