Что такое центральный процессор?
Центральный процессор (ЦПУ) – это аппаратный компонент, который является основным вычислительным блоком сервера. Серверы и другие интеллектуальные устройства преобразуют данные в цифровые сигналы и выполняют над ними математические операции. Центральный процессор является основным компонентом, который обрабатывает сигналы и делает возможными вычисления. Он действует как мозг любого вычислительного устройства. Он извлекает инструкции из памяти, выполняет необходимые задачи и отправляет выходные данные обратно в память. Он выполняет все вычислительные задачи, необходимые для работы операционной системы и приложений.
Как развивалась технология ЦПУ с течением времени?
В самых ранних компьютерах для обработки использовались вакуумные трубки. Такие машины, как ENIAC и UNIVAC, были большими и громоздкими, потребляли много энергии и выделяли значительное количество тепла. Изобретение транзисторов в конце 1940-х годов произвело революцию в технологии ЦПУ. Транзисторы заменили вакуумные трубки, сделав компьютеры компактнее, надежнее и энергоэффективнее. В середине 1960-х годов были разработаны интегральные схемы, которые объединили несколько транзисторов и других компонентов на одном компьютерном чипе. ЦПУ стали еще меньше и быстрее, что привело к появлению микропроцессоров.
Микропроцессоры
Микропроцессоры объединили весь ЦПУ на одном микрочипе, что сделало компьютеры более доступными и привело к разработке персональных компьютеров. Первоначально ЦПУ могли обрабатывать от 16 до 32 бит данных одновременно. В начале 2000-х годов появились 64-разрядные ЦПУ, которые обеспечивали большую адресацию памяти и поддерживали более интенсивную обработку данных.
По мере увеличения плотности транзисторов повышение производительности одноядерных ЦПУ усложнилось. Вместо этого производители ЦПУ начали использовать архитектуры многоядерных процессоров для интеграции нескольких ядер в один чип.
Современные процессоры
С появлением мобильных устройств энергоэффективность стала играть решающую роль. Теперь производители ЦПУ разрабатывают маломощные и энергоэффективные ЦПУ для современных портативных устройств, таких как смартфоны и планшеты.
По мере распространения задач, связанных с искусственным интеллектом и графической обработкой, для обработки рабочих нагрузок стали использоваться специализированные ЦПУ, такие как графические процессоры и ускорители искусственного интеллекта.
Непрерывные исследования и разработки в области нанотехнологий и материаловедения проложили путь к созданию микроскопических транзисторов и более мощных ЦПУ. Квантовые вычисления и другие новые технологии могут способствовать дальнейшему развитию компьютерных процессорных технологий.
Из каких компонентов состоит ЦПУ?
ЦПУ – это сложная электронная схема, состоящая из нескольких ключевых компонентов, обрабатывающих данные и исполняющих инструкции. Ниже описаны основные компоненты ЦПУ.
Блок управления
Блок управления контролирует обработку инструкций и координирует поток данных внутри процессора и между другими компьютерными компонентами. Он содержит декодировщик команд, который интерпретирует инструкции, извлеченные из памяти, и преобразует их в микрооперации, которые может выполнить процессор. Блок управления направляет другие компоненты процессора на выполнение необходимых операций.
Регистры
Регистры – это небольшие высокоскоростные места хранения внутри процессора. Они содержат данные, с которыми работает процессор в данный момент, и обеспечивают к ним быстрый доступ. Процессоры имеют несколько типов регистров, в частности такие:
- регистры общего назначения, содержащие оперативные данные;
- регистры инструкций, содержащие текущую обрабатываемую инструкцию;
- счетчик команд, содержащий адрес памяти следующей инструкции, которую нужно извлечь.
Регистры обеспечивают более быстрый доступ к данным по сравнению с другими уровнями памяти, такими как ОЗУ или кэш-память.
ALU
Арифметико-логическое устройство (ALU) выполняет над данными основные арифметические (сложение, вычитание, умножение и деление) и логические операции (AND, OR и NOT). Оно получает данные из регистров процессора, обрабатывает их на основе инструкций блока управления и выдает результат.
Блок управления памятью
Процессор может быть оснащен отдельным интерфейсным блоком или блоком управления памятью в зависимости от его архитектуры. Эти компоненты выполняют задачи, связанные с памятью, такие как управление взаимодействием процессора и оперативной памяти. Этот компонент также управляет кэш-памятью, небольшим блоком быстрой памяти, расположенным внутри процессора, и виртуальной памятью, используемой процессором для обработки данных.
Генератор синхроимпульсов
Процессор использует тактовый сигнал для синхронизации внутренних операций. Генератор синхроимпульсов вырабатывает устойчивые импульсы с определенной частотой, и эти тактовые циклы координируют операции процессора. Тактовая частота измеряется в герцах (Гц) и определяет количество команд, которое процессор может выполнять в секунду. Современные процессоры имеют переменную тактовую частоту, которая регулируется в зависимости от рабочей нагрузки, для сбалансирования производительности и энергопотребления.
Каков принцип работы ЦПУ?
Компьютерные процессоры работают на базе других аппаратных компонентов и программного обеспечения для обработки данных и управления потоком информации в электронных устройствах. Обычно они работают циклически, при этом каждый цикл команд представляет собой три основных этапа.
Цикл базового процессора
Ниже приведены основные этапы цикла команд.
Выборка команд
ЦПУ получает команды из памяти. Команды – это двоичные коды, представляющие конкретные задачи или операции ЦПУ. Блок управления интерпретирует команду и определяет операцию, которую необходимо выполнить. При этом также определяются конкретные компоненты ЦПУ, необходимые для выполнения задачи.
Обработка команд
ЦПУ выполняет указанную операцию с полученными данными. Он выполняет математические вычисления, логические сравнения, манипуляции с данными или передачу данных между регистрами или ячейками памяти.
Хранение результатов
После выполнения команд ЦПУ может потребоваться сохранить результаты в памяти или обновить определенные регистры новыми данными. Счетчик команд обновляется и указывает адрес следующей команды, которую нужно получить. ЦПУ повторяет цикл и последовательно загружает, декодирует и выполняет команды.
Дополнительные функции процессора
ЦПУ также может обрабатывать команды потока управления, такие как переходы и ответвления, а также прерывания, сигналы, генерируемые внешними устройствами, или события, требующие немедленного внимания. При прерывании ЦПУ временно приостанавливает выполнение текущей задачи, сохраняет ее состояние и переходит к процедуре обслуживания прерываний. После обработки прерывания ЦПУ возобновляет выполнение предыдущей задачи.
Современные ЦПУ часто используют такие методы, как параллелизм и конвейерная обработка команд, для повышения производительности. Несколько команд могут одновременно находиться на разных стадиях цикла, что позволяет более эффективно использовать ресурсы ЦПУ.
Каковы расширенные функции ЦПУ?
Лучший ЦПУ отличается производительностью, эффективностью и гибкостью, что позволяет эффективно выполнять широкий спектр вычислительных задач. Далее мы опишем несколько дополнительных функций.
Ядра
Ранее одноядерный процессор был стандартным решением, однако сегодня все ЦПУ имеют несколько физических ядер. Ядро – это отдельный процессор в ЦПУ. Большее количество ядер позволяет ЦПУ обрабатывать несколько потоков (последовательностей команд) параллельно, что значительно повышает общую производительность. Приложения могут использовать преимущества многоядерной архитектуры, разделяя задачи на более мелкие подзадачи, которые можно выполнять одновременно.
Гиперпоточность
Гиперпоточность – это одновременная многопоточная реализация, разработанная Intel, которая позволяет каждому ядру ЦПУ запускать несколько потоков одновременно. Таким образом, каждое физическое ядро в операционной системе имеет вид двух виртуальных ядер. Программное обеспечение более эффективно использует доступные аппаратные ресурсы.
Расширенные наборы команд
Современные ЦПУ также оснащены расширенными наборами команд и технологиями, предназначенными для ускорения выполнения определенных задач. Эти наборы команд выходят за рамки фундаментальных арифметических и логических операций и предоставляют дополнительные возможности для более эффективной обработки сложных вычислений.
Например, ЦПУ могут включать наборы команд, специально предназначенных для описанных ниже задач.
- Мультимедийные задачи, такие как декодирование видео, кодирование звука и обработка изображений.
- Алгоритмы шифрования и дешифрования, такие как AES и SHA.
- Задачи типа SIMD, требующие одновременного выполнения ЦПУ одной и той же операции с большими наборами данных. Это такие задачи, как графический рендеринг, научное моделирование и цифровая обработка сигналов.
- Виртуализация, позволяющая виртуальным машинам (VM) работать более эффективно.
- Рабочие нагрузки ИИ, такие как операции с нейронными сетями.
Как AWS обеспечивает соответствие вашим требованиям к процессорам?
У Amazon Web Services (AWS) предлагает решения для реализации ваших требований к процессорам.
Эластичное вычислительное облако Amazon (Amazon EC2) предлагает самую масштабную и разноплановую вычислительную платформу. Она насчитывает более 600 инстансов и позволяет выбрать новейший процессор, систему хранения данных, сетевую систему, операционную систему и модель покупки, которые помогут вам наилучшим образом удовлетворить потребности вашей рабочей нагрузки. Мы первый крупный облачный провайдер, который поддерживает работу процессоров Intel, AMD и Arm, а также единственное облако с инстансами EC2 Mac по требованию.
При использовании Amazon EC2 вы мгновенно получаете следующие преимущества:
- лучшее соотношение цены и производительности машинного обучения, а также самая низкая стоимость инстансов логических выводов в облаке;
- возможность выбора оптимального сочетания ЦПУ, памяти, хранилища и сетевых ресурсов для ваших приложений;
- возможность выбора предварительно настроенного шаблона образа машины Amazon (AMI) для мгновенного начала работы.
Начните работу с пользовательскими инстансами и процессорами на AWS, создав аккаунт уже сегодня.
Unix2019b/Организация памяти на x86-64
Процессоры архитектуры x86-64 поддерживают два основных режима работы: Long mode («длинный» режим) и Legacy mode («унаследованный», режим совместимости с 32-битным x86).
Long mode
«Длинный» режим — «родной» для процессоров x86-64. Этот режим даёт возможность воспользоваться всеми дополнительными преимуществами, предоставляемыми архитектурой. Для использования этого режима необходима 64-битная операционная система.
Этот режим позволяет выполнять 64-битные программы; также (для обратной совместимости) предоставляется поддержка выполнения 32-битного кода, например, 32-битных приложений, хотя 32-битные программы не смогут использовать 64-битные системные библиотеки, и наоборот. Чтобы справиться с этой проблемой, большинство 64-разрядных операционных систем предоставляют два набора необходимых системных файлов: один — для родных 64-битных приложений, и другой — для 32-битных программ.
Когда вы используете 64-битную операционную систему (Windows, Linux или какую-либо другую), ваш процессор работает в длинном режиме. 32-битные ОС теряют популярность и используются всё реже, так как не позволяют использовать весь потенциал современного железа. Так, дистрибутив Ubuntu Linux уже начиная с версии 17.10 не выпускается в 32-битном исполнении. Windows Server 2008 стала последней серверной ОС от Microsoft, которая имела 32-битную версию, и Server 2012 существует только 64-битная.
Legacy mode
Данный «унаследованный» режим позволяет процессору выполнять инструкции, рассчитанные для процессоров x86, и предоставляет полную совместимость с 32-битным кодом и операционными системами. В этом режиме процессор ведёт себя точно так же, как x86-процессор, например Athlon или Pentium III, и дополнительные функции, предоставляемые архитектурой x86-64 (например, дополнительные регистры), недоступны. В этом режиме 64-битные программы и операционные системы работать не будут.
Этот режим включает в себя подрежимы:
- Реальный режим (real mode)
- Защищённый режим (protected mode)
- Режим виртуального 8086 (virtual 8086 mode)
Реальный режим использовался в MS-DOS, в реальном режиме выполнялся код BIOS при загрузке компьютера.
Защищённый режим используется в 32-битных версиях современных многозадачных операционных систем (например, обычная 32-битная Windows XP работает в защищённом режиме, как и 32-битная версия Ubuntu 16.04).
Режим виртуального 8086 — подрежим защищённого, предназначался главным образом для создания т. н. «виртуальных DOS-машин». Если из 32-битной версии Windows вы запускаете 16-битное DOS-приложение, то работает эмулятор NTVDM (NT Virtual DOS Machine), который использует этот режим процессора. Другой эмулятор, DOSBox, не использует этот режим V86, а выполняет полную эмуляцию. Заметим, что в 64-битных версиях Windows эмулятор NTVDM был исключён, поэтому напрямую запустить на выполнение 16-битный com- или exe-файл стало невозможно (тем не менее, можно использовать тот же DOSBox или другой гипервизор для полной эмуляции реального режима).
Переход между режимами
Из длинного режима нельзя перейти в реальный или режим виртуального 8086 без перезагрузки. Поэтому, как уже отмечено, в 64-битных версиях Windows не работает NTVDM и нельзя запускать 16-битные программы.
Самый современный процессор x86-64 полностью поддерживает реальный режим. Если загрузка выполняется через BIOS, то код загрузчика (из сектора #0) исполняется в реальном режиме. Однако если вместо BIOS используется UEFI, то переход в Long mode происходит ещё раньше, и никакого кода в реальном режиме уже не выполняется. Можно считать, что современный компьютер сразу начинает работать в 64-битном длинном режиме.
Поэтому далее нас будет интересовать только длинный режим.
Трансляция адресов в памяти
Упрощённо говоря, процессор обращается к памяти через шину. Адресами памяти, которыми обмениваются в шине, являются физические адреса, то есть сырые числа от нуля до верхней границы доступной физической памяти (например, до 2 33 , если у вас установлено 8 ГБ оперативки). Ранее между процессором и микросхемами памяти располагался северный мост — отдельный чип, но в реализации Intel начиная с микроархитектуры Sandy Bridge он интегрирован на кристалл процессора.
Физические адреса являются конкретными и окончательными — без трансляции, без подкачки, без проверки привилегий. Вы выставляете их на шину и всё: выполняется чтение или запись.
Однако в современной операционной системе программы используют абстрацкию — виртуальное адресное пространство. Каждая программа пишется в такой модели, что она выполняется одна, всё пространство принадлежит ей, код использует адреса логической памяти, которые должны быть оттранслированы в физические адреса до того, как будет выполнен доступ к памяти. Концептуально трансляция выглядит следующим образом:
Это не физическая схема, а только описание процесса преобразования адресов. Такая трансляция осуществляется всякий раз, когда CPU выполняет инструкцию, которая ссылается на адрес памяти.
Логический адрес на x86 состоит из двух частей: селектора сегмента и смещения внутри сегмента. Процесс трансляции включает два шага:
- учёт сегментного селектора и переход от смещения внутри сегмента к некоторому линейному адресу;
- перевод линейного адреса в физический.
Спрашивается, зачем нужен первый шаг и зачем нужны эти сегменты, почему бы напрямую не использовать линейные адреса в программе? Это результат эволюции. Чтобы действительно понять смысл сегментации x86, нам нужно вернуться в 1978 год.
Сегментация
Реальный режим
16-битный процессор 8086 использовал 16-битные регистры и мог напрямую адресовать только 2 16 байт памяти. Инженеры придумывали, как же можно заставить его работать с большим объёмом памяти, не расширяя разрядность регистров.
Были придуманы сегментные регистры, которые должны были задавать, к какому именно 64-килобайтному куску памяти относится данный 16-битный адрес.
Решение выглядит логичным: сначала вы устанавливаете сегментный регистр, по сути говоря “так, я хочу работать с куском памяти начиная с адреса X”; затем 16-битный адрес уже используется как смещение в рамках этого куска.
Всего предусматривалось сначала четыре 16-битных сегментных регистра, потом добавили ещё два:
- CS = Code Segment
- DS = Data Segment
- ES = Extra (или Destination) Segment
- SS = Stack Segment
- FS
- GS
Названия этих регистров связаны с назначением. При выполнении инструкций они загружаются из сегмента кода. При обращении к стеку (инструкции push/pop) неявно используется сегмент стека (при работе с регистрами SP и BP). Некоторые инструкции (так называемые «строковые») используют фиксированные сегменты, например инструкция movs копирует из DS:(E)SI в ES:(E)DI.
Для вычисления линейного адреса ячейки памяти процессор вычисляет физический адрес начала сегмента — умножает сегментную часть виртуального адреса на число 16 (или, что то же самое, сдвигает её влево на 4 бита), а затем складывает полученное число со смещением от начала сегмента. Таким образом, сегменты частично перекрывались, и всего можно было адресовать около 1 МБ физической памяти. Спрашивается, почему не умножать значение сегментного регистра сразу на 65536, ведь тогда можно было бы адресовать 4 ГБ памяти. Тогда это было не нужно и только растило стоимость чипа.
В реальном режиме отсутствует защита памяти и разграничение прав доступа.
Программы были маленькие, поэтому их стек и код полностью помещались в 64 КБ, не было проблем. В языке C тех древних времён обычный указатель был 16-битный и указывал относительно сегмента по умолчанию, однако существовали также far-указатели, которые включали в себя значение сегментного регистра. Призраки этих far-указателей преследуют нас в названиях типов в WinAPI (например LPVOID — long (far) pointer to void).
#include int main(){ char far *p =(char far *)0x55550005; char far *q =(char far *)0x53332225; *p = 80; (*p)++; printf("%d",*q); return 0; }
Тут оба указателя указывают на один и тот же физический адрес 0x55555.
Защищённый режим
В 32-битном защищенном режиме также используется сегментированная модель памяти, однако уже организованная по другому принципу: расположение сегментов описывается специальными структурами (таблицами дескрипторов), расположенными в оперативной памяти.
Сегменты памяти также выбираются все теми же сегментными регистрами. Значение сегментного регистра (сегментный селектор) больше не является сырым адресом, но вместо этого представляет собой структуру такого вида:
Существует два типа дескрипторных таблиц: глобальная (GDT) и локальная (LDT). Глобальная таблица описывает сегменты операционной системы и разделяемых структур данных, у каждого ядра своя. Локальная таблица может быть определена для каждой конкретной задачи (процесса). Бит TI равен 0 для GDT и 1 для LDT. Индекс задаёт номер дескриптора в таблице дескрипторов сегмента. Поле RPL расшифровывается как Requested Privilege Level.
Сама таблица представляет собой просто массив, содержащий 8-байтные записи (дескрипторы сегмента), где каждая запись описывает один сегмент и выглядит так:
Помимо базового адреса сегмента дескрипторы содержат размер сегмента (точнее, максимально доступное смещение) и различные атрибуты сегментов, использующиеся для защиты памяти и определения прав доступа к сегменту для различных программных модулей. Базовый адрес представляет собой 32-битный линейный адрес, указывающий на начало сегмента, а лимит определяет, насколько большой сегмент. Добавление базового адреса к адресу логической памяти дает линейный адрес (никакого умножения на 16 уже нет). DPL (Descriptor Privilege Level) — уровень привилегий дескриптора; это число от 0 (наиболее привилегированный, режим ядра) до 3 (наименее привилегированный, пользовательский режим), которое контролирует доступ к сегменту.
Когда CPU находится в 32-битных режимах, регистры и инструкции могут в любом случае адресовать всё линейное адресное пространство. Итак, почему бы не установить базовый адрес в ноль и позволить логическим адресам совпадать с линейными адресами? Intel называет это «плоской моделью», и это именно то, что делают современные ядра операционных систем под x86. Это эквивалентно отключению сегментации.
Понятно, что раз таблицы GDT и LDT лежат в памяти, каждый раз ходить в них за базовым адресом долго. Поэтому сегментные дескрипторы кешируются в специальных регистрах в момент загрузки (в тот момент, когда происходит запись в сегментный селектор).
Местоположение GDT в памяти указывается процессору посредством инструкции lgdt.
Длинный режим
На архитектуре x86-64 в длинном (64-битном) режиме сегментация не используется. Для четырёх сегментных регистров (CS, SS, DS и ES) базовый адрес принудительно выставляются в 0. Сегментные регистры FS и GS по-прежнему могут иметь ненулевой базовый адрес (но он стал 64-битным и может быть установлен через отдельные моделезависимые регистры (MSR)). Это позволяет ОС использовать их для служебных целей.
Например, Microsoft Windows на x86-64 использует GS для указания на Thread Environment Block, маленькую структурку для каждого потока, которая содержит информацию об обработке исключений, thread-local-переменных и прочих per-thread-сведений. Аналогично, ядро Linux использует GS-сегмент для хранения данных per-CPU.
Посмотрим на таблицы сегментных дескрипторов. Таблица LDT на самом деле вышла из употребления и сейчас не используется. В таблице GDT в современных системах есть как минимум пять записей:
- Null — первая ячейка не используется (сделано, чтобы нулевое значение селектора было зарезервированным [1]);
- Kernel Code;
- Kernel Data;
- User Code;
- User Data.
Практика: просмотр регистров
(gdb) info registers rax 0x40052d 4195629 rbx 0x0 0 rcx 0x0 0 rdx 0x7fffffffde78 140737488346744 rsi 0x7fffffffde68 140737488346728 rdi 0x1 1 rbp 0x7fffffffdd80 0x7fffffffdd80 rsp 0x7fffffffdd80 0x7fffffffdd80 r8 0x7ffff7dd4e80 140737351863936 r9 0x7ffff7dea700 140737351952128 r10 0x7fffffffdc10 140737488346128 r11 0x7ffff7a32e50 140737348054608 r12 0x400440 4195392 r13 0x7fffffffde60 140737488346720 r14 0x0 0 r15 0x0 0 rip 0x400531 0x400531 eflags 0x246 [ PF ZF IF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0
Мифы о сегментных регистрах
Сегментные регистры остались в прошлом, в 64-битном длинном режиме они окончательно выпилены. Это неправда. Регистры существуют, даже GDB их печатает.
Раньше сегментные регистры были 16-битные, а сейчас они уже 64-битные. Это неправда, регистры CS, SS, DS, ES и пр. всегда были 16-битными и остаются такими, у них нет расширенных E- или R-версий.
Сегодня в этих регистрах всегда записан ноль. Это тоже неправда, там записан индекс сегментного дескриптора в таблице, а уже в этом дескрипторе базовый адрес равен тождественно нулю. Из приведённого вывода GDB очевидно, что CS и SS не равны нулю. К тому же биты RPL играют свою роль.
Раз сегментные регистры не нужны, я могу в своей программе делать с ними разные арифметические операции. Это неправда, регистры не относятся к регистрам общего назначения и их не получится использовать в качестве операндов в любых инструкциях.
Ладно, я смогу использовать их для хранения произвольных данных, а именно 16-битных чисел. Так тоже не выйдет, потому что при любом обращении к памяти процессор всё равно обращается к сегментному селектору и проверяет сегментный дескриптор.
Кольца защиты
Вы, вероятно, знаете интуитивно, что приложения имеют ограниченные полномочия на компьютерах Intel x86 и что только код операционной системы может выполнять определенные задачи. Как это работает? Уровни привилегий x86 — механизм, с помощью которого ОС и ЦП ограничивают возможности программ пользовательского режима.
Существует четыре уровня привилегий: от 0 (наиболее привилегированных) до 3 (наименее привилегированных). В любой момент времени процессор x86 работает на определенном уровне привилегий, который определяет, что код может и не может сделать. Эти уровни привилегий часто описываются как защитные кольца, причем самое внутреннее кольцо соответствует самым высоким привилегиям. [2]
Большинство современных ОС на x86 используют только Ring 0 и Ring 3.
Кольца управляют доступом к памяти. Код с уровнем привилегий i может смотреть только данные уровня i и выше (менее привилегированных).
На кольце 0 можно делать всё. На кольце 3, например, нельзя:
- изменить текущее кольцо защиты (иначе весь механизм был бы бесполезен);
- изменить таблицу страниц;
- зарегистрировать обработчик прерываний;
- выполнить ввод-вывод инструкциями in и out;
- .
Текущий уровень привилегий (CPL) определяется сегментным дескриптором кода. Если сейчас исполняется сегмент кода с уровнем привилегий 3, значит, исполняется пользовательский код. Если исполняется код с уровнем привилегий 0 — исполняется код ядра.
При обращении к памяти проверяется неравенство
max(CPL, RPL) ≤ DPL,
- CPL — текущий уровень привилегий,
- RPL — записан в сегментном регистре (селекторе),
- DPL — записан в сегментном дескрипторе.
Еси неравенство ложно, генерируется ошибка general protection fault (GPF).
Как мы ранее выяснили, системные вызовы позволяют менять текущий уровень привилегий, поэтому эта операция достаточно тяжёлая.
Страничная организация памяти
Страничная память — способ организации виртуальной памяти, при котором виртуальные адреса отображаются на физические постранично.
В семействе x86 поддержка появилась с поколения 386, оно же первое 32-битное поколение.
Если сегментация сейчас практически не используется, то таблицы страниц, наоборот, используются вовсю во всех современных операционных системах. Его важно понимать, так как с особенностями страничной организации можно прямо или косвенно столкнуться при решении прикладных задач.
Страницы
Виртуальная память делится на страницы. Размер размера страницы задается процессором и обычно на x86-64 составляет 4 KiB. Это означает, что управление памятью в ядре выполняется с точностью до страницы. Когда вам понадобится новая память, ядро предоставит вам одну или несколько страниц. При освобождении памяти вы вернёте одну или несколько страниц. Каждый более гранулярный API (например malloc) реализуется в пространстве пользователя.
Физическая память также поделена на страницы.
Виртуальное адресное пространство
Хотя виртуальные адреса имеют разрядность в 64 бита, текущие реализации (и все чипы, которые находятся на стадии проектирования) не позволяют использовать всё виртуальное адресное пространство из 2 64 байт (16 экзабайт). Это будет примерно в четыре миллиарда раз больше виртуального адресного пространства на 32-битных машинах. В обозримом будущем большинству операционных систем и приложений не потребуется такое большое адресное пространство, поэтому внедрение таких широких виртуальных адресов просто увеличит сложность и расходы на трансляцию адреса без реальной выгоды. Поэтому AMD решила, что в первых реализациях архитектуры фактически при трансляции адресов будут использоваться только младшие 48 бит виртуального адреса.
Кроме того, спецификация AMD требует, что старшие 16 бит любого виртуального адреса, биты с 48-го по 63-й, должны быть копиями бита 47 (по принципу sign extension). Если это требование не выполняется, процессор будет вызывать исключение. Адреса, соответствующие этому правилу, называются «канонической формой». Канонические адреса в общей сложности составляют 256 терабайт полезного виртуального адресного пространства. Это по-прежнему в 65536 раз больше, чем 4 ГБ виртуального адресного пространства 32-битных машин.
Это соглашение допускает при необходимости масштабируемость до истинной 64-разрядной адресации. Многие операционные системы (включая семейство Windows NT и GNU/Linux) берут себе старшую половину адресного пространства (пространство ядра) и оставляют младшую половину (пользовательское пространство) для кода приложения, стека пользовательского режима, кучи и других областей данных. Конструкция «канонического адреса» гарантирует, что каждая совместимая с AMD64 реализация имеет, по сути, две половины памяти: нижняя половина «растет вверх» по мере того, как становится доступнее больше виртуальных битов адреса, а верхняя половина — наоборот, вверху адресного пространства и растет вниз.
Первые версии Windows для x64 даже не использовали все 256 ТБ; они были ограничены только 8 ТБ пользовательского пространства и 8 ТБ пространства ядра. Всё 48-битное адресное пространство стало поддерживаться в Windows 8.1, которая была выпущена в октябре 2013 года.
Структура таблицы страниц
Ставится задача транслировать 48-битный виртуальный адрес в физический. Она решается аппаратным обеспечением — блоком управления памятью (memory management unit, MMU). Этот блок является частью процессора. Чтобы транслировать адреса, он использует структуры данных в оперативной памяти, называемые таблицами страниц.
Вместо двухуровневой системы таблиц страниц, используемой системами с 32-битной архитектурой x86, системы, работающие в длинном режиме, используют четыре уровня таблицы страниц.
Возможные размеры страниц:
- 4 КБ (2 12 байт) — наиболее часто используется (как и в x86)
- 2 МБ (2 21 байт)
- 1 ГБ (2 30 байт)
Пусть для определённости размер страницы равен 4 КБ. Значит, младшие 12 битов адреса кодируют смещение внутри страницы и не изменяются, а старшие биты используются для определения адреса начала страницы.
CR3 — это специальный регистр процессора. В записях каждой таблицы лежит физический адрес начала таблицы следующего уровня.
Полная иерархия сопоставления страниц размером 4 КБ для всего 48-битного пространства займет немногим больше 512 ГБ ОЗУ (около 0.195% от виртуального пространства 256 ТБ).
Кеширование
Таблицы страниц хранятся в оперативной памяти. Если при каждом обращении по виртуальному адресу выполнять полностью трансляцию адресов, это будет работать очень медленно. Поэтому в процессоре реализуется специальный кеш под названием «буфер ассоциативной трансляции» (Translation lookaside buffer, TLB).
На практике вероятность промаха TLB невысока и составляет в среднем от 0,01% до 1%.
Практика: как скоро оно упадёт?
Понятно, что данный код по стандарту некорректен, содержит Undefined Behavior, а раз так, то компилятор может сделать что угодно, например не упасть вообще. Но тем не менее, если запускать на x86-64, то падает оно в определённый момент.
#include #include char buf[1]; #define PAGE_SIZE 4096 int main() { char* ptr = buf; for (;;) { int offset = (intptr_t)ptr % PAGE_SIZE; printf("%p: offset = %d\n", ptr, offset); *ptr = 'a'; // Segmentation fault expected! ++ptr; } return 0; }
Литература
Что такое операционная система и как она работает?¶
Основа конспекта, лекция — Что такое операционная система и как она работает Автор конспекта/статьи немного переработал и дополнил некоторые моменты: структуру и повествование, постарался дать более глубокое и последовательное разъясление, добавил как скаченные, так и созданные им лично схемы.
Цель конспекта — последовательно рассмотреть и объяснить принципы устройства и функционирования операционной системы, её основных компонентов и абстракций.
Введение¶
Операционные системы окружают нас повсюду – это основное программное обеспечение персональных компьютеров, серверов, мобильных устройств, сетевых устройств (роутеры, коммутаторы) и даже современных автомобилей (борт-компьютер), телевизоров и прочего. Перечислять можно очень долго, ведь они требуются практически в каждой компьютерной системе.
Любой компьютер представляет собой связанную совокупность: процессора, памяти и устройств ввода-вывода.
Рис. 1. Общее представление архитектуры компьютера
Сама по себе, аппаратура умеет делать только очень простые, базовые операции — по типу: сложить два числа, перейти к адресу, записать по адресу и тд.
Например, процессор умеет выполнять только четыре базовых типа инструкции:
- Чтение инструкций/данных из памяти (read)
- Выполнение интрукции (execute)
- Запись результата в память (write)
- Прерывание (interrupt)
Получается, что непосредственное создание и управление сложными процессами (приложениями) на аппаратуре становится крайне неэффективным и неудобным. То есть, например, создать и запустить на исполнение программу-браузер исключительно с помощью данных инструкций становится крайне сложной задачей. Особенно при условии, что помимо этого процесса (браузера) существуют и другие процессы, которые также пользуются ресурсами вычислительной машины.
Возникает вопрос — Как заставить всё это слаженно и эффективно работать, сделав пользование компьютером удобным как для обычного человека, так и для прикладного программиста?
Чтобы ответить на этот вопрос более последовательно, немного заглянем туда, откуда всё начиналось.
Немного истории¶
На заре компьютерной эпохи, первые компьютеры представляли собой огромные блоки (занимавшие большие комнаты), в которых размещались основные его компоненты: процессор, память и устройства ввода-вывода. И всего можно было выделить два состояния, в котором, в реальном времени находится компьютерная система:
- Ввод/Вывод
- Вычисление
Важная идея! Так как вычисления производятся быстрее, чем непосредственный ввод-вывод данных, разработчикам пришла идея о том, что к ресурсам можно допускать не одного пользователя (процесс), а множество, предоставляя им способ независимо друг от друга загружать (ввод) и получать (вывод) данные через отдельные терминалы, чтобы более эффективно использовать ресурсы компьютера и вычислительные модули не простаивали в ожидании ввода/вывода.
Идея многопользовательского режима в использовании ресурсов компьютера нашла свою реализацию в понятии процесс. То есть, каждый процесс — это пользователь ресурсов компьютера.
Эта идея положила начало созданию такой системы, которую мы теперь называем операционной — программной системы, которая управляет ресурсами компьютера, а следовательно осуществляет доступ к этим ресурсам и управляет процессами — пользователями этимх ресурсов.
Далее, термины: процесс, приложение идут как синонимы термину пользователь ресурсов.
Зачем нужна Операционная Система?¶
Операционная система — программная система, которая управляет ресурсами компьютера, а следовательно осуществляет доступ к этим ресурсам, управляет процессами, вводит и реализует различные абстракции, выполняет другие системные функции.
Существует три ключевых элемента операционной системы:
- Абстракции (процессы, потоки, файлы, сокеты, адресное пространство).
- Функции (создание, управление, открытие, запись, распределение).
- Конкретные реализации
- Архитектуры: монолитные, модульные, гибридные;
- Алгоритмы: LRU, EDF;
Фунции ОС¶
- Управление ресурсами и процессами, а также совместное использование вычислительных ресурсов группой приложений (многозадачность) — центральная функция ОС, которая является базой для разных системных архитектур
- Scheduler — планировщик. Механизм управляющий процессами и реализующий многозадачность.
- Memory manager — менеджер памяти. Механизм выделяющий память и управляющий ею.
- то есть реализация единого интерфейса для разного, но схожего по функциям оборудования.
- Inter Process Communication (IPC) — Механизм межпроцессного взаимодействия
- файлы и файловая система
Основные абстракции ОС¶
- Процессы и потоки — программы, что находятся в оперативной памяти и обрабатываются процессором. Другими словами — исполнение программы.
- Файлы и файловые системы — некоторая структура данных и связи между этими структурами, универсальный системный интерфейс.
- Адресное пространство и память — распределение и управление памятью.
- Сокеты, протоколы, устройства — интерфейсы взаимодействия.
Положение ОС в многоуровневой иерархии организации компьютера¶
Современный компьютер можно представить в виде иерархии уровней (от двух и более), где на каждом уровне выделяются свои абстракции и набор возможных функций.
Рис. 2. Основные уровни устройства ПК
Операционная система является одним из таких уровней и представляет собой интерфейс («прослойку») между пользователем ресурсов компьютера и самими ресурсами, управляющий взаимодействиями как между пользователь-ресурс, так и пользователь-пользователь, устройство-устройство.
В целом, общей схемой это можно отобразить так:
Рис. 3. Место ОС в компьютерной системе
- App — пользователь ресурсов;
- Hardware — оборудование;
- Proc — Процессор;
- Memory — Оперативная память;
- I/O — Устройства ввода/вывода;
Интерфейс — набор правил и средств взаимодействия двух систем. Иными словами способ взаимодействия.
Kernel space — адресное пространство ядра ОС, в котором процессы имеют привилегированный доступ к ресурсам компьютера и другим процессам.
User space — адресное пространство, отведённое для пользовательских процессов (приложений), то есть не имеющих привилегированный доступ к ресурсам.
Как операционная система загружается в компьютер?¶
Процесс загрузки операционной системы и вообще компьютера имеет несколько этапов, основные из которых:
- Запуск компьютера – на процессор подаётся напряжение и его элекрические компоненты начинают работу.
- Процессор начинает исполнять инструкции с фиксированного, аппаратно зашитого в него адреса.
- По этому адресу находится специальная программа POST – Power On Self Test. Которая проверяет работоспособность основных компонентов вычислительной системы.
- Далее, управление передаётся BIOS’y — Basic Input Output System (Базовая система ввода-вывода), которая инициализирует основные устройства ввода-вывода: загрузочные устройства (раличные хранители информации: HDD, SSD, Flash и так далее), клавиатура, монитор и прочее.
- BIOS обращается к загрузочному устройству и читает первый блок данных, на котором должен находиться загрузчик. Загружает его в память и передаёт ему управление.
- Загрузчик загружает в память и инициализирует основные компоненты операционной системы и передаёт ей управление.
- Операционная система запускает таймер, который будет возвращать управление операционной системе каждый, заранее установленный разработчиками ОС, квант времени. Это делается для реализация Scheduler’a — планировщика, чтобы ОС могла управлять и контролировать процессы.
- Операционная система создаёт первый процесс-пользователя и дальше от него начинают множится другие процессы.
Что делает ядро ОС?¶
Ядро ОС – центральная часть операционной системы. По сути, это и есть ОС.
Это реакционный механизм, то есть его работа заключается исключительно в реакции на какие-либо события для их последующей обработки.
- Обрабывает запросы приложений
- системные вызовы (программные прерывания)
- прерывания
- Разного рода ошибки
- реализация многопользовательского режима доступа к ресурсам
- время работы процессора делится на фрагменты и они распределяются по процессам
Процессорное время измеряется в тиках или секундах. Часто бывает полезно измерение процессорного времени в процентах от мощности процессора, которое называется загрузкой процессора.
Вывод программы top. Процессорное время каждого процесса (task) указано в колонке «TIME+», «CPU%» — загружаемость процессора относительно его «мощности».
Прерывания¶
Эта часть больше относится непосредственно к аппаратной части, но этот механизм стоит освятить, так как именно это основной аппаратный механизм реализации ОС.
Прерывание – сигнал остановки последовательного выполнения программы, для обработки запроса или реакции на событие.
Чтобы получить код обработки прерывания, в памяти расположена специальная таблица обработчиков прерываний, в которой для каждого типа прерывания содержится указатель на тот участок памяти, где расположен соответствующий код обработки данного прерывания.
Инициализация данной таблицы первично осуществялется BIOS’ом в соответствии с архитектурой процессора. После, её инициализирует операционная система для дополнения этой таблицы какими-либо своими прерываниями.
- Аппаратные прерывания – с помощью специального контроллера прерываний.
- Нажатие на кнопку
- Заполнение памяти сетевой карты
- И тд.
- Открытие/закрытие файла
- Разного рода ошибки
Как приложения взаимодействуют с ОС?¶
Взаимодействие процессов с ОС осуществляется с помощью системных вызовов.
Механизм системных вызовов — это интерфейс, который предоставляет ядро ОС (kernel space) пользовательским процессам (user space).
Системный вызов – программное прерывание, обращение пользовательского процесса к ядру операционной системы для выполнения какой-либо операции.
Например, чтобы выполнить обычное действие, с точки зрения прикладного программиста, – вывод строки в консоль, необходимо загрузить исполнимый код в оперативную память и передать его процессору. С помощью системных вызовов, запускающий процесс (уже запущенный процесс, из которого вызывается новый процесс — одни процессы порождают другие) обращается к соответствующим сервисам ОС и передаёт им управление для выполнения этих функций.
То есть с помощью системных вызовов выполняются те рутинные действия, которые раньше осуществлялись вручную, — загрузка кода программы в память, передача его на исполнение процессору и прочее.
Схема организации ОС расширяется добавлением интерфейса для взаимодействия приложений с ядром ОС — механизмом системных вызовов:
Рис 4. Интерфейс системных вызовов
Как оборудование взаимодействует с ОС?¶
Оборудование взаимодействует с ОС с помощью аппаратных прерываний. И одна из функций ОС — абстрагирование оборудования.
Что это значит?¶
У каждого оборудования есть свой фиксированный интерфейс. Например, операции с флешкой, жестким диском, сетевой платой и многими другими будут похожи по своему типу — «записать/считать данные». Но у каждого устройства для этого, тем не менее, будет свой особенный и отличный от других интерфейс. То есть эти однотипные действия нужно будет выполнять для разных устройств по разному.
ОС должка выполнять одни и те же операции над разными типами устройств. И чтобы она выполняла их однообразно — нужно чтобы был общий интерфейс. Реализацией этого общего интерфейса занимаются специальные программы — драйверы устройств. То есть, ОС обращается к драйверам устройств используя однотипные команды «отправить команду/считать/записать», а драйвера уже превращает эти команды в то, что понимает конкретное устройство.
Схема организации ОС расширяется добавлением интерфейса взаимодействия ОС и оборудования — специальные программы «драйвера»:
Рис 5. Интерфейс драйверов
Сервисы ОС¶
Функции ОС заключены в её сервисах (модулях). Реализация организации которых зависит от архитектуры ядра. Рассмотрим на примере монолитного ядра:
Рис 6. Основные компоненты ОС
Основные¶
- Управление процессами (Process scheduler — планировщик)
- Запуск (помещение на процессор, выделение процессорного времени)
- Приостановка (заморозка)
- Завершение
- Изменение приоритета
Как говорилось в части о загрузке ОС, реализация планировщика осуществляется с помощью прерывания по таймеру — каждый квант времени происходит прерывание, которое передаёт управление ОС и она анализирует состояние всех процессов и что с каким процессом сделать: запустить, приостановить, завершить или изменить приоритет.
- Межпроцессное взаимодействие (IPC — Inter Process Communication)
- Общая память для нескольких процессов (shared memory)
- Способы обмена данными через те или иные механизмы (file, pipe, signals)
- Сетевое взаимодействие
- Механизмы предотвращения коллизий и синхронизации (семафоры, мьютексы)
- Динамическое выделение памяти (Memory allocation)
- Создание иллюзии уникальности адресного пространства для каждого процесса
- Механизм виртуальной памяти
Дополнительные¶
- Файловая система (File system)
- Файлы и их содержимое
- Каталоги и директории
- Прерывания
- Драйвера
- Пользователи («юзеры») и их группы
- Права доступа
- Интерфейс ввода-вывода (I/O Interface)
- Сетевой интерфейс (Network Interface)
Основные абстракции¶
Процесс¶
Процесс — совокупность инструкций и данных, что находятся в оперативной памяти и обрабатываются процессором. Другими словами — исполнение программы в целом (не путать с потоком исполнения).
Компьютерная программа сама по себе — лишь пассивная последовательность инструкций. В то время как процесс — непосредственное выполнение этих инструкций.
В рамках ОС, это абстракция, которая предоставляет иллюзию персональной машины. То есть то, что данный исполнимый код полностью владеет всеми вычислительными ресурсами машины.
Состояние (контекст) процесса¶
- Состояние
- Состояние памяти
- Содержимое регистров процессора
Изнутри, процесс можно условно разделена на четыре части: Stack, Heap (кучу), Text (код) и данные (Data).
Рис 7. Сегменты памяти процесса
Состояния исполнения¶
Когда процесс выполняется, он проходит через разные состояния. Эти этапы могут различаться в разных операционных системах.
Общая картина выглядит так:
Рис 8. Состояния исполнения процесса
- Новый: начальное состояние при создании процесса.
- Готов: процесс ожидает исполнения на процессоре. В течение работы процессор может переключаться между процессами, переводя одни в режим готовности, другие – в режим исполнения.
- Исполнение: непосредственное выполнение инструкций на процессоре.
- Ожидает: процесс переходит в состояние ожидания. Например, ждёт ввода данных или получения доступа к файлу.
- Завершен: как только процесс завершится, он перейдёт в это состояние и будет ожидать удаления.
Информация о процессе¶
Вся информация о процессе содержится в специальной структуре данных, поддерживаемой операционной системой для каждого процесса – PCB (Process Control Block) — Блок управления процессов.
Рис 9. Process Control Block
- Process ID: идентификатор каждого из процессов в ОС.
- State: текущее состояние процесса.
- Privileges: разрешения доступа к системным ресурсам.
- Pointer: указатель на родительский процесс.
- Priority: приоритет процесса и другая информация, которая требуется для планирования процесса.
- Program Counter: указатель на адрес следующей команды, которая должна быть выполнена.
- CPU registers: регистры процессора, необходимые для состояния исполнения.
- Accounting Information: уровень нагрузки на процессор, статистика и другие данные.
- I/O Information: список ресурсов, использующих чтение и запись.
Информацию о процессах в целом, ОС хранит в специальной таблице процессов.
Поток¶
Процесс может делиться на потоки (threads). Они обеспечивают параллелизм, то есть одновременное исполнение нескольких потоков инструкций, на уровне программы.
Поток выполнения (нить, thread) — последовательность исполнения инструкций. Ход исполнения программы**.
Процесс является контейнером ресурсов (адресное пространство, процессорное время и тд), а поток – последовательность инструкций, которые исполняются внутри этого контейнера.
Реализация потоков выполнения и процессов в разных операционных системах отличается друг от друга, но в большинстве случаев поток выполнения находится внутри процесса.
Рис 10. Многопоточный процесс
Потоки, существующие в рамках одного процесса, в его адресном пространстве, могут совместно использовать ресурсы процесса, например такие как память или файл. Тогда как процессы не разделяют этих ресурсов, так как каждый существует в своём адресном пространстве.
Также поток называют легковесный процесс.
Сегодня потоки широко применяются в работе серверов и многопроцессорных устройств с общей памятью.
Рассмотрим на примере утилиты htop.
Рис 11. Вывод утилиты мониторинга процессов htop
PID — Process ID; Уникальное число идентификатор для каждого процесса
TGID — Tread Group ID; Индентификатор группы потоков
На скриншоте, процесс 2881 имеет множество потоков, отношение которых к нему можно определить по тому, что TGID у этих потоков имеет значение PIDа этого процесса — 2881. Таким образом, один процесс разбивается на множество потоков, в которых инструкции исполняются параллельно.
Чем хороши потоки¶
- Они минимизируют время переключения контекста (процессора).
- Их использование обеспечивает параллелизм процесса.
- Они эффективно общаются между собой.
- Потоки позволяют использовать многопроцессорные архитектуры в большем масштабе.
Файл¶
Это очень широкое и многогранное понятие. Но если выделить наиболее общее, то получится, что файл — это универсальный системный интерфейс для обращения к тем или иным данным.
А файловая система — это система имён. То есть возможность выделять те или иные объекты данных и присваивать им имена, а также выделять иерархию.
По другому, файл и файловую систему можно также представить как структуру данных и связи между этими структурами.
Реализация многозадачности¶
Осуществляется при помощи следующих механизмов:
- Прерывание таймера
- когда при запуске, ОС программирует таймер на то, чтобы он каждый квант времени передавал управление ОС.
- сохранение состояния исполнения (регистров) процесса и установка на процессор контекста другого процесса.
Переключение контекста¶
Контекст процесса — это состояние регистров, при его выполнении на процессоре.
Следовательно, переключение контекста — это смена контекста одного процесса, на контекст другого, без потери данных сменяемого процесса — то есть, чтобы его потом можно было восстановить с того момента, где он был переключён.
Например, у нас на процессоре в данный момент времени выполняется «процесс 1» — в регистрах хранятся данные, которые относятся к этому процессу.
Но происходит прерывание и «процесс 1» снимается с выполнения на процессоре, чтобы вместо него выполнялся «процесс 2». Следовательно, нужно заполнить регистры уже теми данными, что относятся к «процессу 2».
Однако, «процесс 1» ещё не выполнился полностью, и для дальшейнего исполнения ему нужны те данные, что хранились в регистрах при прерываний, то есть необходим его контекст. Операционная система должна обеспечивать подобные смены контекстов без потери данных.
- Как?
- Когда?
- Между кем и кем?
Как?¶
- Значения регистров процесса записываются в Stack этого же процесса в оперативной памяти. Таким образом, процесс в своей памяти хранит свой же контекст.
- Контекст планировщика появляется на процессоре, выполняет анализ имеющихся процессов.
- Переключает процессор на контекст уже другого, нового процесса.
В целом, смена контекста происходит между состояниями «Готов», «Ожидает» и «Исполняется».
Критические секции и блокировки¶
Одна из основных проблем с которыми может столкнуться такая система с вытесняющей многозадачностью — порядок доступа процессов к их общим ресурсам.
Возникают, так называемые, критические секции – участки исполняемого кода программы, в которых производится доступ к общему ресурсу (данным или устройству), который не должен быть одновременно использован более чем одним потоком выполнения.
Рис 12. Критические секции в потоках процесса
Может возникнуть такая ситуация, когда один поток, «потребитель», начинает использовать данные, которые должен подготовить другой поток, «производитель», но этот производитель ещё не закончил их подготовку и снялся с исполнения. Таким образом, «потребитель» использует некорректные данные, что с высокой долей вероятности приведёт к ошибке.
Данная проблема решается с помощью механизма блокировок – когда поток, получивший доступ к ресурсу, блокирует его, не давая другим потокам пользоваться этим захваченным ресурсом до разблокировки. То есть, если один поток хочет захватить (заблокировать) ресурс, а он уже занят другим потоком, то первый будет ожидать пока этот другой поток-владелец сам не освободит этот ресурс.
Все эти механизмы обеспечиваются операционной системой
Чтобы лучше это понять, можно обратиться к аналогии с туалетом — им может пользоваться только один человек. Если другой хочет им воспользоваться, то ему нужно дождаться когда его освободит уже им пользующийся.
Deadlock — взаимная блокировка¶
Из-за блокировки, захвата ресурса может возникнуть другая проблема: Deadlock — взаимная блокировка.
Рис 13. Аналогия пробки на перекрёстке с Deadlock
Deadlock — ситуация, при которой несколько потоков находятся в состоянии ожидания ресурсов, занятых друг другом, и ни один из них не может продолжать свое выполнение.
Пример Deadlock’a на псевдокоде¶
Шаг Поток 1 Поток 2 0 Хочет захватить A и B, начинает с A Хочет захватить A и B, начинает с B 1 lock(A) — Захват А lock(B) — Захват B 2 lock(B) — Ожидает освобождения ресурса B lock(A) — Ожидает освобождения ресурса A … DEADLOCK –> Далее код не выполнится, так как произошел Deadlock в коде выше n unlock(A) — освобждение A unlock(B) — освобждение B n+1 unlock(B) — освобждение B unlock(A) — освобждение A Схематично, Deadlock можно изобразить так:
Рис 14. Deadlock
Проблема Deadlock-ов решаема и существует множество способов сделать это — начиная от недопущения подобных ситуаций в самом коде программы, заканчивая механизмами операционной системы, которые разрешают подобные ситуации. Но, однозначно исключить вероятность возникновения подобных ситуаций нельзя. Однако, это отдельная достаточно большая тема.
Адреса и управление памятью¶
Тема адресации очень сложна, поэтому здесь я лишь проведу краткий обзор общей технологии.
- Физический адрес – непосредственно адрес внутри микросхемы памяти, который передаётся по шине памяти.
- Логический адрес – тот адрес, которым оперирует процесс.
Чтобы отобразить логический адрес в физический, существует специальный аппаратный механизм.
- Реальный режим
- Защищенный режим
Итог¶
Начав с базовой архитектуры и небольшой истории развития компьютера, мы разобрали причины появления такого комплекса программ как операционная система и выделили главную её цель – обеспечение согласованного доступа к ресурсам компьютера множеству пользователям этих ресурсов, а также управление как самими ресурсами, так и пользователями.
Основные механизмы (сервисы)¶
Рассмотрели основные механизмы реализации этой цели: Scheduler (планировщик), Inter Process Communication (межпроцессное взаимодействие), Memory manager (управление памятью) и другие.
Абстракции¶
Ряд абстракций, которые вводит ОС: Process (процесс), Thread (поток исполнения), File (файл).
Заключение¶
Ух, и вот наконец-то я закончил писать этот материал. Надеюсь, вам было интересно и полезно.
Если вы хотите как-то дополнить материал, дать критику по его содержанию или структуре – пожалуйста, пишите в Issue данного репозитория поднимая ту или иную тему для обсуждения и доработки.
Также, вы можете сделать Fork данного репозитория и после внести свои дополнения с помощью Pull Request. Спасибо за внимание!
© Copyright 2020, Kalashnikov Ivan Revision 17a143dc .
Built with Sphinx using a theme provided by Read the Docs.
Read the Docs v: latestVersions latest Downloads pdf html epub On Read the Docs Project Home Builds Free document hosting provided by Read the Docs.
Что показывает команда TOP
Данная строка показывает общее количество процессов, сколько из них запущено, сколько находится в спящем режиме, сколько процессов остановлено, а также количество зомби процессов — процессы, которые закончили свое выполнение, имеется ошибка в работе процессов. Столбец S – текущий статус процесса: R – running; S – sleeping, Z – zombie
Cpu(s): 1.1%us, 0.7%sy, 0.0%ni, 97.9%id, 0.2%wa, 0.0%hi, 0.2%si, 0.0%st
Данная строка рассказывает нам о состоянии процессора, на что затрачено 100% процессорного времени.
us -(%) действия в пользовательском пространстве;
sy — (%)затраченного на действия в пространстве ядра;
ni — (%) затраченного на процессы с низким приоритетом
id — процент (%) затраченного на простаивание — какое количество времени процессор делает ничего
wa — процент (%) затраченного на ожидание дисковых операций.
hi — процент (%) процессорного времени, затраченного на обработку аппаратных прерываний;
si — процент (%) процессорного времени, затраченного на обработку прерываний ПО;
st — время в вынужденном ожидании виртуального CPU, пока гипервизор обслуживает другой процессор.Mem: 16466952k total, 6696972k used, 9769980k free, 39484k buffers
Эта строка в блок посвященный оперативной памяти. Информация о памяти: total — всего памяти; free — доступно незамедлительно; used — используется в данный момент; buff/cache — сумма буферов и кэша (фактически это можно считать доступной свободной памятью, так как чаще всего эта величина содержит в себе счётчик памяти, требуемой для информации, которая уже записана на диск или скоро будет записана.
Swap: 33554428k total, 45812k used, 33508616k free, 4965696k cached
Информация о свап-памяти: всего, свободно, использовано, доступно.
Также информацию о доступной ОЗУ покажет free.
Загрузка системы (Load average, LA)
Высокие значения показателей load average (LA) говорят о том, что система не справляется с нагрузкой. Если речь идет о целевом сервере, работающем под высокой нагрузкой, то обычно полезно провести тонкую настройку операционной системы (сетевая подсистема, ограничение на количество одновременно открытых файлов и тому подобное). Высокая загрузка также может быть вызвана аппаратными проблемами (выход из строя жесткого диска) или Обнаружение и защита от DDoS-атак.
top - 10:12:16 up 1 day, 57 min, 3 users, load average: 0.48, 0.94, 1.19
текущее время;
up time — время работы системы после включения питания;
user — количество пользователей, которые в данный момент работают в системе;load average — общая средняя загрузка системы (измеряется каждые 1, 5 и 15 минут). Общей средней загрузкой системы называется среднее число процессов, находящихся в состоянии выполнения (R) или в состоянии ожидания (D), эту информацию можно увидеть в колонке S вывода команды top, она может принимать 5 значений:
'D' = uninterruptible sleep (состояние ожидания) 'R' = running (состояние выполнения) 'S' = sleeping 'T' = traced or stopped 'Z' = zombie
Некоторые интерпретации load average:
Если значения равны 0.0, то система в состоянии простоя.
Если среднее значение для 1 минуты выше, чем для 5 или 15, то нагрузка растёт.
Если среднее значение для 1 минуты ниже, чем для 5 или 15, то нагрузка снижается.Если значения нагрузки выше, чем количество процессоров, то у вас могут быть проблемы с производительностью (в зависимости от ситуации).
По этому набору из трёх значений вы можете оценить динамику нагрузки, что безусловно полезно. Также эти метрики полезны, когда требуется какая-то одна оценка потребности в ресурсах, например, для автоматического масштабирования облачных сервисов.
Приведем простой пример: имеется VPS с двумя ядрами. Значение средней нагрузки: 1.03, 1.11, 1.20 — нормальное значение нагрузки для VPS с 2 ядрами.
1 (единица) LA = 100% нагрузка на 1 ядро CPU. Если на VPS два ядра, то средняя нагрузка может достигать 2 LA:
— LA отображает значения 3.21, 4.22, 5.23 — нагрузка падает, но за последние 15 минут в среднем она была 4.22, что равно 422% нагрузки = 4 из 2 ядер — не норма;
— LA показывает значения 7.15, 5.24, 1.18 — нагрузка увеличивается, и за последние 15 минут она была 1.18, в пределах нормы, что соответствует 118% нагрузки = 1 из 2 ядер — в пределах нормы (пик нагрузки, продолжающийся вплоть до 30 мин, допустим).
Состояния процессов
Tasks: 225 total, 1 running, 224 sleeping, 0 stopped, 0 zombie
total — общее количество процессов в системе;
running — количество процессов, выполняемых процессором или стоящих в очереди на выполнение;
sleeping — количество процессов, ожидающих какого-либо события ввода-вывода;
stoped — количество приостановленных процессов;
zombie — количество процессов, находящихся в состоянии «зомби».Состояния процессора (ЦП)
Состояния процессора (ЦП).
Cpu(s): 1.1%us, 0.7%sy, 0.0%ni, 97.9%id, 0.2%wa, 0.0%hi, 0.2%si, 0.0%st
us — (User CPU time) процент использования процессорного времени программами пользователей;
sy — (System CPU time) процент использования процессорного времени процессами ядра Linux;ni — (Nice CPU time) процент использования процессорного времени программами с измененным приоритетом;
id — простой процессора
wa — (iowait) время, затраченное на завершение ввода/вывода (IO)hi — (Hardware IRQ) процент времени, которое процессор тратит на обработку прерываний на уровне оборудования (hardware- прерываний).
si — (Software Interrupts) процент времени, затраченное на работу обработку software- прерываний (network)
st — (Steal Time, Время кражи) время, «украденное» гипервизором у этой виртуальной машины для других задач (например работа другой виртуальной машины). Steal Time — это процент времени, в течение которого процесс виртуальной машины ожидает от физического процессора своего процессорного времени. Вы можете отслеживать процессы и использование ресурсов, запустив команду «top» на вашем сервере Linux. Если значение Steal Time равно 20st, это означает, что 20% общего времени процесса тратится на ожидание выделения физического ЦП. Максимальное значение, которое может иметь st, равно 100,0. Это наихудший сценарий, когда виртуальный ЦП ничего не делает, а только ждет, пока гипервизор выделит физический ЦП. К счастью, такая ситуация встречается очень редко. Если st ЦП меньше 10, то беспокоиться не о чем, и приложение должно работать без сбоев. Однако виртуальная машина, вероятно, работает медленнее, чем ожидалось, если значение времени кражи превышает 10, т. е. превышает нормальное значение примерно на 20–30 минут.
Состояние оперативной памяти (ОЗУ)
Состояние оперативной памяти (ОЗУ). Top показывает, что на компьютере установлено 16GB ОЗУ.
Mem: 16466952k total, 6696972k used, 9769980k free, 39484k buffers
total — общее количество оперативной памяти (16466952k / 1024 = 16081MB (мегабайт) = 16GB);
used — количество использованной оперативной памяти (6540MB);
free — количество свободной оперативной памяти (9540MB);
buffers — (38MB).top показывает объем занятой памяти вместе с кэш. htop выдает объём реально занятой памяти без кэша. Для проверки достоверности данных можно использовать утилиту free как правильно смотреть свободное ОЗУ Linux, которая покажет сколько занято памяти с кэш и без.
Состояние Swap
Использование Swap- раздела:
Swap: 33554428k total, 45812k used, 33508616k free, 4965696k cached
total — общее количество swap- раздела (33554428k / 1024 = 32767 MB );
used — количество использованного swap- раздела (45812k = 44 MB );
free — количество свободного swap- раздела.Расшифровка столбцов
VIRT — (kb — килобайты). Общее количество виртуальной памяти, используемой программой. VIRT = SWAP + RES.
RES — (kb). Количество резидентной (не перемещаемой в swap) памяти. RES = CODE + DATA.
SHR — (kb). Количество разделяемой (shared) памяти программы.
S — статус процесса.htop
Htop – основанный на ncurses просмотрщик процессов подобный top, htop, atop определение загрузки ОС (Load average, LA), но позволяющий прокручивать список процессов вертикально и горизонтально, чтобы видеть их полные параметры запуска. Управление процессами (остановка, изменение приоритета) может выполняться без ручного ввода их идентификаторов.
Htop экономит одну колонку и показывает в колонке PID(процесс) то, что Использование ps для мониторинга процессов (ps -eLf) показывает в колонке LWP(поток; процесс — контейнер для потоков)
htop в CentOS теперь CentOS Stream установка из репозитория см. rpm
# wget http://download.fedora.redhat.com/pub/epel/5/x86_64/htop-0.8.3-1.el5.x86_64.rpm # rpm -i htop-0.8.3-1.el5.x86_64.rpm
Замечания к BSD системам, при использовании htop
При установки htop на FreeBSD требует смонтированную систему linprocfs, для совместимости с Linux. linprocfs — the Linux process file system, or linprocfs, emulates a subset of Linux’ process file system and is required for the complete operation of some Linux binaries.
> man linprocfs . > mount -t linprocfs linproc /compat/linux/proc > df -h . linprocfs 4.0K 4.0K 0B 100% /usr/compat/linux/proc > cd /usr/ports/sysutils/htop > make install clean
Скрипт для монтирования linprocfs при загрузки FreeBSD:
> ee /usr/local/etc/rc.d/0start.sh #! /bin/sh #for htop /sbin/mount -t linprocfs linproc /compat/linux/proc
Или прописать в fstab строку и для проверки примонтировать командой mount linproc
linproc /usr/compat/linux/proc linprocfs rw 0 0
atop
Домашняя страницаatop. Atop — это ASCII полноэкранный монитор производительности для Linux, который способен сообщать об активности всех процессов (даже если процессы завершились во время интервала), ежедневно записывать в журнал активность системы и процессов для долгосрочного анализа, выделять перегруженные системные ресурсы с помощью цветов и т.д. Через регулярные интервалы времени он показывает активность на уровне системы, связанную с процессором, памятью, подкачкой, дисками (включая LVM) и сетевым уровнем, и для каждого процесса (и потока) показывает, например, использование процессора, рост памяти, использование диска, приоритет, имя пользователя, состояние и код завершения.
В сочетании с дополнительным модулем ядра netatop, он даже показывает сетевую активность для каждого процесса/потока.
CentOS: yum install atop Daebian: Ubuntu apt install atop
systemctl enable atop
systemctl start atop
Конфигурационный файл /etc/default/atop считается устаревшим в некоторых системах, если это так изучайте /usr/share/atop/atop.daily
atop
Команда atop имеет несколько основных преимуществ по сравнению с другими инструментами мониторинга производительности:
Потребление ресурсов всеми процессами. Она показывает потребление ресурсов всеми процессами, которые были активны в течение интервала, а также потребление ресурсов теми процессами, которые завершились в течение интервала.
Использование всех соответствующих ресурсов. Очевидно, что он показывает счетчики системного уровня, касающиеся использования процессора и памяти/swap, однако он также показывает счетчики дискового ввода-вывода и использования сети на системном уровне.
Постоянное протоколирование использования ресурсов. Он способен сохранять необработанные счетчики в файл для долгосрочного анализа на системном уровне и на уровне процессов. Эти необработанные счетчики сжимаются в момент записи, чтобы минимизировать использование дискового пространства. По умолчанию ежедневные файлы журнала сохраняются в течение 28 дней. Отчеты об активности системы могут быть сгенерированы из файла журнала с помощью команды atopsar.
Выделить критические ресурсы. Выделяет ресурсы, которые (почти) достигли критической нагрузки, с помощью цветов для системной статистики.
Масштабируемая ширина окна. Он способен динамически добавлять или удалять колонки в тот момент, когда вы увеличиваете или уменьшаете ширину окна.
Потребление ресурсов отдельными потоками. Он может показывать потребление ресурсов для каждого потока в рамках процесса.
Смотреть только активность. По умолчанию показывает только те системные ресурсы и процессы, которые были действительно активны в течение последнего интервала, поэтому вывод, относящийся к ресурсам или процессам, которые были полностью пассивны в течение интервала, по умолчанию подавляется.
Смотреть только отклонения. Для активных системных ресурсов и процессов отображается только загрузка за последний интервал (не накопленное использование с момента загрузки системы или запуска процесса).
Накопленная активность процессов для каждого пользователя. Для каждого интервала можно накопить потребление ресурсов для всех процессов по каждому пользователю.
Накопленная активность процессов для каждой программы. Для каждого интервала, он способен накапливать потребление ресурсов для всех процессов с одинаковым именем.
Сетевая активность на процесс. В сочетании с дополнительным модулем ядра netatop, он показывает счетчики на уровне процесса, касающиеся количества переданных TCP и UDP пакетов, а также потребленной пропускной способности сети для каждого процесса.
Как пользоваться atop
Команда atopsar — это встроенный анализатор логов atop, который позволит быстро найти проблему и смотреть лог в нужное вам время.