Об атомных ядрах и их эффективности

По непонятной мне причине, время пересборки FreeBSD на моем текущем "боевом NAS" было измерено неверно отчего  я написал "время пересборки FreeBSD на новом процессоре больше раза в полтора, чем на старом" (возможно, я сгоряча собирал не ту версию на старой машине, у меня там много src.Minor.Major свалено на диске), после переизмерений получилось вот что (повторено несколько раз, результаты устойчивые).

Методика измерения:

  • выкачиваем FreeBSD 11-stable (ревизия одинаковая, убедился)
  • Чистим /usr/obj (необязательно, как показали повторные измерения)
  • make -j N buildworld, где N=5 для "виртуально-4ядерного" i3-6300T ну и соответственно =10 для реально-8ядерного Атома.
  • Диски: в обоих системах все лежит на старых SSD (в i3 - диск поновее/побыстрее, но я не думаю что есть видимая глазом разница).
  • Обе системы ничем не загружены, все прогонялось ночью, сервера эти были полностью idle.

Старая система:

CPU: Intel(R) Core(TM) i3-6300T CPU @ 3.30GHz (3312.15-MHz K8-class CPU)
FreeBSD/SMP: 1 package(s) x 2 core(s) x 2 hardware threads
real memory  = 34359738368 (32768 MB)
ada0: <OCZ-VERTEX3 MI 2.15> ATA8-ACS SATA 3.x device
$ time make -j5 buildworld
...
World build completed on Tue Nov 20 00:14:39 MSK 2018
--------------------------------------------------------------
real    89m19,839s
user    333m34,812s
sys     14m28,787s

Новый ящик:

CPU: Intel(R) Atom(TM) CPU C3758 @ 2.20GHz (2200.08-MHz K8-class CPU)
FreeBSD/SMP: 1 package(s) x 8 core(s)
real memory  = 17179869184 (16384 MB)
ada0: <OCZ-VERTEX2 3.5 1.35> ATA8-ACS SATA 2.x device
$ time make -j10 buildworld
World build completed on Wed Nov 14 10:08:19 UTC 2018
--------------------------------------------------------------
real    89m6.999s
user    628m14.852s
sys     29m52.185s

Итого, каждое ядро у этого Атома медленнее примерно вдвое чем "виртуальное-гипертрединговое" ядро у i3-6300T, а в сумме получается один хрен.

Совпадение, конечно, выглядит поразительно: такое все разное, а все едино 89 минут на все. Но перепроверил еще раз - и опять совпало в пределах нескольких процентов (ну 87 минут получилось на Атоме и 88 на i3).

Память на двух системах одинаковая (DDR4-2400/ECC unbuffered), на старой системе ее установлено вдвое больше, но на ней боевой ARC на 21G, поэтому на атоме доступной памяти реально даже и побольше (реально для перекомпиляции в 10 потоков - памяти нужно 5-6G и в обоих системах "свободной памяти достаточно")

Энергопотребление:

Атом в idle жрет 8-9 ватт и практически все приходится на Uncore, в котором у него все: SATA, 10G Ethernet, USB, поэтому сравнивать полное энергопотребление некорректно. Поэтому смотрю только на x86 cores по powermon:

  • Atom: ~6W в момент компиляции (полное потребление 14-15W)
  • i3-6300T: 22-24W (полное потребление 23-25W, Uncore жрет в пределах ватта, чуть меньше)

Получается, что Атом в смысле энергоэффективности - в 2-4 раза лучше (Uncore разложить так, чтобы вычесть "южный мост" не выйдет, поэтому сравниваем или полное энергопотребление или только cores). Ну и хорошо раз так.

P.S. Новый ящик пока подключен по гигабиту и померять скорость ssh/AES между двумя компьютерами не могу.

Comments

По идее ARС тоже должен влиять, и скорее в лучшую сторону (все includes с первого вызова компилятора оказываются там)

Исходники лежат на UFS, obj - тоже.

А includes будут в vnode cache, ну если не с первого раза, так со второго

Интересно было бы увидеть результат на Атоме с -j5. Может там упирается не в ядра?

Этот ящик пустой-ненагруженный, пусть поработает.

Запустил, часа через два будет результат, напишу.

Пока вижу на ~1.5 ватта меньшее потребление.
Гипотеза: user будет такой же примерно, ну а wall - понятно что побольше.

$ time make -j5 buildworld
World build completed on Tue Nov 20 09:45:18 MSK 2018
--------------------------------------------------------------

real    134m7.049s
user    621m27.899s
sys     29m30.579s

134/89 = 1.5

8/5 = 1.6

Короче, если и не ядрами ограничено, то близко к этому.

Я так понимаю надо делать amalgamation там, где конструкция позволяет (тупо united.c с инклюдами всех файлов в каталоге) -- всякие браузеры так собираются, и дает оно 20-30% времени сборки)

PS я думал у вас / тоже на zfs. (у меня тут вопрос есть, на #zfsonlinux я с ним уже ходил и тут спрошу, если позволите)

Не, RootOnZFS я делал (давно), а потом проапгрейдил пул, но не загрузчик. Было весело.

Не вижу смысла в / на ZFS в моей конкретной ситуации (даже если кончатся SATA-слоты - перееду с /, /usr, /var на флешку)

То есть вот в той машине, где был root on zfs, я после того случая (там SATA-портов не было избытка, все было занято) именно на USB-флешку и переехал.

А вопрос - конечно давайте.

Собственно есть у меня каталог на zfs dataset -- в нем примерно 5 миллионов файлов с именами в виде хешей (такой дедупликатор для бедных) -- мы по нему идем, и вычищаем файлы у которых st.nlinks == 1, занимает это часы, а не минуты -- я пошел смотреть strace и разбираться как умею.

strace понятно частичный, от двухминутного пробега
Partial `strace -w -c` for process which do readdir/lstat/unlink loop on 5M files in one dir
file names is a base58(sha256(file_content)).

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 66,36   65,516804     1559923        42           getdents
 22,83   22,535192        1178     19118           lstat
 10,80   10,658754       18440       578           unlink
  0,01    0,012003          20       578           write
------ ----------- ----------- --------- --------- ----------------
100.00 98,722753 20316 total

Просто getdents на том же каталоге отрабатывает за 4 минуты (${coreutils}/bin/ls -f /nix/store/.links >/dev/nill).

Потом я запустил очистку повторно, и увидел следующее: (опять же двухминутная выдержка пока оно по "чистому" колупалось)
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 99,84  115,540901        6728     17172           lstat
  0,16    0,187311        5062        37           getdents
------ ----------- ----------- --------- --------- ----------------
100.00 115,728212 17209 total

Собственно вопрос -- что вызывает такое патологическое поведение, и как лечить.
Сам код -- здесь, https://github.com/NixOS/nix/blob/master/src/libstore/gc.cc#L693

У меня скромные идеи запилить fstatat/unlinkat (и то я не уверен, а можно ли unlinkat(dirfd(dir), file) внутри цикла с readdir, и не сломается ли от этого OSX -- там это тоже используют)

Может ли помочь leveling (или как это правильно называется -- когда "abcde..." разносится по каталогам как a/bc/de...")? Могут ли влиять имена файлов (хеши -- там base58(sha256(content))) -- все имена начинаются с "0" или "1" -- может ли это какой-то corner case триггерить? (или я уже на воду дую)

Хочется идей и советов, потому что свои идеи кончились.

Разнесение по каталогам уж точно попробовать несложно.

Про остальное готового мнения не имею.

Ну относительно несложно.
Надо только про upgrade path подумать, если я хочу это в апстрим продвигать.

Ну я про "попробовать".

На снапшоте если только.
У меня только одна система с zfs. Хотя от разнесения и другим fs должно полегчать, и выбирать имена для "этажей" лучше с конца хеша, там "разброс" больше. А любой файл, который не на нужном уровне, передвигать на нужный (вот кстати и upgrade/downgrade path)

Кстати интересно, при наличии снапшота будет такой же эффект, или это только unlink "навсегда" приводит к таким веселым эффектам.

Ну я вот боюсь, что
а) или lstat выполняется за линейное время от размера каталога
б) или unlink приводит к тому, что там что-то схлопывается-пересчитывается

Короче, 5млн файлов - это плохо.

Опять же, ну можно же сделать песочницу с 1,10,100,1000,10000 файлов и смотреть насколько быстро ситуация ухудшается.

Что-то не могу с одного раза ответить на комментарий, надо завтракать!

Да, конечно united.c (std_pch.cpp) и precompiled headers сильно помогают жизни, хотя я никогда не мерял - насколько именно.

Вообще, поскольку сборка FreeBSD, ну так если поглядывать туда, это процентов на 90 (утрирую) сборка llvm/clang, то может быть там так и сделано, хрен их знает, не вдавался.

Мне казалось, что все эти атомы — наследники P5, минуя и NetBurst и P6. А Core — налсденики P6.

Не, Атом - маркетинговое слово теперь.

Потому что есть атомы для ноутбуков, атомы для серверов и атомы для iot.

Вот атом на 2wt: https://ark.intel.com/ru/products/97133/Intel-Atom-x3-C3265RK-Processor-...
А вот на 25: https://ark.intel.com/ru/products/97940/Intel-Atom-Processor-C3950-16M-C...

Ну и вот тот, что на 25 — Denverton — это архитектура Goldmont — (а это так же и ядра Apollo Lake, если не для серверов) — и это наследник Airmont, который отличался от Silvermont только GPU, который наследник Bonnel'а, в общем, там чётка линия прослеживается и только Bonnel был новым, а это было в 2008 году (и только про него что-то известно). И глядя на схему Bonnel'а я вижу очень простой конвейр и всего лишь 2x суперскалярность. Ну да, похож на P5, только FPU отдельно, а интеджер-часть — очень похожа.

У того что 2wt — ядра Silvermont, формально старее на два поколения (а реально на одно, Airmont который был между ними имел ту же микроахитектуру), но архитектурно те же. Обвязка совсем другая, а ядра на архитектуре Silvermont.

Так что по вычилительной мощности их корректно сравнивать.

Очень Intel всё запутал. Есть отдельно архитектура (один codename), отдельно ядро на этой архитектуре (другой codename) и отдельно название конкретного процессора с такими ядрами и какой-то обвязкой, зависящей от назначения.

Но в любом случае у Atom'ов не core-ядра.

Т.е. линейка такая:

Bonnel — новая, с нуля, архитектура, 2008 год, подозрительно похожа на P5 + FPU, 2xINT ALU + 2xFPU ALU (и они не равноправны а специализирвоаны, так что чистой 4x суперскалярности не получить и даже 2x не получить). Платформы/ядра назывались Diamondville/Silverthorne/Lincroft. Чипы — старые Z/N атомы с трёхзначными нормерами.

Saltwell — шринкнули Bonnel и добавили перефирию на тот же die. Архитектура не поменялась. Платформы/ядра Penwell/Cedarview/Cloverview/Centerton/Briarwood/Berryville, чипов я не нашёл.

Silvermont — что-то подточили в Saltwell, уменьшили конверй на 2 стадии, ALU столько же. Это, в частности, платформа SoFIA, чипы — x3-C3xxx. [Вот тут твой 2wt.]

Airmont — чистый шринк Slivermont, Braswell/Cherry Trail, Atom x5-E8xxxx, x5-Z8xxxx, x7-Z8xxx, Pentium/Celeron N31xx/J31xxx.

Goldmont — добавили третий декодер (3 issue), подточили latency частых инструкций, шринк. Apollo Lake/Denverton, Atom C3xxx [вот тут твой 25wt] и попроще Celeron/Pentium N/J33xx, N/J34xx и N/J42xx. И это 2016 год.

Уф. Вот такое наследие. Как видно, все Atom'ы на уровне ядра — одна и та же линейка, а вот сколько ядер шлёрнуть и чем обвязать — очень сильно отличается.

А уже есть Goldmont Plus, но там только Celeron/Pentium.

Слушай, ну вот вся эта генеалогия - она не кажется маленько того, притянутой за уши?
Ну вот к примеру AES-NI (как пример)- думаешь заново изобретали в параллельной линейке, или взяли таки готовое?

Я абсолютно уверен, что там у них есть кросс-опыление и как тогда считать, от какого папы больше транзисторов что ли?

Нет, не кажется. Потому что определяющим является не AES-NI а архитектура конвейра и количество и возможности ALU.

Наверняка AES-NI они ляпнули внутрь FPU прямо IP-блоком от Core. Я уверен, что это такой кубик Lego, и он во всех процессорах один. Но он — не важен. Важна вот эта схема:

https://en.wikichip.org/w/images/thumb/b/ba/bonnell_block_diagram.svg/10...

И только по архитектуре и количеству ALU чистый IPC будет меньше чем у любого самого захудалого «честного» Core-i3/5/7.

И это я не вспомнил про размер кэшей, про меньший размер регистрового файла, про менее эффективный бранч-предиктор…

И, как выясняется, Atom — не такое и маркетинговое слово. Вот Pentium и Celeron — да, полный бардак, там есть и Atom'ные ядра и Core'вые. В зависимости от модели. А с Atom всё консистентно.

Ну да, так как-то и выходит, 2 ядра (*HT) * 3.3GHz равны (ну прям очень точно) этим восьми ядрам на 2.2

Что меня, в общем, должно устраивать везде, кроме (возможно) AES-NI, но это место я еще пощупаю на днях.

И всё-таки, чтобы сравнивать именно корость CPU, надо выносить на RAM-диск и obj, и TMPDIR, потому как параллельный make очень сильно насилует TMPDIR (если пустая, то /tmp) - это хорошо видно в gstat, если положить TMPDIR на совсем отдельный md-диск. Потому как существенно ненулевой system time это в том числе disk i/o.

"существенно ненулевой" - это 5% от user.

Эта точность меня устраивает :)

Ну и если видели предыдущий комментарий (в другом треде): от переноса всего с USB-флешки (теоретически - медленной) на SSD/SATA - ничего не изменилось.

Я делаю вывод, что IO не так и важен.

(но, конечно, когда в новом ящике будет вся запланированная память, а именно 32G, сделаю и на md, чисто из интересу).

Впрочем, текущий боевой ящик (i3) все едино перегружать скоро, экономить L2ARC смысла нет.
Уменьшил там ARC, перебутился, вот компилирую на md (сделал два отдельных, один под TMPDIR, один под obj) - часа через полтора будет результат.

Пока (но только началось) активного IO на TMPDIR не вижу, если честно.

Возможно, мои данные и устарели - когда я мерял, в качестве make у нас использовался fmake, а нынче bmake.

Я думаю что разница не в make, а в media. Между SSD и ramdrive значимой разницы я не вижу:  https://blog.lexa.ru/2018/11/21/o_sravnenii_processorov_metodom_perekompilyacii_freebsd.html

Вот что кажет iostat на двух md-шках (tmp, obj):

                        extended device statistics
device       r/s     w/s     kr/s     kw/s  ms/r  ms/w  ms/o  ms/t qlen  %b
md0            0      80      0.0      0.0     0     0     0     0    0   0
md1            0      83      0.0      0.0     0     0     0     0    0   0

(это чуть заниженные цифры т.к. я не сразу запустил make, можно процентов 5 добавить)

Для md и для SSD - это смешные iopsы, а вот на железномагнитных дисках - разница с md может быть большой

(почему-то ни iostat, ни gstat ничего не показывают в колонке read, возможно все что на md - автоматически оказывается в кэше)