Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> аппаратная проверка выравненных данных, что же такое выравнивание? 
:(
    Опции темы
null56
Дата 27.3.2014, 13:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: 2
Всего: 12



Всем привет

Процессор x86/x86_64

Задачи:
1) понять что такое проверка на выравненные данные
2) понять почему срабатывает проверка в конкретном примере
3) понять почему не срабатывает проверка в другом примере
4) понять зачем вообще эта проверка нужна? то есть был введен флаг в регистре СЛОВА (бит 18)
http://ru.wikipedia.org/wiki/%D0%A0%D0%B5%...%B3%D0%BE%D0%B2

И так
Вопрос 1: правильно ли я понимаю понятие "проверка на выравнивание"?
проверка на выравнивание - это ошибка в том случае, когда идет ДОСТУП к данным в оперативной памяти не по кратному машинному слову адресу (4 - для x86, 8 - для )
или
это связано с размером данных и адресом? скажем, если читаем 2 байта, то адрес должен быть кратен 2м, 4 - 4м?
Код

....
// ошибка, невыровненный доступ
char * ch = malloc(64);
int *i = (int *)(a + 2);
*i = 789;

....


И так пример: компилятор gcc 64 разрядный, поэтому буду использовать опцию -m32, чтобы сделать тесты 32разрядных приложений

Для незнающих gnu assembler: вставка 1) сохраняет в стек регистр слова, 2) изменяет в этом значении 18 бит, 3) загружает слово обратно в регистр. Код проверенных в дебагере, ошибок нет

32 бита: сборка с флагом -m32
Код

int main()
{
        asm("pushfl; "
        "orl $(1<<18), (%esp); "
        "popfl;");

        char d[] = "12345678";

        return 0;
}

Результат: "Ошибка шины"
Вопрос 2: если я правильно понимаю понятие "проверка на выравнивание", то тогда не понимаю, почему в данном примере идет какая - то проверка? ведь я даже к памяти не обратился?

64 бита (в ассемблерной вставке используется расширенный регистр указателя стека rsp, а так та же суть)
Код

int main()
{
        asm("pushf; "
        "orl $(1<<18), (%rsp); "
        "popf;");

        char a[] = "12345678";
//        char a[] = "1234567812345678";
       
        return 0;
}

Результат: ошибка добиться не получилось

Вопрос 3: как добиться аналогичной x86 ошибки на 64 битах?

ну и на конец
Вопрос 4: для чего нужна эта проверка?
в соседних темах были разговоры о более быстром доступе, размещение в кеше еще чего - то... Но, вопрос именно ЗАЧЕМ нужна проверка? где ее можно использовать?

Спасибо всем отклинувшимся за помощь

Это сообщение отредактировал(а) null56 - 27.3.2014, 13:15
PM MAIL   Вверх
null56
Дата 27.3.2014, 13:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: 2
Всего: 12



вопрос 1, наверное можно снять, нашел правила выравнивания тут
http://www.intel.com/content/www/us/en/arc...t-1-manual.html
иными словами, правильнее будет считать, что начальный адрес должен быть кратен размеру данных

Это сообщение отредактировал(а) null56 - 27.3.2014, 13:32
PM MAIL   Вверх
bsa
Дата 31.3.2014, 18:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



Цитата(null56 @  27.3.2014,  14:03 Найти цитируемый пост)
Вопрос 4: для чего нужна эта проверка?
в соседних темах были разговоры о более быстром доступе, размещение в кеше еще чего - то... Но, вопрос именно ЗАЧЕМ нужна проверка? где ее можно использовать?
Некоторые процессоры просто требуют выровненного доступа. Т.е. если ты пытаешься прочитать 4 байта по адресу не кратному 4, то:
1. возникнет аппаратное исключение
2. будет прочитано хрен знает что (скорее всего, будет прочитано 4 байта с адреса address & ~(4 - 1))
Чтобы это не происходило компилятор выравнивает весь доступ. Если это невозможно, то читает по 1 байту. И вместо одной инструкции для чтения 32-х битного слова ты получаешь минимум 4 штуки.
PM   Вверх
null56
Дата 1.4.2014, 15:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: 2
Всего: 12



bsa, да про исключение я знаю, у нас на blackfin как раз падает всё
тут ключевое слово "некоторые процессоры".
так вот вопрос: зачем на процах(такие как x86), которые умеют читать по невыровненным адресам, этот флажок? для отладки? чтобы переносить на другие процы  что ли?
PM MAIL   Вверх
Alexeis
Дата 1.4.2014, 15:36 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 12
Всего: 459



Цитата(null56 @  1.4.2014,  16:07 Найти цитируемый пост)
так вот вопрос: зачем на процах(такие как x86), которые умеют читать по невыровненным адресам, этот флажок? для отладки? чтобы переносить на другие процы  что ли? 

  Производительность разная. Данные выровненные на границу 4/8ми байт быстрее адресуются, чем выравненные на границу 1го байта. 


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
vinter
Дата 3.4.2014, 09:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Explorer
****


Профиль
Группа: Завсегдатай
Сообщений: 2735
Регистрация: 1.4.2006
Где: Н.Новгород

Репутация: 13
Всего: 56



null56, посмотри первую часть статьи


--------------------
Мой блог
PM MAIL WWW   Вверх
null56
Дата 4.4.2014, 12:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 721
Регистрация: 19.3.2008

Репутация: 2
Всего: 12



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


Alexeis, 
vinter, 
а теперь прочитаем внимательнее вопрос... может я его не верно задал?
Цитата

зачем на процах(такие как x86), которые умеют читать по невыровненным адресам, этот флажок? для отладки? чтобы переносить на другие процы  что ли? 

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

но! вопрос связан с назначением 18 бита в слове процессора? по умолчанию он выключен на х86, если включаю, то включается и проверка.... вопрос: зачем надо включать этот флаг??? зачем он вообще присутствует в процессоре данной архитектуры?
PM MAIL   Вверх
k0rvin
Дата 4.4.2014, 14:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 442
Регистрация: 24.1.2010

Репутация: 1
Всего: 5



Цитата(Alexeis @  1.4.2014,  15:36 Найти цитируемый пост)
Производительность разная. Данные выровненные на границу 4/8ми байт быстрее адресуются, чем выравненные на границу 1го байта.  

Т.е. работа с массивом char менее эффективна, чем с массивом int?


--------------------
“Object-oriented design is the roman numerals of computing.” — Rob Pike
All software sucks
PM MAIL   Вверх
vinter
Дата 4.4.2014, 15:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Explorer
****


Профиль
Группа: Завсегдатай
Сообщений: 2735
Регистрация: 1.4.2006
Где: Н.Новгород

Репутация: 13
Всего: 56



Цитата(k0rvin @  4.4.2014,  15:21 Найти цитируемый пост)
Т.е. работа с массивом char менее эффективна, чем с массивом int?

нельзя этого утверждать, как нельзя утверждать и обратное. Всё нужно измерять.

Это сообщение отредактировал(а) vinter - 4.4.2014, 15:29


--------------------
Мой блог
PM MAIL WWW   Вверх
k0rvin
Дата 5.4.2014, 05:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 442
Регистрация: 24.1.2010

Репутация: 1
Всего: 5



Ладно, фиг с ней, с эффективностью. Есть такой код:
Код

#include <u.h>
#include <libc.h>

typedef int       Value;
typedef Value   **Matrix;
typedef uvlong    Size;

Matrix  Mnew(Size, Size);
void    Mfree(Matrix);
Size    Mrows(Matrix);
Size    Mcolumns(Matrix);

void    minit(Matrix);
void    mprint(Matrix);

void    usage(char*);

void
main(int argc, char *argv[])
{
    Size m, n;
    Matrix a;

    if (argc != 3) {
        usage(argv[0]);
        exits("badarg");
    }
    m = atoi(argv[1]);
    n = atoi(argv[2]);
    if (m < 2 || n < 2) {
        usage(argv[0]);
        exits("badarg");
    }
    a = Mnew(m, n);
    if (a == nil) {
        fprint(2, "can't allocate enough memory: %r");
        exits("Mnew");
    }

    minit(a);
    mprint(a);

    Mfree(a);
    exits(0);
}

void
usage(char *app)
{
    fprint(2, "usage: %s <rows count> <columns count>\n", app);
    fprint(2, "\nrows count    : integer greater than 2\n");
    fprint(2, "\ncolumns count : integer greater than 2\n");
}

Matrix
Mnew(Size m, Size n)
{
    Size *block, i;
    Matrix a;
    Value *r;

    block = malloc(
        2 * sizeof(Size) + 
        m * sizeof(Value *) + 
        m * n * sizeof(Value)
    );
    if (block == nil)
        return nil;
    block[0] = m;
    block[1] = n;
    a = (Matrix) (block + 2);
    for (i = 0, r = (Value *) (a + m); i < m; i++, r += n)
        a[i] = r;
    return a;
}

Size *
_mbbegin(Matrix a, int shift)
{
    return ((Size *) a) + shift;
}

void
Mfree(Matrix a)
{
    free(_mbbegin(a, -2));
}
 
Size
Mrows(Matrix a)
{
    return *(_mbbegin(a, -2));
}
 
Size
Mcolumns(Matrix a)
{
    return *(_mbbegin(a, -1));
}

void
minit(Matrix a)
{
    Size i, j, m, n;
    m = Mrows(a);
    n = Mcolumns(a);

    for (i = 0; i < m; i++)
        for (j = 0; j < n; j++)
            a[i][j] = i * n + j;
}

void
mprint(Matrix a)
{
    Size i, j, m, n;
    m = Mrows(a);
    n = Mcolumns(a);

    for (i = 0; i < m; i++) {
        for (j = 0; j < n; j++)
            print(" %4d ", a[i][j]);
        print("\n");
    }
}


Один знакомый сказал, что такой способ представления массива «опасен при кроссплатформенности — у разных аппаратных платформ разные требования к выравниванию. Необходимо принять меры в виде пустого куска между указателями и данными», но безопасного варианта он пока не предоставил. Может вы что подскажете?


--------------------
“Object-oriented design is the roman numerals of computing.” — Rob Pike
All software sucks
PM MAIL   Вверх
vinter
Дата 5.4.2014, 08:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Explorer
****


Профиль
Группа: Завсегдатай
Сообщений: 2735
Регистрация: 1.4.2006
Где: Н.Новгород

Репутация: 13
Всего: 56



k0rvin, да, твой способ хранения явно не лучший, в плане выравнивания. Во первых тебе нужно выделять память выровненную по Size. Потом тебе уже надо ручками подсчитать, где после Size должны располагаться Value* и это будет зависеть от размера указателя на платформе. Псле чего тебе нужно посчитать, опять руками, где можно начать располагать Value. На мой взгляд оно того не стоит smile

Это сообщение отредактировал(а) vinter - 5.4.2014, 08:50


--------------------
Мой блог
PM MAIL WWW   Вверх
Alexeis
Дата 5.4.2014, 11:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

Репутация: 12
Всего: 459



Цитата(vinter @  4.4.2014,  16:28 Найти цитируемый пост)
нельзя этого утверждать, как нельзя утверждать и обратное. Всё нужно измерять.

  Достаточно посмотреть ассемблерный код. Но на самом деле речь об ином. Когда компилятор вставляет код записи в не выровненные поля то добавляются лишние инструкции. Массив байтов считается выравненным. Даже если поставить режим выравнивания на 8 или 16 байтов, все равно в массиве байты будут идти один за другим. Но тем не менее код записи в char длиннее чем в int размера в регистр.
  
Цитата(null56 @  4.4.2014,  13:45 Найти цитируемый пост)
но! вопрос связан с назначением 18 бита в слове процессора? по умолчанию он выключен на х86, если включаю, то включается и проверка.... вопрос: зачем надо включать этот флаг??? зачем он вообще присутствует в процессоре данной архитектуры? 

  Могу предположить, что флаг связан с риск архитектурой 
Цитата(http://ru.wikipedia.org/wiki/RISC)

Наиболее широко используемые в настольных компьютерах процессоры архитектуры x86 ранее являлись CISC-процессорами, однако новые процессоры, начиная с Intel 486DX, являются CISC-процессорами с RISC-ядром[источник не указан 1169 дней]. Они непосредственно перед исполнением преобразуют CISC-инструкции x86-процессоров в более простой набор внутренних инструкций RISC.
 По крайней мере ARM процессоры, которые чисто RISC генерят исключение при попытке адресовать по не выровненному адресу. Кроме того, этот флаг можно использовать для раннего обнаружения ошибок работы с памятью, ведь даже компиляторы для x86 не используют не выравненные адреса. 


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
vinter
Дата 5.4.2014, 12:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Explorer
****


Профиль
Группа: Завсегдатай
Сообщений: 2735
Регистрация: 1.4.2006
Где: Н.Новгород

Репутация: 13
Всего: 56



Цитата(Alexeis @  5.4.2014,  12:16 Найти цитируемый пост)
Достаточно посмотреть ассемблерный код

нет не достаточно. Ты измерял выровненный и не выровненный код? Я вот измерял и мне пришлось изрядно потрудиться, чтобы написать код при котором будет хотя бы 5% разница на моём core i7.

Цитата(Alexeis @  5.4.2014,  12:16 Найти цитируемый пост)
  Могу предположить, что флаг связан с риск архитектурой 

x86 не является RISC, а то, что там внутри наружу выдавать никто не будет, на мой взгляд


--------------------
Мой блог
PM MAIL WWW   Вверх
k0rvin
Дата 6.4.2014, 09:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 442
Регистрация: 24.1.2010

Репутация: 1
Всего: 5



Цитата(vinter @  5.4.2014,  08:50 Найти цитируемый пост)
Во-первых, тебе нужно выделять память выровненную по Size

Зачем?

Цитата(vinter @  5.4.2014,  08:50 Найти цитируемый пост)
Потом тебе уже надо ручками подсчитать, где после Size должны располагаться Value*

А «2*sizeof(Size)» по-твоему зачем? Впрочем тут все относительно просто, как мне предложили
Код

#include <stddef.h>

struct S
{
    Size s[2];
    Matrix m;
    ...
}

offsetof(struct S, m);

Но размер массива m не известен в compile-time, поэтому я не могу узнать, сколько он на самом деле займет памяти с учетом выравнивания.


Цитата(vinter @  5.4.2014,  08:50 Найти цитируемый пост)
Псле чего тебе нужно посчитать, опять руками, где можно начать располагать Value. На мой взгляд оно того не стоит

«m*sizeof(Value *)» чем не устраивает?

Т.е. собвственно проблема в том, чтобы узнать, какое выравнивание использует текущая среда (компилятор+ОС+железо).


--------------------
“Object-oriented design is the roman numerals of computing.” — Rob Pike
All software sucks
PM MAIL   Вверх
vinter
Дата 6.4.2014, 09:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Explorer
****


Профиль
Группа: Завсегдатай
Сообщений: 2735
Регистрация: 1.4.2006
Где: Н.Новгород

Репутация: 13
Всего: 56



Цитата(k0rvin @  6.4.2014,  10:20 Найти цитируемый пост)
Зачем?

затем, что если ты задумался о выравнивании, то нужно чтобы первый объект твоих данных находился по выровненному адресу. В твоём коде этого нет.

Цитата(k0rvin @  6.4.2014,  10:20 Найти цитируемый пост)
А «2*sizeof(Size)» по-твоему зачем?

понятия не имею, но к выравниванию это не имеет никакого отношения.  К примеру, Size Равный 5 байт. 2*5 = 10. mallco выделяет память по адресу 3. Значит первый Size находится по адресу 3, второй по адресу 8. Указатель по адресу 13. В результате мы имеем чёрти-что. Понятно?

Цитата(k0rvin @  6.4.2014,  10:20 Найти цитируемый пост)
«m*sizeof(Value *)» чем не устраивает?

тоже самое.


Цитата(k0rvin @  6.4.2014,  10:20 Найти цитируемый пост)
Впрочем тут все относительно просто, как мне предложили

Цитата(k0rvin @  6.4.2014,  10:20 Найти цитируемый пост)
о размер массива m не известен в compile-time,

так просто или непонятно как сделать?

Цитата

 malloc(
        2 * sizeof(Size) + 
        m * sizeof(Value *) + 
        m * n * sizeof(Value)

я понимаю твою запись как: выделить память под 2 Size, m указателей на Value и m x n объектов типа Value. Если всё так, то я не вижу просто го способа решения этой проблемы - нужно много считать и не ошибиться при этом


--------------------
Мой блог
PM MAIL WWW   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0679 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.