Pull to refresh
3
0
Send message
Относительно неточных вычислений, можно прочитать в «Intel® 64 and IA-32 Architectures Software Developer’s Manual», том 1, раздел 8.3.10, «Transcendental Instruction Accuracy»:

The accuracy of these instructions is measured in terms of units in the last place (ulp).

With the Pentium processor and later IA-32 processors, the worst case error on transcendental functions is less
than 1 ulp when rounding to the nearest (even) and less than 1.5 ulps when rounding in other modes.


Если это интерпретировать, получается, что младший бит в половине случаев будет неправильным. Чтобы он был правильным, необходима точность 0.5 ulp или лучше.
Согласен, Intel публикует некоторые микроархитектурные данные. Только приведённая Вами таблица ничего не говорит об исполнительных устройствах. Она говорит, на какие порты scheduler может отправить микрооперацию конкретной группы. То есть, если x87 и AVX FP обрабатываются портом 0, это не значит, что за это отвечает одна и та же логика.

И если посмотреть на что-нибудь свежее, типа Skylake (схема 2-1 приведённого Вами документа), то там вообще не говорится про x87 и MMX. Что может говорить о том, что обработка этих инструкций вытащена из общего пайплайна и лежит где-то сбоку. Это, как вы понимаете, не способствует производительности этих инструкций.
Эммм…
А что вы предлагаете использовать вместо float?
Не может публично доступная документация Intel говорить о том, что SSE и x87 реализованы на одном и том же исполнительном устройстве. Это детали реализации, которые не раскрывает ни один разработчик CPU. Архитектурная документация описывает только то, каким будет результат вычислений, а не то, как он будет достигнут в железе.
Насколько я помню, SSE — это не только про SIMD, там есть и скалярные операции. Поэтому, собственно, нормальные компиляторы и не генерируют кода с инструкциями x87, если без этого можно обойтись.
Что касается управления точностью: если особая точность не нужна, можно вообще включить режим denormal flush to zero. Работает в этом режим обычно пошустрее. Ну и в 32-битном ARM единственная возможность использовать векторизацию — это использовать single precision арифметику и denormal flush to zero.
В Intel 80-битная арифметика — это legacy 1980 года издания. Если процессор поддерживает наборы инструкций SSE и SSE2 (вообще все процессоры Intel начиная с Pentium 4), single и double precision floating point там считается гораздо быстрее, чем в формате 80bit x87. И расчёты в SSE/SSE2 происходят именно в 32-битном и 64-битном форматах. Почитайте что ли архитектурную документацию на досуге.
Инструкции из набора x87 это legacy, в процессорах эти инструкции работают весьма медленно. И если нет требований именно к точности вычислений, лучше про них вообще забыть. Но выполнять точные вычисления на x87 это так себе занятие. В документации описаны ситуации, когда младший бит мантиссы результата принимает непредсказуемое значение. К сожалению, прямо сейчас я не смогу предоставить ссылку на конкретный раздел документации, но если интересно, завтра могу уточнить.
Кстати, интересен вопрос: а как Microsoft в своём трансляторе обеспечит total store ordering для кода x86, если в ARM вполне себе relaxed memory ordering? Если обкладывать все записи в память барьерами, это будет работать дико медленно. А если не обкладывать, то можно забыть об исполнении на нескольких ядрах.
Ну про транслятор от Apple не знаю, не пробовал. Но PowerPC попроще x86, RISC всё-таки.
А в x86 просто дофига legacy, взять хотя бы parity flag, которого в ARM нет, считать его в софте очень тяжело, а софт на него иногда закладывается.
Я вас умоляю, по этой документации такой транслятор не сделать: слишком много там неочевидного или откровенно плохо документированного.
Интел не судится с разработчиками QEMU в основном потому, что у них денег нет, с них взять нечего. К тому же, в QEMU ещё не реализовали ни одной архитектуры нормально. Поддержка допиливается до состояния «чтобы Линукс запустился». А чуть в сторону — и не работает. До ошибок в арифметике доходит.
Что касается мелкомягкой реализации бинарной трансляции из x86 в ARM, я бы с интересом на неё посмотрел, но что-то мне подсказывает, что там тоже точность ±поллаптя, то есть аппликухи вроде бы работают, но софт для расчёта зарплаты пускать стрёмно.
Увы, это не так работает. Если вы хотите сделать в кремнии свою реализацию, скажем, процессора архитектуры ARM, вам придётся купить лицензию на архитектуру. В частности, чтобы иметь возможность продавать свои процессоры, Apple, Qualcomm и nVidia заплатили за архитектурную лицензию, и это не то же самое, что приобрести Soft или Hard IP какого-нибудь условного Cortex-A57. Аналогичный пример: для того, чтобы в МЦСТ можно было разрабатывать процессоры Spark, у Sun была куплена лицензия.
Ну, MIPS — вообще интересная архитектура. Там аппаратный Translation Table Walk является сильно опциональным с точки зрения архитектуры, если я не ошибаюсь.
В ARM64 с размерами страниц ситуация следующая: все размеры страниц зависят от базовой гранулярности, которая может быть 4k, 16k и 64k (конфигурируется). При гранулярности 4k размеры страниц 4k, 2M, 1G. При 16k — 16k, 32M. При 64k — 64k, 512M. Также существует Contiguous hint, позволяющий объединять несколько страниц в одну запись в TLB. Для 4k объединяется 16 страниц, для 64k — 32 страницы, а для 16k — 32 страницы 32M или 128 страниц 16k.

По поводу решения с тегами, я ведь не против, если кто-то сделает это в железе. Только пока такое железо если и есть, его не достать. Поэтому пока используем то, что есть.

Что касается non-shareable данных в ARM, проще, наверное процитировать документацию (ARM® Architecture Reference Manual. ARMv8, for ARMv8-A architecture profile. Ревизия B.a, страница B2-109)
For Normal memory locations, the Non-shareable attribute identifies Normal memory that is likely to be accessed only by a single PE.

A location in Normal memory with the Non-shareable attribute does not require the hardware to make data accesses by different observers coherent, unless the memory is Non-cacheable. For a Non-shareable location, if other observers share the memory system, software must use cache maintenance instructions, if the presence of caches might lead to coherency issues when communicating between the observers. This cache maintenance requirement is in addition to the barrier operations that are required to ensure memory ordering.

Как видно из процитированного, если софт (операционка, приложение) собирается использовать non-shareable данные с разных ядер, нужно самостоятельно выполнять Cache Maintenance. Это же нужно делать, если поток мигрирует на другое ядро. В случае же, если исполнение потока прерывается, а через какое-то время продолжается на том же процессорном ядре, никаких дополнительных телодвижений не требуется.
Собственно, Global Foundries и была создана путём выделения фабрик AMD в отдельную компанию. Поэтому AMD на Global Foundries и пекут свои чипы.
Страниц и так будет много — по одной на каждые 4k виртуального адресного пространства. Никаких особых проблем с поддержанием второй кучи я не вижу.

Что касается совмещения local и shared данных в одном объекте, пример какой-то искусственный. не очень понимаю сферу применения. Размер в 64 байта опять же с потолка взят — никто не гарантирует, что cacheline будет именно такого размера. Это implementation defined, от конкретной модели процессора зависит.

По поводу MIPS64 — не знаком с этой архитектурой, поэтому не готов комментировать отличий от ARM64. Что же касается причин разработки ARM64, тут, как мне кажется, всё довольно прямолинейно: ARM Limited хочет продать больше процессоров (на самом деле IP, но не суть), поэтому вынуждена разрабатывать что-то новое постоянно, иначе покупать перестанут.
TLB и так хранит отдельную запись для каждой виртуальной страницы, к которой осуществляется доступ.

Про второй аллокатор и совмещение в одном объекте когерентных и некогерентных данных, не понимаю, что вы имеете в виду.

У варианта с атрибутом в таблице страниц есть одно неоспоримое преимущество: он уже реализован в железе, причём не на экзотических архитектурах, а на вполне мэйнстримном ARM. Решение, работающее здесь и сейчас, на мой взгляд, гораздо лучше решения, которое ещё нужно сделать, причём не очень понятно, какие ресурсы для этого потребуются, и какой профит оно принесёт.
При подаче флага MAP_ANONYMOUS никакой файл в память не отображается — отображается только физическая память в виртуальное адресное пространство. А про загаживание TLB не очень понимаю, что вы хотите этим сказать. В TLB и так хранятся атрибуты памяти: Memory Type, Cacheability и Shareability.
Что касается того, с какими опциями выделяется память под стек — не знаю наверняка. Я просто предположил, что нет смысла делать её разделяемой, к ней всё равно только один поток обращаться будет.

По крайней мере в *nix, память выделяется с помощью системного вызова mmap (http://man7.org/linux/man-pages/man2/mmap.2.html). Этот системный вызов принимает в том числе флаги, например MAP_SHARED или MAP_PRIVATE. Таким образом, операционка узнаёт, нужна потоку разделяемая память, или локальная. malloc — это библиотечная функция, которая вызывает mmap с какими-то дефолтными параметрами. Соответственно, если прикладного программиста не устраивают дефолты, с которыми вызывается mmap внутри malloc, он волен вызвать mmap самостоятельно. Также при вызове mmap нужно отдельно запрашивать выделение памяти большими страницами — для этого есть флаг MAP_HUGETLB.

Поэтому не вижу особых преимуществ тегов перед Shareability-атрибутом в таблице страниц. Для обоих механизмов нужна поддержка как операционки, так и приложения. При этом накладные расходы на хранение тегов гораздо больше, чем для атрибутов страницы. Собственно, может быть, хранить тег для каждого cacheline и удобно для прикладного программиста, но очень уж дорого. Да и размер cacheline вы в общем случае не знаете.

Information

Rating
Does not participate
Registered
Activity