В 47 мои увлечения стали Си, Radare2 , Биты, Логика, Память. Изучая память зацепился за адреса. На адрес 0x7ffe10b284 можно смотреть бесконечно долго. Трудно сказать с ходу насколько удачно ваши данные легли в память. Влезают они в одну кеш-линию или размазаны по двум. Чтоб не заниматься битовой арифметикой в уме, я написал утилиту на Си для Linux и Termux. Она раскладывает младшие 12 бит адреса на 4 строки визуализации. Теперь сразу видно, попали мы в «Голову» или застряли в «Хвосте» кеш-линии.
Утилита максимально легковесная. Вам не нужны сложные дебаггеры, достаточно gcc. Работает, как на десктопном Linux, так и в Termux на Android. Можно проверить выравнивание даже лёжа на диване.
Что такое «Голова» и «Хвост» кеш-линии
В современных процессорах (х86_64, ARM) память нарезана на блоки по 64 байта — это и есть кеш-линия. Процессор не умеет забирать из памяти один байт, он всегда тянет всю линию целиком.
Если ваша структура данных (например 16 интов) начинается в начале этой линии (адрес кратен размеру данных 64), она ложится в ее «Голове». Если же адрес смещен к концу блока (ближе к 63-му биты), данные попадают в хвост.
Почему это критично
Представьте вашу структуру массив на 16 интов (это как раз 64 байта размер кеш-линии). И вы не расположили так, что 8 интов лежат в конце одной кеш-линии в «Хвосте» , в остальные 8 в начале следующей.
-
РЕЗУЛЬТАТ: Процессору придётся выкачивать две линии вместо одной. Поход в память это дорого. Процессору в этом случае приходится ждать заряд, разряд конденсаторов.
-
ИТОГИ: Лишние такты, посадка производительности, не эффективное использование кеш L1.
АККУМУЛЯТОР: Каждая лишняя активная линия это мизерный но реальный ток. В масштабах миллионов операций в секунду это превращается в повышенный расход АКБ. Что особенно критично для мобильных устройств.
Код на Си
Я новичок мой код скорее всего кривой и косой. Я хочу визуализировать адрес памяти.
Логика простая: мы берём адрес переменной, разглаживает на биты и смотрим карту где мы находимся. Смещение страницы, кеш, номер набора и все остальное.
#include <stdio.h>#include <stdint.h>#define RAZR 12 //колличество разрядов выводим на печать#define GEL "\033[1;33m"#define RED "\033[1;31m"#define GRIN "\033[1;32m"#define ROZ "\033[1;35m"#define SIN "\033[1;34m"#define RES "\033[0m"void hex_dec_nom_raz(){ printf("\n\n"); int dec = 1; // строка десятичное представление двоичного числа dec for (int i = 0; i < RAZR; i ++) { printf(GRIN "%8d" RES , dec); dec = dec << 1; } printf("\n\n"); for (int i = 0; i < RAZR; i ++) // строка для вычисления номера индекса номер набора { printf(ROZ "%8d" RES ,1 << (i % 6)); } printf("\n\n"); for (int j = 0; j < RAZR; j ++) // строка для номер разряда { printf(SIN "%8d" RES , j); } printf("\n\n");}int bin_addr (uint64_t addr) //функция двоичного вида адреса{ int bin, offset_kech, mask = 63; for (int i = 0; i < RAZR; i ++) { bin = (addr >> i) & 1; // для цветного вывода единиц if (bin == 1) { printf(RED "%8d" RES, bin); } else { printf("%8d", bin); } } offset_kech = addr & mask; // смотрим смещение в КЭШ линии if ( offset_kech != 0 ) { printf(GEL "\nРасстояние до головы КЕШ линии > %d < байт \n" RES, offset_kech); } else { printf(GEL "\nТы попал в голову\n" RES); } printf("\n"); return 0;}int main (){ uint64_t addr_mem; hex_dec_nom_raz (); while (1) { if (scanf("%li", &addr_mem) == 1) { bin_addr (addr_mem); } else { break; } } return 0;
Эксперимент
Сравним два адреса. Чтоб окончательно убедиться в пользе визуализатор, я сравниваю два случая.
Пишем две маленькие программы. В каждой программе массив, один случайный, другой выровненный по кеш-линии. И нам нужно вывести адреса нулевых элементов.
Массив со случайным адресом < vim mas_random.c>
Массив выровненный по кеш-линии <vim mas_alig.c>
gcc mas_alig.c -o mas_alig
-
gcc mas_random.c -o mas_random
-
./mas_alig
-
./mas_random
-
Утилита после запуска Адрес жёлтого цвета это выровненный массив по кеш-линии
-
Адрес красного цвета это адрес случайного массива
-
РОЗОВАЯ ЛИНИЯ: Номер набора.
-
СИНЯЯ ЛИНИЯ: Номер разряда.
-
БЕЛЫЕ ЛИНИИ: Двоичное представление адреса памяти.
-
Мы можем управлять разрядностью #define RAZ.
-
Вводить сколько угодно адресов.
-
DEC or HEX
-
Выход из программы любой символ я применяю стандарт » q «.
-
Можно выводить множество сообщений где ты находишься в кеш, на странице, можем расписать тэги.
Запуск
./bin_analiz_addt

ЗЕЛЁНАЯ ЛИНИЯ: Десятичное представление двоичного числа.
Первый адрес заканчивается на 0х80 это выровненный массив по кеш-линии. Единица в 7 разряде. Мы положили свои 16 интов в одну кеш-линию. ( Потом мы можем прочитать смещение страницы нам до «Головы» 128 байт. 4096 — 128 полученная цифра расстояние до «Хвоста» (до конца страницы). Номер набора 2 розовая линия с 6 по 11 разряды.
Второй адрес заканчивается 0х7с это адрес случайного массива. Две кеш-линии не избежны. Мы находимся в средине страницы сложи 1024+512+256+64+32+16+8+4. Номер набора 1 +4+8+16.
Здесь на самом деле много информации
Техничка
Ссылка на GitHub
ссылка на оригинал статьи https://habr.com/ru/articles/1026430/