Обновить
16K+
3

Пользователь

22
Рейтинг
6
Подписчики
Отправить сообщение

Деконструкция GO: CPU, RAM и что там происходит. Системные вызовы. Часть 1.5

Уровень сложностиПростой
Время на прочтение6 мин
Охват и читатели11K

Итак, финал части 1! По крайней мере основного разбора без дополнений. Собственно, сегодня мы разберем то, чем в основном с точки зрения ядра ОС и CPU являются все вот эти ваши бэкенды – системные вызовы и всё, что вокруг них.

На самом деле механизм немного замудренный и “в лоб” сразу все эти системные вызовы мы разбирать не будем, потому что вокруг них существует ещё несколько концепций.

Итак, начнем!

User mode, Kernel mode

Процессор исполняет код в разных уровнях привилегий.

Это механизм защиты, который не позволяет пользовательским программам напрямую управлять системой. Зачем? Для безопасности. Чтобы чей-нибудь опасный ассемблерный вайбкод случайно всё не поломал!

Да и вообще, если бы любая программа могла выполнять любые инструкции CPU, она могла бы:

• Читать память других процессов

• Управлять устройствами

• Изменять таблицы страниц

• Выключать систему

Чтобы этого не происходило, CPU разделяет код по уровням доступа.

Хотя в архитектуре x86 существует 4 уровня привилегий:

Ring 0 – kernel mode

Ring 1 – драйверы

Ring 2 – системные службы и файлы

Ring 3 – user mode

По факту, Ring 1 и Ring 2 – это легаси, которое американские деды проектировали с научной красотой, но без реальной производственной необходимости. В реальной жизни используются только 2 уровня – Ring 0 и Ring 3 для бОльшей совместимости софта с другими ОС, упрощения поддержки, да и вообще переключение уровней доступа дорогое(100-150 тактов CPU), соответственно, чем больше колец, тем хуже производительность.

Получается, что

В user mode выполняется обычный код программ.

Читать далее

Деконструкция GO: CPU, RAM и что там происходит. Оптимизации на CPU. Часть 1.4

Уровень сложностиСредний
Время на прочтение7 мин
Охват и читатели7.3K

Первые великие оптимизаторы появились уже на таком низком уровне, как железо. По факту, задача выжимки ресурсов в программировании есть на любом уровне. В этой статье мы разберем оптимизации на уровне CPU такие как NUMA, prefetch, TLB и alignment.

Статья получится немного неоднородной и больше про “высокие материи”, что в принципе намекает на то, что разбор “железной” составляющей скоро подойдет к концу!

Вводная

Как мы рассматривали некогда ранее обращение на RAM – это достаточно дорого. CPU пытается это “скрыть”, чтобы работа казалась куда более быстрой.

Одним из таких механизмов, естественно, является иерархия кэшей!

Но вот не возникало ли у вас вообще вопроса – “А почему память – это в принципе проблема? Почему дорого?”. Все очень просто – доступ к памяти медленный

Тактовая частота например моего ноута – 2,70 ГГц, то есть 2,7 миллиарда циклов/операций в секунду

Доступ к ОЗУ имеет задержку аж в 150–350 циклов! То есть за это время мы могли бы выполнить 200 операций. 

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

Prefetch

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

На всякий случай зафиксируем:

Читать далее

Деконструкция GO: CPU, RAM и что там происходит. Reordering, atomics, locks, fences. Часть 1.3

Уровень сложностиСредний
Время на прочтение8 мин
Охват и читатели7.7K

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

В этот раз снова будет Go Assembler, а также снова будут примеры на Go. В прошлый раз это было необходимое зло во имя соответствия реальности

Напоминаю, что эта статья – часть большого цикла разбора языка программирования Golang End 2 End. Но если вы уверены, что понимаете природу многозадачности, многопоточности, проблемы оных, а также то, как выполняются инструкции и пришли разбираться в самых примитивных механизмах синхронизации, то велком

Instructions reordering

Обычно мы считаем, что CPU добросовестно выполняет свои инструкции последовательно. Ровно так, как мы ему сказали. Но это не всегда верно!

Допустим есть код

Читать далее

Деконструкция GO: CPU, RAM и что там происходит. Многозадачность, многопоточность, кэши, проблемы. Часть 1.2

Уровень сложностиПростой
Время на прочтение9 мин
Охват и читатели8.7K

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

В части 1.1 мы рассмотрели базовые инструкции, которые выполняет наш CPU и которыми в конечном счете и являются наши прекрасные строчки на Go. Но возникает закономерный вопрос: “Окей, мы поняли как работает на одном ядре, но Go у нас во многом про многопоточку, соответственно как это будет работать на нескольких потоках?”

Если что, то это часть большого цикла по разбору Go! Данная статья – это подводка уже к тому, с чем мы имеем дело в Go достаточно часто(барьеры памяти, атомики, сисколы)

В этот раз будет без Go Assembler, но с +- реальными примерами, если что-то непонятно будет, то на Хабре есть классный ИИ-помощник.

Читать далее

Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1

Уровень сложностиПростой
Время на прочтение9 мин
Охват и читатели9.4K

Go-код никогда не исполняется напрямую.

Любая строка Go превращается в машинные инструкции, которые выполняет CPU.

В этой статье мы разберём:

1) Какие инструкции генерирует компилятор Go

2) Как выглядит Go assembler

3) И что на самом деле выполняет процессор

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

Напомню, что сам CPU определяет:

Читать далее

Деконструкция Go: модель памяти, happens-before и почему ваш код работает. Часть 0

Уровень сложностиПростой
Время на прочтение5 мин
Охват и читатели6.6K

Приветствую всех!

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

Решил я фундаментально разобрать то, как работает Golang, потому что в интернете(YT, Конфы и пр.), на мой взгляд, крайне много откровенно поверхностной и верхнеуровневой информации. Я, конечно, буду рад, если вы укорите меня в моих слабых навыках поиска и покажете мне, что реальность не такая, какой я её выдумал, но субъективно это так.

Разборы здесь будут скорее про то, что лежит в порождении сумрачного американского гения по ссылке github.com/golang/go с периодической синхронизацией с официальной документацией.

Моя главная цель – разобрать всё максимально исчерпывающе, насколько я это смогу.

Чтож, поехали!

Ах, да. В этом цикле не будет особо веселых рисуночков с гоферами, а скучные блок-схемы, диаграммы и вырезки из кода.

Структурная схема

Читать далее

Информация

В рейтинге
361-й
Зарегистрирован
Активность