Подтвердить что ты не робот

Выровнены и неравнозначные обращения к памяти?

В чем разница между выровненным и неприглаженным доступом к памяти?

Я работаю над DSP TMS320C64x, и я хочу использовать встроенные функции (функции C для инструкций сборки), и он имеет

ushort & _amem2(void *ptr);
ushort & _mem2(void *ptr);

где _amem2 выполняет выравниваемый доступ из 2 байтов, а _mem2 выполняет неравномерный доступ.

Когда мне следует использовать какой?

4b9b3361

Ответ 1

Выравниваемый доступ к памяти означает, что указатель (как целое число) является кратным значению типа, называемому выравниванием. Выравнивание - это естественный адрес, который должен быть указан или должен быть сохранен (например, по соображениям производительности) на процессоре. Например, для ЦП может потребоваться, чтобы все двухбайтовые нагрузки или хранилища выполнялись по адресам, кратным двум. Для небольших примитивных типов (до 4 байтов) выравнивание почти всегда является размером этого типа. Для структур, выравнивание обычно является максимальным выравниванием любого члена.

Компилятор C всегда ставит переменные, которые вы объявляете по адресам, которые удовлетворяют "правильному" выравниванию. Поэтому, если ptr указывает, например, переменная uint16_t, она будет выровнена, и вы можете использовать _amem2. Вам нужно использовать _mem2 только в том случае, если вы получаете доступ, например. массив упакованных байтов, полученный через I/O, или байты в середине строки.

Ответ 2

Многие компьютерные архитектуры хранят память в словах по нескольким байтам. Например, 32-разрядная архитектура Intel хранит слова 32 бита, каждый из 4 байтов. Однако память адресуется на уровне одного байта; поэтому адрес может быть "выровнен", что означает, что он начинается с границы слова или "не выравнивается", то есть это не так.

В некоторых архитектурах некоторые операции с памятью могут быть медленнее или даже полностью не разрешены на невысоких адресах.

Итак, если вы знаете, что ваши адреса выровнены по правому адресу, вы можете использовать _amem2() для скорости. В противном случае вы должны использовать _mem2().

Ответ 3

_mem2 является более общим. Он будет работать, если ptr выровнен или нет. _amem2 более строгий: он требует, чтобы ptr был выровнен (хотя, по-видимому, немного более эффективен). Поэтому используйте _mem2, если вы не можете гарантировать, что ptr всегда выровнен.

Ответ 4

У многих процессоров есть ограничения на выравнивание доступа к памяти. Невыраженный доступ генерирует прерывание исключения (например, ARM) или просто медленнее (например, x86).

_mem2, вероятно, реализован как выборка двух байтов и использование сдвиговых и побитовых операций, чтобы сделать из них 16-битное ushort.

_amem2, вероятно, просто читает 16-битовое ushort из указанного ptr.

Я не знаю TMS320C64x специально, но я предполагаю, что для 16-битного доступа к памяти требуется 16-битное выравнивание. Таким образом, вы можете использовать _mem2 всегда, но с ограничением производительности, и _amem2, когда вы можете гарантировать, что ptr является четным адресом.

Ответ 5

Согласованные адреса - это те, которые являются кратными размеру доступа.

  • Доступ к 4-байтным словам по адресам, кратным 4, будет выровнен.
  • Доступ 4 байта от адреса (скажем) 3 будет неравномерным доступом

Очень вероятно, что функция _mem2, которая будет работать и для неравномерного доступа, будет менее оптимальной, чтобы получить правильные выравнивания, работающие в коде. Это означает, что функция _mem2 скорее всего будет более дорогой, чем ее версия _amem2.

Итак, когда вам нужна производительность (особенно когда вы знаете, что задержка доступа высока), было бы разумно определить, когда вы можете использовать выровненный доступ. Для этой цели существует _amem2 - чтобы дать вам производительность, когда вы знаете, что доступ выровнен.

Когда дело доходит до двухбайтовых доступов, идентификация выровненных операций очень проста.
Если все адреса доступа для операции "четные" (то есть их младший бит равен нулю), у вас есть 2-байтовое выравнивание. Это можно легко проверить с помощью

if (address & 1) // is true
    /* we have an odd address; not aligned */
else
    /* we have an even address; its aligned to 2-bytes */

Ответ 6

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

Будь то драма или проклятие или флеш или другое. Возьмите sram как простой пример, он построен из битов, а конкретный sram будет построен из фиксированного количества бит в ширину и фиксированного количества строк в глубину. скажем, 32 бит в ширину и несколько/много строк в глубину.

если я делаю 32-разрядную запись в адрес 0x0000 в этом sram, контроллер памяти вокруг этого sram может просто сделать один цикл записи для строки 0.

если я делаю 32-разрядную запись в адрес 0x0001 в этом sram, предполагая, что это разрешено, контроллеру необходимо будет прочитать строку 0, изменить три байта, сохранить их и записать, что для строки 0, затем прочитайте строку 1, измените один байт, оставив остальные три, как указано, и запишите это обратно. какие байты модифицируются или не имеют отношения к контенту для системы.

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

Если бы я должен был читать 32 бита с адреса 0x0000, то выполнялось одно чтение строки 0. Но прочитайте от 0x0001, и мне нужно сделать два чтения row0 и row1, и в зависимости от дизайна системы просто отправьте эти 64 бита обратно на процессор, возможно, два шинных такта вместо одного. или контроллер памяти имеет дополнительную логику, так что 32 бита выровнены по шине данных в одном цикле шины.

16-битные чтения немного лучше, чтение с 0x0000, 0x0001 и 0x0002 будет считаться только чтением из строки0 и может на основе архитектуры системы/процессора отправить эти 32 бита назад, а процессор извлекает их или переносит в контроллер памяти, чтобы они приземлялись на определенные полосы байтов, поэтому процессору не нужно вращаться. Один или другой должен, если не тот и другой. Чтение из 0x0003, хотя и похоже на выше, вам нужно прочитать строки 0 и строку1, так как один из ваших байтов находится в каждом, а затем либо отправляет 64 бита назад для извлеченного процессора, либо контроллер памяти объединяет биты в один 32-битный ответ шины ( предполагая, что шина между процессором и контроллером памяти имеет 32 бита для этих примеров).

16-разрядная запись, хотя всегда заканчивается как минимум одним read-modify-write в этом примере sram, адрес 0x0000, 0x0001 и 0x0002 read row0 модифицирует два байта и записывает их обратно. адрес 0x0003 читает две строки, каждый раз меняет один байт и записывает обратно.

8 бит вам нужно только прочитать одну строку, содержащую этот байт, пишет, хотя это чтение-изменение-запись одной строки.

Armv4 не понравился без выровненности, хотя вы могли бы отключить ловушку, и результат не похож на то, что вы ожидали бы выше, а не важно, текущие руки позволяют выровнять и дать вам описанное выше поведение, которое вы можете немного изменить в регистре управления, а затем будет отменять неизмененные переводы. мифы, которые раньше не позволяли, не уверены, что они делают сейчас. x86, 68K и т.д., и контроллеру памяти, возможно, пришлось больше всего работать.

Проекты, которые не позволяют это ясно, для производительности и меньшей логики в том, что некоторые скажут, это бремя для программистов, которые другие могут сказать, что это не лишняя работа над программистом или проще программиста. вы можете также понять, почему лучше не пытаться сохранять память, делая 8-битные переменные, но продолжайте и записывайте 32-битное слово или независимо от того, какой размер регистра или шины есть. Это может помочь вашей производительности при небольшой стоимости нескольких байтов. Не говоря уже о дополнительном коде, который компилятор должен был бы добавить, чтобы позволить сказать, что 32-битный регистр имитирует 8-битную переменную, маскируя и иногда подписывая расширение. В тех случаях, когда используются собственные размеры регистра, эти дополнительные инструкции не требуются. Вы также можете упаковать несколько вещей в место на шине/в памяти и сделать один цикл памяти для их сбора или записи, а затем использовать некоторые дополнительные инструкции для манипулирования между регистрами, не обходимыми с помощью ram, и возможной стиранием количества инструкций.

Я не согласен с тем, что компилятор всегда будет выравнивать данные для цели целиком, есть способы разбить это. И если цель не поддерживает unaligned, вы попадете в неисправность. Программистам никогда не нужно было говорить об этом, если бы компилятор всегда делал это правильно, основываясь на любом юридическом коде, который вы могли бы придумать, не было бы причин для этого вопроса, если бы это не было для производительности. если вы не контролируете адрес void ptr, который должен быть выровнен или нет, тогда вы должны использовать unlanged-доступ mem2() все время или вам нужно сделать if-then-else в вашем коде на основе значения ptr как nik указал. объявив как void, компилятор C теперь не имеет возможности правильно справиться с вашим выравниванием, и он не будет гарантирован. если вы берете char * prt и подаете его на эти функции, все ставки отключены на компиляторе, если вы добавите лишний код, который похож на функцию mem2() или вне этих двух функций. так как написанный в вашем вопросе mem2() является единственным правильным ответом.

DRAM говорит, что используемый на вашем рабочем столе/ноутбуке имеет ширину 64 или 72 (с ecc), и каждый доступ к ним выравнивается. Несмотря на то, что карты памяти фактически состоят из 8-битных или 16 или 32-битных чипов. (это может меняться с помощью телефонов/планшетов по разным причинам) контроллер памяти, и в идеале по крайней мере один кэш находится перед этим драм, так что раздаются неглавные или равноуровневые обращения, которые меньше, чем ширина чтения-изменения-записи шины с в кэше sram, который намного быстрее, и обратные вызовы AMD выровнены по ширине. Если у вас нет кеша перед дем, а контроллер предназначен для доступа по полной ширине, то это наихудшая производительность, если она предназначена для освещения байтовых полос отдельно (при условии, что чипы шириной 8 бит), то у вас нет модификации read-modify -writes, но более сложный контроллер. если типичный вариант использования - с кешем (если он есть в дизайне), то может быть бессмысленно иметь эту дополнительную работу в контроллере для каждой байтовой полосы, но просто знать, как делать полную передачу ширины шины или кратными.