...

суббота, 27 февраля 2016 г.

Apple наняла на работу автора Signal

TOM.js — особая библиотека, для особых случаев

Протокол Handlersocket в деталях

[Перевод] Как создать свой собственный Dependency Injection Container

Привет всем!
Это вольный перевод статьи How to Build Your Own Dependency Injection Container.
Т.к. это мой первый перевод для хабра, да и вообще. Прошу указывать на ошибки, неточности итд..

Как создать свой собственный Dependency Injection Container.


Поиск “dependency injection container” на packagist на данный момент выдает более 95 страниц результата. С уверенностью можно сказать, что это особое “колесо” уже изобретено.

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

В этой статье мы собираемся учиться делать простой dependency injection container пакет. Весь написанный в статье код, плюс PHPDoc аннатации и unit-тесты с 100% покрытием доступны на GitHub. Все это так же добавлено на Packagist.

Планируем наш Dependency Injection Container


Позвольте нам начать с планирования того что мы хотим чтобы наш контейнер делал.
Хорошее начало это разделить “Dependency Injection Container” на две роли, “Dependency Injection” и “Container”.

Два наиболее распространенных метода для выполнения внедрения зависимости через constructor injection или setter injection. Это передача класса зависимости через конструктор в виде аргумента или вызов метода. Если наш контейнер будет иметь возможность создавать экземпляр и содержать сервисы, он будет способен осуществить оба этих способа.

Чтобы быть контейнером, он должен иметь возможность хранить и извлекать экземпляры сервисов. Это достаточно тривиальная задача по сравнению с созданием сервиса, но это все еще требует некоторого рассмотрения. Пакет container-interop обеспечивает набор интерфейсов которые контейнер может реализовать. Основной интерфейс ContainerInterface который определяет два метода, один для получения сервиса, другой для проверки определен ли сервис.

interface ContainerInterface
{
    public function get($id);
    public function has($id);
}

Опыт других Dependency Injection Containers


Symfony Dependency Injection Container позволяет нам определять сервисы различными способами. В YAML, конфигурация для контейнера может выглядеть так:
parameters:
    # ...
    mailer.transport: sendmail

services:
    mailer:
        class:     Mailer
        arguments: ["%mailer.transport%"]
    newsletter_manager:
        class:     NewsletterManager
        calls:
            - [setMailer, ["@mailer"]]

Путь Symfony разбивать конфигурацию контейнера в конфигурацию параметров и сервисов очень полезна. Это позволяет секретным данным приложения таким как ключи API, ключи шифрования и токены авторизации быть сохраненными параметрами в файлах которые исключены из исходного кода репозитория.

В PHP, та же самая конфигурация компонента Symfony Dependency Injection была бы похожа на это:

use Symfony\Component\DependencyInjection\Reference;

// ...
$container->setParameter('mailer.transport', 'sendmail');

$container
    ->register('mailer', 'Mailer')
    ->addArgument('%mailer.transport%');

$container
    ->register('newsletter_manager', 'NewsletterManager')
    ->addMethodCall('setMailer', array(new Reference('mailer')));

Используя объект Reference в вызове метода setMailer, логика внедрения зависимости может обнаружить что это значение не должно быть передано непосредственно, и заменить его сервисом на который имеется ссылка в контейнере. Это позволяет для обоих значений PHP и других сервисов быть легко внедренными в сервис без путаницы.

Начало работы


Первая вещь которую мы должны сделать это создать директорию и файл composer.json который будет использовать Composer чтобы работал автозагрузчик наших классов. Весь этот файл в данный момент является картой SitePoint\Container пространства имен к директории src.
{
    "autoload": {
        "psr-4": {
            "SitePoint\\Container\\": "src/"
        }
    },
}

Дальше как мы собиралемся сделать наш контейнер будет реализовать интерфейс container-interop, нам нужно чтобы composer загрузил их и добавил в наш composer.json файл:
composer require container-interop/container-interop

Наряду с главным интерфейсом ContainerInterface, пакет container-interop также определяет два интерфейса для исключений. Первый для общих исключений при создании сервиса и другой для исключений когда запрошенный сервис не был найден. Мы также добавим другое исключение к этому списку, для тех ситуаций когда запрошенный параметр не был найден.

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

Создадим папку src и в ней следующие файлы src/Exception/ContainerException.php, src/Exception/ServiceNotFoundException.php и src/Exception/ParameterNotFoundException.php соответственно:

<?php

namespace SitePoint\Container\Exception;

use Interop\Container\Exception\ContainerException as InteropContainerException;

class ContainerException extends \Exception implements InteropContainerException {}

<?php

namespace SitePoint\Container\Exception;

use Interop\Container\Exception\NotFoundException as InteropNotFoundException;

class ServiceNotFoundException extends \Exception implements InteropNotFoundException {}

<?php

namespace SitePoint\Container\Exception;

class ParameterNotFoundException extends \Exception {}

Ссылки в контейнере


Symfony класс Reference рассматриваемый ранее, позволил библиотеке различать PHP значения для непосредственного использования и аргументы которые необходимо заменить другими сервисами в контейнере.

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

Создайте следующие файлы src/Reference/AbstractReference.php, src/Reference/ServiceReference.php и src/Reference/ParameterReference.php соответственно:

<?php

namespace SitePoint\Container\Reference;

abstract class AbstractReference
{
    private $name;

    public function __construct($name)
    {
        $this->name = $name;
    }

    public function getName()
    {
        return $this->name;
    }
}

<?php

namespace SitePoint\Container\Reference;

class ServiceReference extends AbstractReference {}

<?php

namespace SitePoint\Container\Reference;

class ParameterReference extends AbstractReference {}

Класс контейнера


Настало время создать наш контейнер. Мы собираемся начать с базовой схемы нашего класса контейнера, и мы будем добавлять методы в него по ходу дела.

Основная идея принимать два массива в конструктор нашего контейнера. Первый массив должен содержать определения сервиса, а второй определения параметров.

В src/Container.php поместите следующий код:

<?php

namespace SitePoint\Container;

use Interop\Container\ContainerInterface as InteropContainerInterface;

class Container implements InteropContainerInterface
{
    private $services;
    private $parameters;
    private $serviceStore;

    public function __construct(array $services = [], array $parameters = [])
    {
        $this->services     = $services;
        $this->parameters   = $parameters;
        $this->serviceStore = [];
    }
}

Все что мы здесь сделали это реализовали интерфейс ContainerInterface из container-interop и загрузили определения в свойства к которым можно получить доступ позднее. Так же мы создали свойство serviceStore и инициализировали его пустым массивом. Когда контейнер попросят создать сервисы, мы сохраним их в этом массиве так чтобы они могли быть восстановлены позже без необходимости пересоздания их.

Сейчас позвольте нам начать писать методы объявленные в container-interop. Начнем с get($name), добавим следующий метод в класс:

use SitePoint\Container\Exception\ServiceNotFoundException;

// ...
    public function get($name)
    {
        if (!$this->has($name)) {
            throw new ServiceNotFoundException('Service not found: '.$name);
        }

        if (!isset($this->serviceStore[$name])) {
            $this->serviceStore[$name] = $this->createService($name);
        }

        return $this->serviceStore[$name];
    }
// ...


Обязательно добавьте use в начале файла. Наш get($name) метод это простая проверка на наличие в контейнере определения сервиса. Если его нет будет выброшен ServiceNotFoundException который мы создали ранее. Если он есть, возвращает его, создает его и сохраняет в хранилище если он не был уже создан.

Пока мы находимся в нем, нам следует создать метод для извлечения параметров из контейнера. Принимая параметры преданные в конструктор из n-мерного ассоциативного массива, нам необходим способ чистого доступа к любому элементу в пределах массива используя единственную строку. Простой способ сделать это, использовать точку как разделитель, так чтобы строка foo.bar ссылалась на ключ bar в ключе foo из корня массива параметров.

use SitePoint\Container\Exception\ParameterNotFoundException;

// ...
    public function getParameter($name)
    {
        $tokens  = explode('.', $name);
        $context = $this->parameters;

        while (null !== ($token = array_shift($tokens))) {
            if (!isset($context[$token])) {
                throw new ParameterNotFoundException('Parameter not found: '.$name);
            }

            $context = $context[$token];
        }

        return $context;
    }
// ...

Сейчас мы использовали пару методов которые мы еще не написали. Первый из них has($name), который объявлен в container-interop. Это довольно простой метод и ему просто нужно проверить если массив определений предоставляемый конструктору содержит $name сервис.
// ...
    public function has($name)
    {
        return isset($this->services[$name]);
    }
// ...

Другой метод который нам предстоит написать createService($name). Это метод будет использовать определения предоставленные для создания сервиса. Поскольку мы не хотим чтобы этот метод был вызван снаружи контейнера, мы сделаем его приватным.

Первая вещь которую нужно сделать в этом методе это некоторые разумные проверки.
Для каждого объявленного сервиса мы требуем массив содержащий ключ class и необязательные ключи arguments и calls. Они будут использоваться для внедрения конструктора и сеттера соответственно. Мы можем так же добавить защиту от зацикливания ссылок, проверив, попытались ли мы уже создать сервис.

Если ключ arguments существует мы хотим преобразовать тот массив определений аргумента в массив PHP значений который можно предать конструктору. Для того чтобы сделать это нам необходимо преобразовать справочник объектов который мы объявили ранее в значения на которые ссылаются в контейнере. На данный момент мы будем использовать эту логику в методе resolveArguments($name, array $argumentDefinitons).
Мы используем метод ReflectionClass::newInstanceArgs() для создания сервиса используя массив arguments. Это внедрение конструктора.

Если ключ calls существует, мы хотим использовать массив call definitions и применить его к сервису который мы только что создали. Снова мы будем использовать логику в отдельном методе определенном как initializeService($service, $name, array $callDefinitions). Это внедрение сеттера.

use SitePoint\Container\Exception\ContainerException;

// ...
    private function createService($name)
    {
        $entry = &$this->services[$name];

        if (!is_array($entry) || !isset($entry['class'])) {
            throw new ContainerException($name.' service entry must be an array containing a \'class\' key');
        } elseif (!class_exists($entry['class'])) {
            throw new ContainerException($name.' service class does not exist: '.$entry['class']);
        } elseif (isset($entry['lock'])) {
            throw new ContainerException($name.' service contains a circular reference');
        }

        $entry['lock'] = true;

        $arguments = isset($entry['arguments']) ? $this->resolveArguments($name, $entry['arguments']) : [];

        $reflector = new \ReflectionClass($entry['class']);
        $service = $reflector->newInstanceArgs($arguments);

        if (isset($entry['calls'])) {
            $this->initializeService($service, $name, $entry['calls']);
        }

        return $service;
    }
// ...

Нам осталось создать два финальных метода. Первый должен преобразовать массив аргументов объявлений в массив PHP значений. Чтобы это сделать нужно заменить объекты ParameterReference и ServiceReference соответствующими параметрами и сервисами из контейнера.
use SitePoint\Container\Reference\ParameterReference;
use SitePoint\Container\Reference\ServiceReference;

// ...
    private function resolveArguments($name, array $argumentDefinitions)
    {
        $arguments = [];

        foreach ($argumentDefinitions as $argumentDefinition) {
            if ($argumentDefinition instanceof ServiceReference) {
                $argumentServiceName = $argumentDefinition->getName();

                $arguments[] = $this->get($argumentServiceName);
            } elseif ($argumentDefinition instanceof ParameterReference) {
                $argumentParameterName = $argumentDefinition->getName();

                $arguments[] = $this->getParameter($argumentParameterName);
            } else {
                $arguments[] = $argumentDefinition;
            }
        }

        return $arguments;
    }

Последний метод выполняет внедрение сеттера в экземпляр объекта сервиса. Чтобы сделать это необходимо перебрать массив определений при вызове метода. Ключ method используется для указания метода и необязательный ключ arguments может быть использован для предоставления аргументов этому методу. Мы можем использовать метод который мы только что написали, для перевода его аргументов в PHP значения.
private function initializeService($service, $name, array $callDefinitions)
    {
        foreach ($callDefinitions as $callDefinition) {
            if (!is_array($callDefinition) || !isset($callDefinition['method'])) {
                throw new ContainerException($name.' service calls must be arrays containing a \'method\' key');
            } elseif (!is_callable([$service, $callDefinition['method']])) {
                throw new ContainerException($name.' service asks for call to uncallable method: '.$callDefinition['method']);
            }

            $arguments = isset($callDefinition['arguments']) ? $this->resolveArguments($name, $callDefinition['arguments']) : [];

            call_user_func_array([$service, $callDefinition['method']], $arguments);
        }
    }
}

И сейчас мы имеем готовый dependency injection container! Чтобы увидеть примеры использования, проверьте репозиторий на GitHub.

Окончание мысли


Мы изучили как создать простой dependency injection container, но есть множество контейнеров с замечательными функциями которые наш еще не имеет.

Некоторые dependency injection containers, такие как PHP-DI и Aura.DI предоставляют особенность которая называется автоматическое подключение. Это где контейнер догадывается какие сервисы из контейнера следует внедрить в другие. Чтобы сделать это они используют reflection API для поиска информации о параметрах конструктора.

Полезен ли был данный перевод?

Проголосовало 17 человек. Воздержалось 14 человек.

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

Комментарии (0)

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.

Патчим gnupg или пара RSA-32768 за 106 минут

Эксперимент: создание алгоритма для прогнозирования поведения фондовых индексов

пятница, 26 февраля 2016 г.

[Перевод] Go с точки зрения PHP программиста

[Перевод] DevTips: Советы веб-разработчику (49-64)

Привет, Хабр! В этот прекрасный пятничный день предлагаем вам ознакомиться с очередной частью цикла переводов советов для веб-разработчиков. Предыдущие части: 1-16, 17-32, 33-48.

Содержание:

   49   Циклическое переключение между панелями при помощи шорткатов
   50   Проверка и активация CSS media queries, а также нахождение этих правил в коде
   51   Предустановка разрешения нового устройства
   52   Улучшения полоски хлебных крошек в панели Elements
   53   Печать стектрейса в консоли
   54   Детектирование долгих фреймов (не путать с iframe)
   55   Продвинутая фильтрация запросов в панели «Network»
   56   Поиск по проекту с возможностью указания файла
   57   Новый экспериментальный редактор раскладки страницы
   58   Дублирование DOM-элементов
   59   Просмотр скриншотов поведения страницы
   60   Редактирование html-кода в панели «Console»
   61   Простые клавиатурные трюки для управления панелей «Стили»
   62   Выбор цвета, сгенерированного палитрой
   63   Инкремент и декремент чисел в DOM-атрибутах
   64   Сетевые запросы в панели «Timeline»

49. Циклическое переключение между панелями при помощи шорткатов


Используйте Cmd + ] / Cmd + [ для циклического переключениями между панелями в DevTools. Кроме этого существует шорткат Cmd + Alt + i для открытия инструментов разработчика.
Посмотреть скринкаст

50. Проверка и активация CSS media queries, а также нахождение этих правил в коде


В деле инспектирования и активации зарегистрированных CSS media queries вам поможет инструмент Media Query Inspector. Чтобы его открыть, в режиме устройства (Device Mode) кликните на иконку, напоминающую лесенку, в верхнем левом углу страницы. Вы можете активировать различные точки останова простым кликом на появившиеся полосы. При этом правых клик на них позволяет открыть конкретную место в коде, где эта Media Query определена.
Посмотреть скринкаст

51. Предустановка разрешения нового устройства


Часто ли вам приходится эмулировать разрешение нового устройства? Режим Device Mode позволяет задать и запомнить профиль такого аппарата.
  1. Откройте панель Devices в настройках DevTools.
  2. Выберите Add custom device.
  3. Введите информацию об устройстве.
  4. Нажмите на Add Device.

Добавленное выше устройство появится в меню Devices в верхнем левом углу.
Посмотреть скринкаст

52. Улучшения полоски хлебных крошек в панели Elements


А вы знали, что в панели Elements есть «хлебные крошки»? Они могут помочь вам отслеживать полную вложенность, когда вы работаете с DOM-деревом. Активируйте экспериментальный Material Design в Canary и вы получите несколько приятных фич:
  • В новом дизайне «хлебные крошки» смотрятся гораздо лучшее.
  • Теперь они находятся сверху панели Elements, что улучшает их видимость.
  • В общем, интерфейс DevTools стал выглядеть более структуризированным.

Не забывайте, что по клику на конкретный сегмент «хлебных крошек» будет подсвечен соответствующий DOM-элемент.
Посмотреть скринкаст

53. Печать стектрейса в консоли


Вызов функции console.trace() может вам помочь быстро и легко получить стектрейс для лучшего понимания потока управления вашей программы.

Его особенности:

  • Вы получите имена файлов и номера строк, кликнув по которым вы переместитесь в соответствующее место кода.
  • console.trace совместим со сниппетами.
  • Этот метод является часть Console API (наряду с console.log).

Посмотреть скринкаст

54. Детектирование долгих фреймов (не путать с iframe)


Панель Timeline в Canary может подсвечивать некоторые фреймы красным. Это предупреждение означает, что время нахождения в нем вышло за рамки 18мс. При клике на конкретный фрейм вы получите детальную информацию о причинах возникновения проблемы. Если частота обновления монитора 60Гц (так делают большинство дисплеев), то на фрейм должно приходится не более 16мс, потому что 1000мс / 60 кадров в секунду = ~16мс.
Посмотреть скринкаст

55. Продвинутая фильтрация запросов в панели «Network»


Для того, чтобы уменьшить количество найденных сетевых запросов, используйте продвинутую фильтрацию:
  • larger-than:100 выведет вам все ресурсы, размер которых превышает 100 байт.
  • -larger-than:50k найдет все запросы, не превышающие 50Кб.
  • status-code:200 покажет все ответы со статусом 200.

Вот еще несколько запросов, с которыми вы можете поэкспериментировать:
  • domain
  • mime-type
  • scheme
  • set-cookie-domain
  • set-cookie-value
  • has-response-header

Автодополнение поиска поможет вам обнаружить все фильтры и определить тип их значений. При этом все показанные значения взяты из записанных запросов при последней сессии.
Посмотреть скринкаст

56. Поиск по проекту с возможностью указания файла


Вы можете искать по всем файлам при помощи шортката Cmd + Opt + F / Ctrl + Shift + F. Если поиск вернет слишком много результатов, вы можете ограничить выборку, указав конкретный файл, поменяв запрос query на query file:main.js или query file:main.
Посмотреть скринкаст

57. Новый экспериментальный редактор раскладки страницы


Layout Editor — скрытый эксперимент средств разработчика Canary. Хотя некоторая функциональность из этого инструмента может измениться или вовсе исчезнуть, я расскажу кое-что о нем:
  • Когда вы инспектируете элемент, рядом с его границами появляются маркеры.
  • Потянув за них, вы измените отступы (margin или padding) этого узла.
  • Эти маркеры также отображают текущее значение отступов в процессе их изменения.

Посмотреть скринкаст

58. Дублирование DOM-элементов


DevTools позволяют очень просто модифицировать DOM-дерево, не меняя при этом куски html-кода.
  • Кликните на элементе в панели Elements правой кнопкой и выберите Copy.
  • Теперь вы можете вставить этот элемент в текстовый редактор или, для прототипирования, в любое другое место DOM-дерева. Скопированный узел добавляется в качестве ребенка выбранного элемента. В видео я поднимался от дочернего узла к родительскому при помощи для того, чтобы вставить элемент в него.

Кроме этого вам доступка функция Cut (также она вызывается по Cmd + x / Ctrl + x). В противовес копирования, она переместит элемент на новое место в дереве.

Эксперимент: Попробуйте добавить больше ссылок в хедер/футер какого-нибудь сайта при помощи техники копирования-вставки и выяснить, какие места верстки требуют улучшения!

Посмотреть скринкаст

59. Просмотр скриншотов поведения страницы


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

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

Посмотреть скринкаст

60. Редактирование html-кода в панели «Console»


Контекстное меню DOM-элемента, знакомое вам по панели Elements также доступно и в панели Console.
  1. Отлогируйте DOM-узел в консоль и вызовите его контекстное меню.
  2. Выберите Edit as HTML или Edit Text и отредактируйте его.
  3. Заметьте, что оригинальный узел в панели Elements будет также изменен.

Посмотреть скринкаст

61. Простые клавиатурные трюки для управления панелей «Стили»


Клавиша Tab позволяет вам навигироваться по CSS-свойствам в следующей порядке:
  • Селектор (например, h1)
  • Свойство (например, color)
  • Значение (например, green)

В случае достижения конца CSS-правила курсор будет перенесен на следующее. Кроме этого сочетание Shift + Tab переключает фокус в обратную сторону. Предположим, в поле названия правила вы начали вводить back с намерением выбрать background из вариантов выпадающей подсказки, но случайно ошиблись и выбрали background-color. В этом случае просто нажмите клавишу Backspace, и вы будете перемещены обратно к редактированию названия свойства.

Для удаления свойства вы можете стереть его название или значение при помощи Backspace, а дальше просто нажмите Enter.

Посмотреть скринкаст

62. Выбор цвета, сгенерированного палитрой


Инструмент выбора цвета (Color Picker) в Canary DevTools снова получил обновление. Теперь он получил новую цветовую палитру, генерирующуюся автоматически на основании набора цветов, уже представленных в ваших таблицах стилей.
Посмотреть скринкаст

63. Инкремент и декремент чисел в DOM-атрибутах


Вы можете модифицировать DOM-атрибут так же, как и название класса при помощи клавиш / . Предположим, что на некотором элементе висит класс span_1_of_7, стрелка в этом случае трансформирует его в span_2_of_7.

Эта возможность может быть очень полезной, если вы используете систему CSS-сеток, которая включает в имена классов элементов конкретные числа.

Посмотреть скринкаст

64. Сетевые запросы в панели «Timeline»


Разработчики Canary DevTools сделали новый эксперимент Network on Timeline: теперь панель Timeline отображает сетевые запросы, которые могли бы влиять на процесс отображения страницы.
Посмотреть скринкаст

Комментарии (0)

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.

Пятничный формат: ДНК и решение проблемы хранения данных

По мнению сотрудников компании Backblaze, которая не так давно провела эксперимент по вычислению длительности работы жестких дисков, некоторые HDD способны хранить информацию без повреждений порядка 10 лет – не так уж и много.

К сожалению, современные запоминающие устройства не могут служить вечно. Именно поэтому исследователи стараются найти способ, позволяющий хранить данные как можно дольше – в идеале несколько миллионов лет.

Вечный накопитель


Исследователи из Швейцарской высшей технической школы Цюриха считают, что ответ может лежать в ДНК. По словам Питера Шэндболта (Peter Shandbolt), написавшего материал о перспективах хранения данных для блога CNN, структура нитей ДНК сложна и в то же время компактна, так что «один грамм ДНК теоретически способен вместить все данные таких крупных компаний, как Google и Facebook, причем даже с запасом».

Говоря техническим языком, в одном грамме ДНК может храниться до 455 экзабайтов информации, где один экзабайт равен миллиарду гигабайтов.

Процесс синтеза последовательности ДНК похож на нанизывание жемчуга на нитку. В этом случае информация кодируется в виде традиционных нулей и единиц.

Эти значения присваиваются определенным химическим компонентам, мономерам, которые при помощи химических методов сцепляются в одну цепь, образуя полимеры. Чтобы прочитать записанную информацию, достаточно воспользоваться масс-спектрометром – устройством для считывания ДНК-последовательности.

Знаменитая двойная спираль ДНК

«Ископаемые» данные


Информация о геноме живого организма может достаточно долго сохраняться в окаменелостях: так был расшифрован геном полярного медведя, жившего 110 000 лет назад, и геном лошади, возраст которой составляет 700 000 лет.

По словам представителей Швейцарской высшей технической школы Цюриха (ETH Zurich), они хотят «совместить возможности хранения на ДНК большого объема данных со стабильностью ДНК, обнаруженных в ископаемых останках».

«Мы отыскали необычные способы работы с ДНК, позволяющие сделать ее достаточно стабильной, – сообщает Роберт Грасс, преподаватель кафедры химии и прикладных биологических наук ETH Zurich, в интервью CNN. – Мы хотели связать воедино возможности ДНК, а именно высокую емкость хранения данных и ее археологические особенности».

Таким образом, процесс хранения информации будет выглядеть так: ДНК, заключенная в стеклянную оболочку (инертную и нейтральную среду), хранится при низкой температуре и в сухом состоянии (на ДНК негативно влияют вода и кислород).

В таких условиях информация в её нитях может оставаться неповреждённой на протяжении нескольких тысяч лет.

«Мы смогли добиться того, что созданная нами ДНК с сохраненной на ней информацией распадается с такой же скоростью, что и ДНК, найденная в окаменелостях. Если так пойдет дальше, вскоре у нас появится возможность сохранить данные на срок до миллиона лет».

Первые результаты


Для проверки того, как долго данные могут хранится в ДНК, ученые закодировали 83 килобайта данных.

Материалом послужили Швейцарский Федеральный устав от 1291 года и палимпсест Архимеда. Выбор этих документов, по мнению ученых, показывает не только потенциальную применимость метода, но и его историческую важность. По оценкам представителей ETH Zurich, эти данные останутся неизменными от 10 000 до миллиона лет (если ДНК подвергнется заморозке).

Если говорить о количестве информации, то Джордж Черч (George Church), профессор генетики из института Вайса (Гарвард), поставил все предыдущие рекорды по количеству записанных данных в ДНК на колени, ему с коллегами удалось добиться плотности записи в 5,5 петабитов (около 700 терабайт) на кубический миллиметр жидкости – он создал 70 миллиардов копий своей книги по генетике. Для современных электронных носителей такие показатели пока являются недостижимыми.

Однако, как и всегда, в работе с ДНК-хранилищами есть свои сложности, например стоимость шифрования данных. Однако исследователи уверены, что по мере развития медицинских технологий, она будет снижаться.

«Раньше стоимость расшифровки генома человека составляла несколько миллионов долларов. Сегодня ее можно провести за несколько сотен долларов, – заявляет Грасс. – Новые технологии для проведения медицинского и геномного анализа можно будет вскоре внедрить и в мир IT».

Но самым большим препятствием, которое пока еще не позволяет использовать ДНК для хранения информации на практике, является время.

Даже с использованием современных технологий расшифровки, чтение молекулы ДНК занимает многие часы – на несколько порядков больше, чем чтение обычного файла на компьютере. Потому этот тип хранилищ не подходит для часто используемых данных.

Однако они отлично подойдут на роль надежных долговременных хранилищ – например, это отличный вариант для создания «капсул времени».

P.S. Материалы по теме из нашего блога:

Комментарии (0)

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.

Web файловый менеджер Sprut.IO в OpenSource

Платы для разработчиков и терминал на основе российского микропроцессора Байкал-Т

Пример использования возможностей инвентаризации и отчетов в System Center Configuration Manager

[Перевод] Segmentation Fault (распределение памяти компьютера)

Когда я делаю ошибку в коде, то обычно это приводит к появлению сообщения “segmentation fault”, зачастую сокращённого до “segfault”. И тут же мои коллеги и руководство приходят ко мне: «Ха! У нас тут для тебя есть segfault для исправления!» — «Ну да, виноват», — обычно отвечаю я. Но многие ли из вас знают, что на самом деле означает ошибка “segmentation fault”?

Чтобы ответить на этот вопрос, нам нужно вернуться в далёкие 1960-е. Я хочу объяснить, как работает компьютер, а точнее — как в современных компьютерах осуществляется доступ к памяти. Это поможет понять, откуда же берётся это странное сообщение об ошибке.

Вся представленная ниже информация — основы компьютерной архитектуры. И без нужды я не буду сильно углубляться в эту область. Также я буду применять всем известную терминологию, так что мой пост будет понятен всем, кто не совсем на «вы» с вычислительной техникой. Если же вы захотите изучить вопрос работы с памятью подробнее, то можете обратиться к многочисленной доступной литературе. А заодно не забудьте покопаться в исходном коде ядра какой-нибудь ОС, например, Linux. Я не буду излагать здесь историю вычислительной техники, некоторые вещи не будут освещаться, а некоторые сильно упрощены.

Немного истории


Когда-то компьютеры были очень большими, весили тонны, при этом обладали одним процессором и памятью примерно на 16 Кб. Стоил такой монстр порядка $150 000 и мог выполнять лишь одну задачу за раз: в каждый момент времени выполнялся только один какой-то процесс. Архитектуру памяти в те времена можно схематически представить так:

То есть на ОС приходилась, скажем, четверть всей доступной памяти, а остальной объём отдавался под пользовательские задачи. В то время роль ОС заключалась в простом управлении оборудованием с помощью прерываний ЦПУ. Так что операционке нужна была память для себя, для копирования данных с устройств и для работы с ними (режим PIO). Для вывода данных на экран нужно было использовать часть основной памяти, ведь видеоподсистема либо не имела своей оперативки, либо обладала считанными килобайтами. А уже сама программа выполнялась в области памяти, идущей сразу после ОС, и решала свои задачи.

Совместный доступ к ресурсам


Главная проблема заключалась в том, что устройство, стоящее $150 000, было однозадачным и тратило целые дни на обработку нескольких килобайт данных.

Из-за непомерной стоимости мало кто мог позволить себе приобрести сразу несколько компьютеров, чтобы обрабатывать одновременно несколько задач. Поэтому люди начали искать способы совместного доступа к вычислительным ресурсам одного компьютера. Так наступила эра многозадачности. Обратите внимание, что в те времена ещё никто не помышлял о многопроцессорных компьютерах. Так как же можно заставить компьютер с одним ЦПУ выполнять несколько разных задач?

Решением стало использование планировщика задач (scheduling): пока один процесс прерывался, ожидая завершения операций ввода/вывода, ЦПУ мог выполнять другой процесс. Я не буду здесь больше касаться планировщика задач, это слишком обширная тема, не имеющая отношения к памяти.

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

Задачи А и В хранятся в памяти, поскольку копировать их на диск и обратно слишком затратно. И по мере того, как процессор выполняет ту или иную задачу, он обращается к памяти за соответствующими данными. Но тут возникает проблема.

Когда один программист будет писать код для выполнения задачи В, он должен знать границы выделяемых сегментов памяти. Допустим, задача В занимает в памяти отрезок от 10 до 12 Кб, тогда каждый адрес памяти должен быть жёстко закодирован в пределах этих границ. Но если компьютер будет выполнять сразу три задачи, то память будет поделена на большее количество сегментов, и значит сегмент для задачи В может оказаться сдвинут. Тогда код программы придётся переписывать, чтобы она могла оперировать меньшим объёмом памяти, а также изменить все указатели.

Здесь всплывает и иная проблема: что если задача В обратится к сегменту памяти, выделенному для задачи А? Такое легко может произойти, ведь при работе с указателями памяти достаточно сделать маленькую ошибку, и программа будет обращаться к совершенно другому адресу, нарушив целостность данных другого процесса. При этом задача А может работать с очень важными с точки зрения безопасности данными. Нет никакого способа помешать В вторгнуться в область памяти А. Наконец, вследствие ошибки программиста задача В может перезаписать область памяти ОС (в данном случае от 0 до 4 Кб).

Адресное пространство


Чтобы можно было спокойно выполнять несколько задач, хранящихся в памяти, нам нужна помощь от ОС и оборудования. В частности, адресное пространство. Это некая абстракция памяти, выделяемая ОС для какого-то процесса. На сегодняшний день это фундаментальная концепция, которая используется везде. По крайней мере, во ВСЕХ компьютерах гражданского назначения принят именно этот подход, а у военных могут быть свои секреты. Персоналки, смартфоны, телевизоры, игровые приставки, умные часы, банкоматы — ткните в любой аппарат, и окажется, что распределение памяти в нём осуществляется по принципу «код-стек-куча» (code-stack-heap).

Адресное пространство содержит всё, что нужно для выполнения процесса:

  • Машинные инструкции, которые должен выполнить ЦПУ.
  • Данные, с которыми будут работать эти машинные инструкции.

Схематически адресное пространство делится следующим образом:

  • Стек (stack) — это область памяти, в которой программа хранит информацию о вызываемых функциях, их аргументах и каждой локальной переменной в функциях. Размер области может меняться по мере работы программы. При вызове функций стек увеличивается, а при завершении — уменьшается.
  • Куча (heap) — это область памяти, в которой программа может делать всё, что заблагорассудится. Размер области может меняться. Программист имеет возможность воспользоваться частью памяти кучи с помощью функции malloc(), и тогда эта область памяти увеличивается. Возврат ресурсов осуществляется с помощью free(), после чего куча уменьшается.
  • Кодовый сегмент (code) — это область памяти, в которой хранятся машинные инструкции скомпилированной программы. Они генерируются компилятором, но могут быть написаны и вручную. Обратите внимание, что эта область памяти также может быть разделена на три части (текст, данные и BSS). Эта область памяти имеет фиксированный размер, определяемый компилятором. В нашем примере пусть это будет 1 Кб.

Поскольку стек и куча могут меняться в размерах, они размещены в противоположных частях общего адресного пространства. Направления изменения их размеров показаны стрелками. В обязанности ОС входит контроль над тем, чтобы эти области не наложились друг на друга.

Виртуализация памяти


Допустим, задача А получила в своё распоряжение всю доступную пользовательскую память. И тут возникает задача В. Как быть? Решение было найдено в виртуализации.

Напомню одну из предыдущих иллюстраций, когда в памяти одновременно находятся А и В:

Допустим, А пытается получить доступ к памяти в собственном адресном пространстве, например по индексу 11 Кб. Возможно даже, что это будет её собственный стек. В этом случае ОС нужно придумать, как не подгружать индекс 1500, поскольку по факту он может указывать на область задачи В.

На самом деле, адресное пространство, которое каждая программа считает своей памятью, является памятью виртуальной. Фальшивкой. И в области памяти задачи А индекс 11 Кб будет фальшивым адресом. То есть — адресом виртуальной памяти.

Каждая программа, выполняющаяся на компьютере, работает с фальшивой (виртуальной) памятью. С помощью некоторых чипов ОС обманывает процесс, когда он обращается к какой-либо области памяти. Благодаря виртуализации ни один процесс не может получить доступ к памяти, которая ему не принадлежит: задача А не влезет в память задачи В или самой ОС. При этом на пользовательском уровне всё абсолютно прозрачно, благодаря обширному и сложному коду ядра ОС.

Таким образом, каждое обращение к памяти регулируется операционной системой. И это должно осуществляться очень эффективно, чтобы не слишком замедлять работу различных выполняющихся программ. Эффективность обеспечивается с помощью аппаратных средств, преимущественно — ЦПУ и некоторых компонентов вроде MMU. Последний появился в виде отдельного чипа в начале 1970-х, а сегодня MMU встраиваются непосредственно в процессор и в обязательном порядке используются операционными системами.

Вот небольшая программка на С, демонстрирующая работу с адресами памяти:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    int v = 3;
    printf("Code is at %p \n", (void *)main);
    printf("Stack is at %p \n", (void *)&v);
    printf("Heap is at %p \n", malloc(8));

    return 0;
}


На моей машине LP64 X86_64 она показывает такой результат:

Code is at 0x40054c
Stack is at 0x7ffe60a1465c
Heap is at 0x1ecf010

Как я и описывал, сначала идёт кодовый сегмент, затем стек, а затем куча. Но все эти три адреса фальшивые. В физической памяти по адресу 0x7ffe60a1465c вовсе не хранится целочисленная переменная со значением 3. Никогда не забывайте, что все пользовательские программы манипулируют виртуальными адресами, и только на уровне ядра или аппаратных драйверов допускается использование адресов физической памяти.

Переадресация


Переадресация (транслирование, перевод, преобразование адресов) — это термин, обозначающий процесс сопоставления виртуального адреса физическому. Занимается этим модуль MMU. Для каждого выполняющегося процесса операционка должна помнить соответствия всех виртуальных адресов физическим. И это довольно непростая задача. По сути, ОС приходится управлять памятью каждого пользовательского процесса при каждом обращении. Тем самым она превращает кошмарную реальность физической памяти в полезную, мощную и лёгкую в использовании абстракцию.

Давайте рассмотрим подробнее.

Когда запускается процесс, ОС бронирует для него фиксированный объём физической памяти, пусть это будет 16 Кб. Начальный адрес этого адресного пространства сохраняется в специальной переменной base. А в переменной bounds записывается размер выделенной области памяти, в нашем примере — 16 Кб. Эти два значения записываются в каждую таблицу процессов — PCB (Process Control Block).

Итак, это виртуальное адресное пространство:

А это его физический образ:

ОС решает выделить диапазон физических адресов от 4 до 20 Кб, то есть значение base равно 4 Кб, а значение bounds равно 4 + 16 = 20 Кб. Когда процесс ставится в очередь на выполнение (ему выделяется процессорное время), ОС считывает из PCB значения обеих переменных и копирует их в специальные регистры ЦПУ. Далее процесс запускается и пытается обратиться, допустим, к виртуальному адресу 2 Кб (в своей куче). К этому адресу ЦПУ добавляет значение base, полученное от ОС. Следовательно, физический адрес будет 2+ 4 = 6 Кб.

Физический адрес = виртуальный адрес + base

Если получившийся физический адрес (6 Кб) выбивается из границ выделенной области (4—20 Кб), это означает, что процесс пытается обратиться к памяти, которая ему не принадлежит. Тогда ЦПУ генерирует исключение и сообщает об этом ОС, которая обрабатывает данное исключение. В этом случае система обычно сигнализирует процессу о нарушении: SIGSEGV, Segmentation Fault. Этот сигнал по умолчанию прерывает выполнение процесса (это можно настраивать).

Перераспределение памяти


Если задача А исключена из очереди на выполнение, то это даже лучше. Это означает, что планировщик попросили выполнить другую задачу (допустим, В). Пока выполняется В, операционка может перераспределить всё физической пространство задачи А. Во время выполнения пользовательского процесса ОС зачастую теряет управление процессором. Но когда процесс делает системный вызов, процессор снова возвращается под контроль ОС. До этого системного вызова операционка может что угодно делать с памятью, в том числе и целиком перераспределять адресное пространство процесса в другой физический раздел.

В нашем примере это осуществляется достаточно просто: ОС перемещает 16-килобайтную область в другое свободное место подходящего размера и просто обновляет значения переменных base и bounds для задачи А. Когда процессор возвращается к её выполнению, процесс переадресации всё ещё работает, но физическое адресное пространство уже изменилось.

С точки зрения задачи А ничего не меняется, её собственное адресное пространство по-прежнему расположено в диапазоне 0-16 Кб. При этом ОС и MMU полностью контролируют каждое обращение задачи к памяти. То есть программист манипулирует виртуальной областью 0-16 Кб, а MMU берёт на себя сопоставление с физическими адресами.

После перераспределения образ памяти будет выглядеть так:

Программисту теперь не нужно заботиться о том, с какими адресами памяти будет работать его программа, не нужно переживать о конфликтах. ОС в связке с MMU снимают с него все эти заботы.

Сегментация памяти


В предыдущих главах мы рассмотрели вопросы переадресации и перераспределения памяти. Однако у нашей модели работы с памятью есть ряд недостатков:
  • Мы предполагаем, что каждое виртуальное адресное пространство имеет размер в 16 Кб. Это не имеет никакого отношения к действительности.
  • ОС приходится поддерживать список свободных диапазонов физической памяти размером по 16 Кб, чтобы выделять их для новых запускаемых процессов или перераспределения текущих выделенных областей. Как можно эффективно осуществлять всё это, не ухудшив производительность всей системы?
  • Мы выделяем по 16 Кб каждому процессу, но ведь не факт, что каждый из них будет использовать всю выделенную область. Так что мы просто теряем кучу памяти на пустом месте. Это называется внутренней фрагментацией (internal fragmentation) — память резервируется, но не используется.

Для решения некоторых из этих проблем давайте рассмотрим более сложную систему организации памяти — сегментацию. Смысл её прост: принцип “base and bounds” распространяется на все три сегмента памяти — кучу, кодовый сегмент и стек, причём для каждого процесса, вместо того чтобы рассматривать образ памяти как единую уникальную сущность.

В результате мы больше не теряем память между стеком и кучей:

Как вы могли заметить, свободное пространство в виртуальной памяти задачи А больше не размещено в памяти физической. И память теперь используется гораздо эффективнее. ОС теперь должна запоминать для каждой задачи три пары base и bounds, по одной для каждого сегмента. MMU, как и раньше, занимается переадресацией, но оперирует уже тремя base
и тремя bounds.

Допустим, у кучи задачи А параметр base равен 126 Кб, а bounds — 2 Кб. Пусть задача А обращается к виртуальному адресу 3 Кб (в куче). Тогда физический адрес определяется как 3 – 2 Кб (начало кучи) = 1 Кб + 126 Кб (сдвиг) = 127 Кб. Это меньше 128, а значит ошибки обращения не будет.

Совместное использование сегментов


Сегментирование физической памяти не только не позволяет виртуальной памяти отъедать физическую, но также даёт возможность совместного использования физических сегментов с помощью виртуальных адресных пространств разных процессов.

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

При этом оба процесса не подозревают, что делят с кем-то свою память. Такой подход стал возможен благодаря внедрению битов защиты сегмента (segment protection bits).

Для каждого создаваемого физического сегмента ОС регистрирует значение bounds, которое используется MMU для последующей переадресации. Но в то же время регистрируется и так называемый флаг разрешения (permission flag).

Поскольку сам код нельзя модифицировать, то все кодовые сегменты создаются с флагами RX. Это значит, что процесс может загружать эту область памяти для последующего выполнения, но в неё никто не может записывать. Другие два сегмента — куча и стек — имеют флаги RW, то есть процесс может считывать и записывать в эти свои два сегмента, однако код из них выполнять нельзя. Это сделано для обеспечения безопасности, чтобы злоумышленник не мог повредить кучу или стек, внедрив в них свой код для получения root-прав. Так было не всегда, и для высокой эффективности этого решения требуется аппаратная поддержка. В процессорах Intel это называется “NX bit”.

Флаги могут быть изменены в процессе выполнения программы, для этого используется mprotect().

Под Linux все эти сегменты памяти можно посмотреть с помощью утилит /proc/{pid}/maps или /usr/bin/pmap.

Вот пример на PHP:

$ pmap -x 31329
0000000000400000   10300    2004       0 r-x--  php
000000000100e000     832     460      76 rw---  php
00000000010de000     148      72      72 rw---    [ anon ]
000000000197a000    2784    2696    2696 rw---    [ anon ]
00007ff772bc4000      12      12       0 r-x--  libuuid.so.0.0.0
00007ff772bc7000    1020       0       0 -----  libuuid.so.0.0.0
00007ff772cc6000       4       4       4 rw---  libuuid.so.0.0.0
... ...


Здесь есть все необходимые подробности относительно распределения памяти. Адреса виртуальные, отображаются разрешения для каждой области памяти. Каждый совместно используемый объект (.so) размещён в адресном пространстве в виде нескольких частей (обычно код и данные). Кодовые сегменты являются исполняемыми и совместно используются в физической памяти всеми процессами, которые разместили подобный совместно используемый объект в своём адресном пространстве.

Shared Objects — это одно из крупнейших преимуществ Unix- и Linux-систем, обеспечивающее экономию памяти.

Также с помощью системного вызова mmap() можно создавать совместно используемую область, которая преобразуется в совместно используемый физический сегмент. Тогда у каждой области появится индекс s, означающий shared.

Ограничения сегментации


Итак, сегментация позволила решить проблему неиспользуемой виртуальной памяти. Если она не используется, то и не размещается в физической памяти благодаря использованию сегментов, соответствующих именно объёму используемой памяти.

Но это не совсем верно.

Допустим, процесс запросил у кучи 16 Кб. Скорее всего, ОС создаст в физической памяти сегмент соответствующего размера. Если пользователь потом освободит из них 2 Кб, тогда ОС придётся уменьшить размер сегмента до 14 Кб. Но вдруг потом программист запросит у кучи ещё 30 Кб? Тогда предыдущий сегмент нужно увеличить более чем в два раза, а возможно ли это будет сделать? Может быть, его уже окружают другие сегменты, не позволяющие ему увеличиться. Тогда ОС придётся искать свободное место на 30 Кб и перераспределять сегмент.

Главный недостаток сегментов заключается в том, что из-за них физическая память сильно фрагментируется, поскольку сегменты увеличиваются и уменьшаются по мере того, как пользовательские процессы запрашивают и освобождают память. А ОС приходится поддерживать список свободных участков и управлять ими.

Фрагментация может привести к тому, что какой-нибудь процесс запросит такой объём памяти, который будет больше любого из свободных участков. И в этом случае ОС придётся отказать процессу в выделении памяти, даже если суммарный объём свободных областей будет существенно больше.

ОС может попытаться разместить данные компактнее, объединяя все свободные области в один большой чанк, который в дальнейшем можно использовать для нужд новых процессов и перераспределения.

Но подобные алгоритмы оптимизации сильно нагружают процессор, а ведь его мощности нужны для выполнения пользовательских процессов. Если ОС начинает реорганизовывать физическую память, то система становится недоступной.

Так что сегментация памяти влечёт за собой немало проблем, связанных с управлением памятью и многозадачностью. Нужно как-то улучшить возможности сегментации и исправить недостатки. Это достигается с помощью ещё одного подхода — страниц виртуальной памяти.

Разбиение памяти на страницы


Как было сказано выше, главный недостаток сегментации заключается в том, что сегменты очень часто меняют свой размер, и это приводит к фрагментации памяти, из-за чего может возникнуть ситуация, когда ОС не выделит для процессов нужные области памяти. Эта проблема решается с помощью страниц: каждое размещение, которое ядро делает в физической памяти, имеет фиксированный размер. То есть страницы — это области физической памяти фиксированного размера, ничего более. Это сильно облегчает задачу управления свободным объёмом и избавляет от фрагментации.

Давайте рассмотрим пример: виртуальное адресное пространство объёмом 16 Кб разбито на страницы.

Мы не говорим здесь о куче, стеке или кодовом сегменте. Просто делим память на куски по 4 Кб. Затем то же самое делаем с физической памятью:

ОС хранит таблицу страниц процесса (process page table), в которой представлены взаимосвязи между страницей виртуальной памяти процесса и страницей физической памяти (страничный кадр, page frame).

Теперь мы избавились от проблемы поиска свободного места: страничный кадр либо используется, либо нет (unused). И ядру не в пример легче найти достаточное количество страниц, чтобы выполнить запрос процесса на выделение памяти.

Страница — это мельчайшая и неделимая единица памяти, которой может оперировать ОС.

У каждого процесса есть своя таблица страниц, в которой представлена переадресация. Здесь уже используются не значения границ области, а номер виртуальной страницы (VPN, virtual page number) и сдвиг (offset).

Пример: размер виртуального пространства 16 Кб, следовательно, нам нужно 14 бит для описания адресов (214 = 16 Кб). Размер страницы 4 Кб, значит нам нужно 4 Кб (16/4), чтобы выбрать нужную страницу:

Когда процесс хочет использовать, например, адрес 9438 (вне границ 16 384), то он запрашивает в двоичном коде 10.0100.1101.1110:

Это 1246-й байт в виртуальной странице номер 2 («0100.1101.1110»-й байт в «10»-й странице). Теперь ОС достаточно просто обратиться к таблице страниц процесса, чтобы найти эту страницу номер 2. В нашем примере она соответствует восьмитысячному байту физической памяти. Следовательно, виртуальный адрес 9438 соответствует физическому адресу 9442 (8000 + сдвиг 1246).

Как уже было сказано, каждый процесс обладает лишь одной таблицей страниц, поскольку у каждого процесса собственная переадресация, как и у сегментов. Но где же именно хранятся все эти таблицы? Наверное, в физической памяти, где же ещё им быть?

Если сами таблицы страниц хранятся в памяти, то для получения VPN надо обращаться к памяти. Тогда количество обращений к ней удваивается: сначала мы извлекаем из памяти номер нужной страницы, а затем обращаемся к самим данным, хранящимся в этой странице. И если скорость доступа к памяти невелика, то ситуация выглядит довольно грустно.

Буфер быстрой переадресации (TLB, Translation-lookaside Buffer)


Использование страниц в качестве основного инструмента поддержки виртуальной памяти может привести к сильному снижению производительности. Разбиение адресного пространства на небольшие куски (страницы) требует хранения большого количества данных о размещении страниц. А раз эти данные хранятся в памяти, то при каждом обращении процесса к памяти осуществляется ещё одно, дополнительное обращение.

Для поддержания производительности снова используется помощь оборудования. Как и при сегментации, мы аппаратными методами помогаем ядру эффективно осуществлять переадресацию. Для этого используется TLB, входящий в состав MMU, и представляющий собой простой кэш для некоторых VPN-переадресаций. TLB позволяет ОС не обращаться к памяти лишний раз, чтобы получить физический адрес из виртуального.

Аппаратный MMU инициируется при каждом обращении к памяти, извлекает из виртуального адреса VPN и запрашивает у TLB, хранится ли в нём переадресация с этого VPN. Если да, то его роль выполнена. Если нет, то MMU находит нужную таблицу страниц процесса, и если она ссылается на валидный адрес, то обновляет данные в TLB, чтобы тот предоставлял их при следующем обращении.

Как вы понимаете, если в кэше отсутствует нужная переадресация, то это замедляет обращение к памяти. Можно предположить, что чем больше размер страниц, тем больше вероятность, что в TLB окажутся нужные данные. Но тогда мы будем тратить больше памяти на каждую страницу. Так что здесь нужен какой-то компромисс. Современные ядра умеют использовать страницы разных размеров. Например, Linux способен оперировать «огромными» страницами по 2 Мб вместо традиционных 4 Кб.

Также рекомендуется хранить данные компактно, в смежных адресах памяти. Если вы раскидаете их по всей памяти, то куда чаще в TLB не будет обнаруживаться нужной переадресации, либо он будет постоянно переполняться. Это называется эффективностью пространственной локальности (spacial locality efficiency): данные, которые расположены в памяти сразу за вашими, могут размещаться в той же физической странице, и тогда благодаря TLB вы получите выигрыш в производительности.

Кроме того, TLB в каждой записи хранит так называемые ASID (Address Space Identifier, идентификатор адресного пространства). Это нечто вроде PID, идентификатора процесса. Каждый процесс, поставленный в очередь на выполнение, имеет собственный ASID, и TLB может управлять обращением любого процесса к памяти, без риска ошибочных обращений со стороны других процессов.

Повторимся снова: если пользовательский процесс пытается обратиться к неправильному адресу, тот наверняка будет отсутствовать в TLB. Следовательно, будет запущена процедура поиска в таблице страниц процесса. В ней хранится переадресация, но с неправильным набором битов. В х86-системах переадресации имеют размер 4 Кб, то есть битов в них немало. А значит есть вероятность найти правильный бит, равно как и другие вещи, наподобие бита изменения («грязного бита», dirty bit), битов защиты (protection bit), бита обращения (reference bit) и т.д. И если запись помечена как неправильная, то ОС по умолчанию выдаст SIGSEGV, что приведёт к ошибке “segmentation fault”, даже если о сегментах уже и речи не идёт.

На самом деле разбиение памяти на страницы в современных ОС устроено куда сложнее, чем я расписал. В частности, используются многоуровневые записи в таблицах страниц, многостраничные размеры, вытеснение страниц (page eviction), также известное как «обмен» (ядро скидывает страницы из памяти на диск и обратно, что повышает эффективность использования основной памяти и создаёт у процессов иллюзию её неограниченности).

Заключение


Теперь вы знаете, что стоит за сообщением “segmentation fault”. Раньше операционки использовали сегменты для размещения пространства виртуальной памяти в пространстве физической. Когда пользовательский процесс хочет обратиться к памяти, то он просит MMU переадресовать его. Но если полученный адрес ошибочен, — находится вне пределов физического сегмента, или если сегмент не имеет нужных прав (попытка записи в read only-сегмент), — то ОС по умолчанию отправляет сигнал SIGSEGV, что приводит к прерыванию выполнения процесса и выдаче сообщения “segmentation fault”. В каких-то ОС это может быть “General protection fault”. Вы можете изучить исходный код Linux для х86/64-платформ, отвечающий за ошибки доступа к памяти, в частности — за SIGSEGV. Также можете посмотреть, как на этой платформе осуществляется сегментирование. Вы откроете для себя интересные моменты относительно разбиения на страницы, дающие куда больше возможностей, чем при использовании классических сегментов.

Комментарии (0)

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.

Какие мобильные устройства предпочитают пассажиры общественного транспорта

Каждый будний день огромное количество людей, живущих в Подмосковье, но работающих в Москве, тратит много времени на то, чтобы сначала добраться до офиса, а затем вернуться домой. Вы сами можете быть одним из постоянных пользователей общественного транспорта. Yota совместно с TelecomDaily выяснили, с каких устройств, какой контент и на каких условиях (в том числе и со стороны сотового оператора) потребляют жители Подмосковья, добираясь из области на работу в столицу – и мы готовы поделиться с вами результатами этого исследования.

В исследовании приняли участие две тысячи жителей Подмосковья, ежедневно приезжающих на электричке в столицу. В частности, опросы велись на станциях «Тимирязевская» (жители Лобни и Дмитрова, а также близлежащих поселков), «Коломенское» (Домодедово, Кашира, Ступино), «Петровско-Разумовская» (Зеленоград, Клин) и на Ярославском вокзале (Мытищи, Фрязино, Сергиев Посад, Пушкино).

Нас интересовали источники трафика, сколько люди готовы тратить в месяц на платный контент, какие предпочитают соцсети, услугами каких операторов пользуются и т.п. Мы обращали внимание на модель мобильного устройства пользователей, а также постарались установить, существует ли связь между форматом использования устройства и самой моделью. Кроме того, нам хотелось узнать, замечают ли клиенты изменения в своем формате использования гаджета (стали больше / меньше расходовать, чаще / реже выходить за лимит), каковы основные задачи для устройства (видео локальное / потоковое, соцсети, музыка, почта, серфинг, игры онлайн / оффлайн) и какой тип контента (платный / бесплатный) потребляется пользователями.

Мобильные устройства пользователей мы разделили на три класса: смартфоны (диагональ экрана до 5,5 дюймов), фаблеты (5,5-7 дюймов) и планшеты (от 7 дюймов). У почти трети респондентов не оказалось ни смартфона, ни планшета ― и в дальнейшем опросе они участия не принимали.

Далее мы выяснили уровень популярности мобильных ОС: как ожидалось, большинство (72%) пользуется устройствами на Android, 23% ― на iOS, 4% ― на WindowsPhone и 1% суммарно набрали Symbian, Blackberry, WindowsMobile и планшеты на Windows.

Сколько же обладателей планшетов среди пользователей? Оказывается, всего 8%. Зато на планшетах чаще всего (в 92% случаев) смотрят видео ― самый высокий показатель проникновения при среднем значении 55%.

Среди владельцев фаблетов (11%) видео смотрит лишь 68%, на смартфонах этот показатель составляет и того меньше ― 49%.
Для чего еще, помимо видео, используются мобильные устройства в пути? 87% проводят время в социальных сетях, 82% читают почту, 71% занимаются веб-серфингом. Мобильные игры занимают внимание 32% пользователей, а завершают список поклонники музыки ― их 31%.

Контент: источники и типы трафика


По популярности соцсети расположились в следующем порядке: «ВКонтакте» (66%), «Одноклассники» (23%), Instagram (18%), Facebook (13%), Twitter (5%) и 2% суммарно набрали «Мой Мир» и Google+.

Подавляющее большинство (91%) отдает предпочтение локальным играм. Только 15% выбирают сетевые игры, но среди них велика доля тех, кто также играет и в оффлайновые игры.

Что касается видео, то лишь 10% скачивают контент заранее, в то время как 93% предпочитают сразу смотреть видео на YouTube, в соцсетях, через мессенджеры и т.п.

Покупают контент только 6% опрошенных. В основном это игроки и владельцы дорогих смартфонов, в частности, замечены покупатели музыки в iTunes. Все остальные не скачивают платные приложения и не покупают мультимедийный контент. Среди причин такого неравномерного распределения клиенты в частности называли то, что информация должна быть бесплатной.

54% респондентов признали, что им важно прогнозировать расходы на связь. Не можем не напомнить, что Yota предлагает пользователям контролировать расходы в мобильном приложении даже при нахождении за границей.

Отметим еще один интересный момент: в ходе исследования нам удалось выявить закономерности зависимости структуры трафика и используемых устройств от возраста опрошенных. Люди от 40 лет в целом потребляют больше голосового трафика, чем молодежь (16-25 лет) и люди среднего возраста (25-40 лет). При этом группа от 40 лет меньше всего использует интернет-трафик. Лидируют по потреблению трафика люди среднего возраста.

Среди средней возрастной группы максимально проникновение флагманов (iPhone, Samsung Galaxy S и пр.): на нее приходится 72% от всех аппаратов этой категории, в то время как молодежь и старшее поколение имеет в основном бюджетные смартфоны и модели средней ценовой категории. Бюджетных устройств больше у старшего поколения, а в среде молодежи доминируют аппараты средней ценовой категории, а также распространены флагманы 2-4-летней давности.

Время в пути ― это возможность воспользоваться мобильным интернетом, развлекая себя или получая дополнительные знания. Как мы выяснили в ходе исследования, многие этим пользуются и нуждаются в безлимитном интернете, хорошем покрытии и доступной связи. Значительная часть пользователей Yota – жители Москвы и Подмосковья, где мы используем более 23 тысяч базовых станций, работая на мощной объединенной сети «Скартела» и «Мегафона». Всем нашим клиентам доступны высокое качество связи и настоящий безлимитный интернет в сетях 2G/3G/4G.

А теперь расскажите вы – какой контент вы чаще всего потребляете с телефона / планшета? Может быть, вам тоже довелось принять участие в этом исследовании? :)

Комментарии (0)

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.

Embedded World 2016: куда катится embedded-мир?

Всем привет!

Давненько мы ничего не писали. А тем временем...

В тридевятом царстве, в тридесятом государстве, в баварской вотчине, в средневековом городе Нюрнберге проходит выставка под названием Embedded World. Цель выставки — собрать в одном месте производителей, разработчиков, студентов и других заинтересованных граждан. Проходит она три дня — с 23 по 25 февраля.

Сайт выставки: http://ift.tt/1aBjrFc

Около 900 участников, примерно 25 тысяч посетителей. Двух дней еле-еле хватает, чтобы понять, что к чему. Поэтому выставка длится три дня :)

Судьба забрасывает меня на это мероприятие уже не в первый раз: мы с коллегами по НТЦ Метротек посещали выставку в 2013, 2014 и 2015 годах. Именно здесь мы впервые увидели Cyclone V SoC (System On Chip c ARM и FPGA на борту), который впоследствии лёг в основу новых девайсов производства НТЦ Метротек (это — Беркут-ЕТ, EthOnd, BlueSoM, ETL-N). Именно здесь мы нашли производителей корпусов EMKO и наладили с ними сотрудничество, теперь все стоечные приборы (свитч Metrotek X10-24, Беркут-МХ) выглядят единообразно. Здесь мы узнаём о новинках и трендах.

Под катом больше информации об участниках, новых продуктах и просто вещах, которые нам понравились и запомнились.
С фотографиями и ссылками.

К сожалению, выступить со своим стендом в этом году у нас не получилось, поэтому мы были в роли наблюдателей: изучали, куда катится этот Embedded мир. Интересовались всем, что попадалось под руку, поэтому не удивляйтесь, если встретите хорошо знакомую вам технологию или продукт. Однако, мы старались делать упор на новинки.

Ну что, поехали!

Заряжаем без проводов


Начну с популярного.

На стенде компании RRC я узнал про стандарт беспроводного питания под названием Qi (это как раз тот случай, когда технологии уже много лет, а ты узнаёшь о её названии только сейчас). Он позволяет передавать до 5 ватт (5 вольт, 1 ампер) энергии без проводов, с помощью электро-магнитной индукции. Трансмиттер и ресивер выглядят так:

На стенде можно было поднести девайс к передатчику и увидеть, как загорается лампочка. Понятно, что уже давно не rocket science, но для "разогрева" — самое то.

Olimex


Заглянул на стенд Olimex (парни из Болгарии, которые делают небезызвестный JTAG-отладчик openocd). Ребята переключились на IoT, и вот, что они предлагают.

Wi-Fi розетки (~ 30 евро): каждой розеткой можно управлять со смартфона и с помощью кнопки (см. ниже).

Wi-Fi выключатель, который может включить и выключить всё, что угодно, поскольку кнопка по wi-fi передаёт сигнал, например, на ту же розетку. К сожалению, фото не сделал, но внешне это обычный выключатель, внутри которого вот такой модуль:


микро-компьютер A20-OLinuXino-LIME на базе двух-ядерного ARM-а (dual-core Cortex-A7) со всей необходимой периферией, линуксом и разъёмами для подключения своих модулей. Цена — от 35 евро. И полностью открытое железо. Ищите на сайте ссылки на схемы и сорцы.

На подходе у olimex SODIMM-модуль на базе этого же процессора.

Simulink/Matlab


На стенде Matlab/Simulink снова показали возможность генерировать FPGA-код из Simulink. Это давно известная фича.
На фото показано, как схема, созданная в Simulink, управляет мотором, подключенным к SoC Altera Cyclone V.

Что меня больше всего заинтересовало, так это наличие API для добавления своей платы в Simulink, чтобы можно было использовать её для создания и моделирования схем. То есть теперь при желании можно любую плату, сделанную на базе Cyclone V SoC, интегрировать в свои модели Simulink.

denx


denx показал работающий u-boot на Intel'овом процессоре, то бишь на архитектуре x86! u-boot — это популярный бутлоадер для ARM-устройств. Мы используем его почти во всех наших устройствах. Но теперь он будет работать и на таких процессорах как Atom и других. Считаю, что это большой шаг вперёд.

Вывод версии u-boot — на фото.


Ну и, конечно, они не могли не похвастался загрузкой за 1.5 секунды, от подачи питания до появления окна приложения на экране. Достигли они таких результатов без модификаций кода — хватило возможностей конфигурирования u-boot'а и linux kernel, то есть всё "из коробки".

Java ME on ST microcontrollers


Я двинулся к стенду ST microelectronics, где разработчики из Oracle (в т.ч. наш соотечественник) предлагают использовать Java ME для программирования микроконтроллеров STM. Утверждают, что есть все Java API для доступа к периферии (i2c, SPI, etc..).

Меня это заинтересовало, потому что мир явно не стоит на месте. Привычно думать, что контроллеры программируются на C… А тут — на тебе — Java.

Первый релиз должен появиться в апреле и в базе он поддерживает процессор, который на фото. Java ME можно будет пробовать на конкретной плате, но будет возможность конфигурировать бинарник, чтобы поддерживать и другие платы тоже.

AdaCore — больше Ada


Зато на соседнем стенде разработчики из AdaCore программируют ARM-контроллеры на Ada. Вот пример: паровозы ездят по двум путям и по задаче никогда не должны сталкиваться. Бесперебойная работа гарантируется анализом кода за счёт того, что перед разработкой программы составляется спецификация программы (написанная на Ada же) и prover проверяет программу на соответствие спецификации.

Все (или почти все) инструменты для разработки на Ada — открытые.

Что ж, надо пробовать. Не Си единым, как говорится… Но сначала Java ME.

Надо сказать, что это очень характерно для Embedded World: здесь из года в год много стендов, посвящённых достижению абсолютного (или почти абсолютного) качества ПО и контроля над ним. Статический анализ за баснословные деньги, декларативное описание проекта с автоматической генерацией тестов и кода и т.п. Не удивительно, ведь Embedded-девайсы теперь везде и чтобы доверять им свою жизнь, нужно быть уверенным, что софт не глючит.

Cypress


Проходим дальше, к ещё одной интересной компании — Cypress. Моё близкое знакомство с чипами этой компании состоялось 10 лет назад, когда мы делали сканер отпечатков пальцев. Мы тогда использовали FX2 для передачи картинки со сканера на комп по USB 2.0. Помню, что был восхищён тем, как просто и понятно Cypress описали работу USB-шины, и с тех пор внимательно слежу за их продукцией.

Однако, сейчас время USB 3.0 и появились новые чипы. Встречайте FX3. Со стороны хоста — USB 3.0, со стороны платы — 32-разрядная шина, работающая на частоте до 100 МГц (что даёт порядка 400 МБайт/с). Ну и ARM9 в этом же флаконе. Всё как было у FX2: 8 разрядная шина (частоту не помню уже), USB 2.0, 51-й контроллер. Только круче.

Но на этом Cypress не остановился. В линейке есть ещё CX3, позволяющий подключить до 4 MIPI-камер по USB 3.0, и GX3, позволяющий "пробросить" Gigabit Ethernet over USB3.0.

А ещё Cypress же показали HyperFLASH, которая имеет скорость чтения до 333(!) мегабайт в секунду. Для подключения к этой флеш-памяти используется шина HyperBUS — 12 пинов, 8 из которых для данных. Используется Dual Data Rate на частоте 166 МГц. Некоторые производители контроллеров уже анонсировали поддержку HyperBus, см. пресс-релиз. Объём такой памяти — от 128 мегабит до 512 мегабит. Обратите внимание, что HyperFlash оптимизирована под чтение. Запись на неё значительно медленнее. Подразумевается такой кейс, когда на производстве эта флешка чем-то прошивается, а потом процессор грузится с неё мгновенно.

Ну и, конечно, полный комплект решений для TypeC

ST Microelectronics


Узнал, что для контроллеров STM32 теперь есть фреймворк под названием STM32Cube Software

Он включает в себя все необходимые библиотеки, HAL, коллекцию middleware с поддержкой RTOS, USB, файловых систем и т.п.

Пожалуй, это очень хорошая новость, поскольку я помню, чего стоило нам освоение Cortex-M3, с портированием NutOS, кучей времени, потраченным на поддержку USB и исправлением багов в libopencm3 (раньше библиотека, правда, по-другому называлась).

Intuitive filter design


На стенде компании Huber, занимающейся обработкой сигналов, натолкнулись на интересную программу — ASN Filter Designer. Это приложение, которое позволяет проектировать фильтр через задание его характеристик в форме графиков. По такому виду фильтра (его частотной и фазовой характеристикам) программа рассчитывает порядок, коэффициенты и т.п. В итоге выдаёт матлаб-код (в следующих релизах будет выдавать и VHDL/Verilog), который можно дальше использовать в привычной манере. Воистину DSP для чайников.

SIGFOX + LoRa = LPWAN


На стенде sigfox мы познакомились с одноимённым протоколом для объединения IoT-девайсов. Точнее, sigfox — это сеть для IoT-устройств. Пример использования — датчики парковки. Важно то, что теперь многие производители (Atmel, OnSemi, etc...) заявляют поддержку sigfox. См. подробнее: http://ift.tt/1S5eQSa. Также важно, что идёт работа над созданием LPWAN-стандарта на базе двух стандратов — sigfox и LoRa. Т.е. в скором времени должен выйти стандарт, который позволит объединять IoT-датчики с крайне низким потреблением энергии в одну wide-area сеть. Интересно, а как эти сети будут защищаться от вторжения?

LoRa на стенде ST Microelectronix

TES


Идём дальше. На сайте Altera компания TES анонсировала ядро для FPGA, которое реализует графический контроллер с поддержкой opengl es 2.0/3.1. По словам разработчиков, они обнаружили спрос на подобное решение. В итоге можно будет заюзать FPGA в Cyclone V SoC под графический контроллер. Сам контроллер идёт в зашифрованном виде как модуль для QSYS, а весь программный стек планируется сделать открытым.

Altera


Разработчики из Altera признались нам в том, что трансиверы в Arria 10 GT (те, которые должны поддерживать аж 28.3 ГГц по спецификации) ещё плохо изучены ими самими и такую частоту они не гарантируют, сейчас речь идёт только о примерно 26 ГГц. Будьте внимательны, если вдруг задумаете делать что-то действительно высокоскоростное на Arria 10. Они сказали, что нужно подождать, в ближайшее время будут известны точные характеристики.

Если кого-то интересует, что будет за десятым семейством, то вот roadmap от Altera. Обратите внимание, что все чипы являются SoC

Tektronix и Keithley


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


Synopsis


Что ещё впечатлило — это станция для симуляции ASIC от Synopsis. Можно собрать монстра из шести таких станций, объединяемых в стек. В итоге можно получить 24 чипа, и все они будут использоваться для симулируемого дизайна ASIC. Interconnect Synopsis берёт на себя. Мы даже спрашивать не стали, сколько это стоит ;)

Baikal Electronics


Наши соотечественники — fabless компания по производству микроэлектроники — тоже "засветились" на выставке с MIPS-процессором собственной разработки Baikal T1.

Материнская плата с Байкалом на борту

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

Небольшое резюме


Развитие IoT даёт огромный толчок всей embedded-индустрии. Появляются и обкатываются новые протоколы, новые режимы энергосбережения, методики разработки устойчивого кода. Выходят новые стандарты и выпускаются чипы.

За всем этим очень интересно наблюдать, а ещё более интересно — участвовать, осваивать новые технологии. Надеюсь, нам удастся применить полученные знания в наших новых продуктах. Но я пока не знаю, с чего начать — с перехода на Java ME или с поддержки беспроводной зарядки ;)

Надеюсь, было интересно.
Спасибо за внимание!

См. мой предыдущий отчёт о выставке в 2015 году: http://ift.tt/1Qjhmzz

Комментарии (0)

This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.