中文翻译暂不可用,显示俄语原文。
Профилировать NUMA влияние на latency
ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Профилировать NUMA влияние на latency
1. Цель задачи
Научиться измерять и анализировать влияние NUMA-топологии на латентность доступа к оперативной памяти в многосокетных системах (AMD EPYC). Выполнить серию экспериментов с привязкой процессов к разным NUMA-узлам с помощью numactl, зафиксировать разницу в latency между локальным и удалённым доступом к памяти. Закрепить понимание того, как архитектура NUMA влияет на производительность latency-чувствительных приложений.
Ключевой результат Документ с отчётом, содержащим результаты замеров latency на локальной и удалённой NUMA-ноде, подтверждающий разницу в 2–3 раза (или более), а также практические рекомендации на основе полученных данных.
2. Исходные данные
| Что нужно | Откуда взять |
|---|---|
| Сервер с NUMA-архитектурой (например, AMD EPYC, 2+ NUMA-узла) | Физическая машина / облачный bare-metal инстанс |
| ОС Linux (ядро 5.x+) с поддержкой NUMA | Установленная система, `dmesg |
Утилита numactl | Репозиторий дистрибутива (apt / yum) |
Утилита perf | linux-tools-common / linux-tools-generic |
| Микро-бенчмарк для измерения латентности памяти | Собственная программа на C / lmbench / mbw + stress-ng |
| Графический инструмент (gnuplot / matplotlib) | Для построения графиков, необязательно |
Если нет реального инструмента — симулируем:
- Использовать QEMU/KVM с эмуляцией нескольких NUMA-узлов:
qemu-system-x86_64 -m 8G -smp 4 -numa node,cpus=0-1,memdev=mem1 -numa node,cpus=2-3,memdev=mem2 -object memory-backend-ram,id=mem1,size=4G -object memory-backend-ram,id=mem2,size=4G - В облачных средах (AWS / GCP) выбрать bare-metal инстансы с multi-socket (например, m5n.metal).
- Если доступен только односокетный процессор — запустить numactl --hardware и убедиться, что есть как минимум два узла (возможно, через эмуляцию подсистемы; в противном случае задание невыполнимо – нужно дополнить наблюдением: «на односокетных системах разница будет минимальна, эксперимент не имеет смысла»).
3. Технологический стек
| Компонент | Инструменты | Назначение |
|---|---|---|
| Операционная система | Linux (Ubuntu 22.04 / RHEL 9) | Запуск тестов |
| Управление NUMA | numactl, numastat | Привязка потоков/памяти, просмотр топологии |
| Профилирование | perf, likwid-perfctr | Замеры циклов, латентности кэша/памяти |
| Микро-бенчмарк | lmbench (lat_mem_rd), stress-ng, mbw | Измерение latency и bandwidth |
| Программирование | C / Python (ctypes) | Собственный бенчмарк (опционально) |
| Визуализация | gnuplot / matplotlib | График latency против размера рабочего набора |
| Анализ | Bash, awk, скрипты | Обработка сырых данных |
4. Этапы выполнения
Этап 1: Изучение NUMA-топологии и подготовка окружения (20–30 мин)
Действия
- Выполните команду numactl --hardware и запишите:
- количество NUMA-узлов;
- какие CPU и область памяти привязаны к каждому узлу;
- расстояние между узлами (distance).
available: 2 nodes (0-1) node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 node 0 size: 128929 MB node 0 free: 118629 MB node 1 cpus: 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 node 1 size: 129021 MB node 1 free: 119028 MB node distances: node 0 1 0: 10 21 1: 21 10 - Убедитесь, что numactl, numastat, perf, lmbench (или его аналоги) установлены. Если нет — установите:
sudo apt install numactl linux-tools-common lmbench stress-ng mbw - Соберите lat_mem_rd из пакета lmbench (или используйте готовый бинарник).
Ожидаемый результат этапа Полная карта топологии NUMA, готовый инструментарий.
Этап 2: Измерение локальной латентности (30–40 мин)
Действия
-
Запустите lat_mem_rd на процессоре и памяти одного и того же NUMA-узла (например, узел 0):
numactl --cpunodebind=0 --membind=0 lat_mem_rd -W 100 -N 100 -t 128M 2>&1 | tee local_0.log(где
-W— количество разогрева,-N— количество измерений,-t— размер доступа, 128M — размер рабочего набора, превышающий L3-кэш). -
Выполните тест для разных размеров рабочего набора (stride) — от 1K до 128M (можно скриптом):
for s in 1K 8K 64K 512K 4M 32M 128M; do numactl --cpunodebind=0 --membind=0 lat_mem_rd -W 100 -N 100 -t $s 2>&1 | tee -a local_results.txt done -
Извлеките из вывода среднее значение latency (в наносекундах) для последнего, наибольшего размера (обычно он показывает latency DRAM).
Ожидаемый результат этапа Файл local_results.txt с таблицей «размер – latency» для локального доступа.
Этап 3: Измерение удалённой латентности (30–40 мин)
Действия
- Запустите тот же бенчмарк с привязкой процессора к узлу 0, но памяти — к узлу 1 (remote access):
numactl --cpunodebind=0 --membind=1 lat_mem_rd -W 100 -N 100 -t 128M 2>&1 | tee remote_01.log - Повторите сканирование по размерам, сохраняя в
remote_results.txt. - Выполните обратный случай: процесс на узле 1, память на узле 0.
- Для каждого измерения запишите также значение из
/sys/devices/system/cpu/cpu*/cache/index*/для информации о кэшах (необязательно).
Ожидаемый результат этапа Файл remote_results.txt с аналогичной структурой.
Этап 4: Дополнительные эксперименты (1–1.5 ч)
Действия
- Влияние количества потоков – запуск multithreaded-бенчмарка (stress-ng) с разным числом потоков:
Замерьте среднюю латентность через perf stat -e cache-misses,LLC-load-misses.numactl --cpunodebind=0 --membind=0 stress-ng --memrate 0 --mem-ops 100000 --mem-rate-method cache-miss --numa-rast --taskset 0-3 - Bandwidth test – с помощью mbw:
Сравните пропускную способность.numactl --cpunodebind=0 --membind=0 mbw -n 10 -t memcpy -b 4096 numactl --cpunodebind=0 --membind=1 mbw -n 10 -t memcpy -b 4096 - Гибридная привязка (interleaving) – запуск numactl --interleave=all – замерить среднюю латентность.
Ожидаемый результат этапа Дополнительные данные, подтверждающие влияние NUMA на разные виды нагрузок.
Этап 5: Анализ и отчёт (30–60 мин)
Действия
-
Соберите все данные из логов в таблицу (например, в CSV):
-
Постройте график (используя matplotlib или gnuplot): latency vs размер, две кривые (local, remote). Убедитесь, что на размере > 64M (DRAM) разница ≥ 2x.
-
Оцените impact на реальные приложения: если приложение обращается к большому объему данных и неправильно привязано к NUMA, latency может ухудшиться в разы. Напишите краткие рекомендации:
-
Оформление отчёта:
report_numa_latency.md.
Ожидаемый результат этапа Готовый отчёт с таблицами, графиком, выводами и рекомендациями.
5. Критерии приемки (Definition of Done)
- Выполнен сбор информации о NUMA-топологии (numactl --hardware).
- Замерена латентность на локальном доступе для набора размеров от 1K до 128M.
- Замерена латентность на удалённом доступе (cross-node) для тех же размеров.
- Коэффициент удалённой задержки (remote / local) при размере > 64M не менее 2.0.
- Построен график зависимости latency от размера рабочего набора с двумя кривыми.
- Проведён хотя бы один дополнительный тест (multithreaded latency, bandwidth).
- Подготовлен markdown-отчёт с таблицей, графиком и рекомендациями.
- Все команды привязки выполняются через numactl (не через taskset без memory binding).
- Исключены известные артефакты (освобождение кэша, разогрев, достаточное количество итераций).
6. Ожидаемый результат
| Файл | Содержание |
|---|---|
report_numa_latency.md | Отчёт: топология, методология, таблица замеров, график (base64 embedded PNG или ссылка), выводы, рекомендации |
local_results.txt | Сырые данные локальных замеров |
remote_results.txt | Сырые данные удалённых замеров |
(опционально) scatter.png / latency_plot.png | График в png |
(опционально) additional_experiments.log | Логи запуска stress-ng, mbw |
7. Возможные сложности и их решение
| Сложность | Решение |
|---|---|
В системе всего один NUMA-узел (онли node 0) | Задание невыполнимо; в отчёте указать «single-socket, NUMA отсутствует, тест не имеет смысла». Можно использовать QEMU VM с эмуляцией. |
отсутствует lmbench (или lat_mem_rd) | Использовать stress-ng --memrate + perf или написать простой враппер на C (см. листинг ниже). |
| Высокие фоновые нагрузки | Запускать тесты на изолированных ядрах (isolcpus в ядре) или с nice -n -20. |
| Первые замеры показывают аномально высокую латность | Убедиться, что кэш очищен: выполнить drop_caches перед каждым замером (echo 3 > /proc/sys/vm/drop_caches). |
Показания lat_mem_rd колеблются | Увеличить количество повторений (-N 200), проверить отсутствие троттлинга по питанию. |
Пример простого C-бенчмарка для замера латентности чтения (для справки):
#include <numa.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define SIZE (128 * 1024 * 1024) // 128 MB
#define STRIDE 64 // bytes
#define ITERATIONS 100
int main() {
char *buf = (char *)numa_alloc_local(SIZE);
for (int i = 0; i < SIZE; i += 64) buf[i] = 0;
struct timespec t1, t2;
clock_gettime(CLOCK_MONOTONIC, &t1);
for (int k = 0; k < ITERATIONS; k++) {
volatile char tmp;
for (int i = 0; i < SIZE; i += STRIDE) {
tmp = buf[i];
}
}
clock_gettime(CLOCK_MONOTONIC, &t2);
double ns = (t2.tv_sec - t1.tv_sec) * 1e9 + (t2.tv_nsec - t1.tv_nsec);
printf("Latency: %.2f ns per access\n", ns / (ITERATIONS * (SIZE/STRIDE)));
numa_free(buf, SIZE);
return 0;
}
8. Бюджет времени (оценка)
| Этап | Время |
|---|---|
| Этап 1. Изучение топологии и установка инструментов | 20–30 мин |
| Этап 2. Локальные замеры latency | 30–40 мин |
| Этап 3. Удалённые замеры latency | 30–40 мин |
| Этап 4. Дополнительные эксперименты | 1–1.5 ч |
| Этап 5. Анализ и отчёт | 30–60 мин |
| Итого | 3–4 ч |
Примечание: при первом знакомстве с NUMA и инструментами может потребоваться 5–6 часов.
9. Связанные вопросы из базы знаний
| Вопрос | Тема |
|---|---|
| 45 | NUMA архитектура и топология |
| 67 | Латентность оперативной памяти и кэша |
| 89 | Профилирование доступа к памяти (perf, likwid) |
| 112 | Использование numactl для управления привязкой |
| 234 | Особенности AMD EPYC (CCX, multiple dies) |
| 345 | Латентность vs пропускная способность (bandwidth) |
| 456 | Методы микробенчмаркинга (reproducibility) |
| 567 | Анализ LLC misses и удалённых обращений |
| 678 | Влияние кэш-памяти на производительность |
| 789 | TMA (Top-down Microarchitecture Analysis) |
| 890 | Измерение времени с помощью RDTSC |
10. Чек-лист самопроверки
- Я проверил(а) NUMA-топологию командами numactl --hardware и lscpu | grep -i numa.
- Я убедился(ась), что замеры локального доступа выполняются с привязкой и процесса, и памяти к одному узлу.
- Я зафиксировал(а) размер рабочего набора, превышающий кэш последнего уровня (L3) для достижения DRAM latency.
- Я выполнил(а) как минимум два полных запуска на разных узлах (node0→node1 и node1→node0).
- Я построил(а) график и проверил(а), что значения remote/local ratio для последнего размера ≥ 2.0.
- Я написал(а) отчёт с интерпретацией результатов и практическими рекомендациями для настройки приложений в NUMA-среде.