Re[4]: Умный вопрос по C/C++
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 23.08.07 08:18
Оценка: 1 (1) +1
Здравствуйте, Smal, Вы писали:

S>А еще лучше так (и короче, и переносимо).


S>
S>void swap_words(uint32_t* arg)
S>{
S>    uint16_t  hi = (uint16_t) ((*arg & 0xFFFF0000u)>>16);
S>    uint16_t  lo = (uint16_t) ((*arg & 0x0000FFFFu));

S>    *arg = hi | (lo << 16);
S>} 
S>


А по скорости?


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[4]: Умный вопрос по C/C++
От: Alexander Pazdnikov  
Дата: 23.08.07 08:19
Оценка: +1
Здравствуйте, Smal, Вы писали:

S>А еще лучше так (и короче, и переносимо).


Согласен, только вот платформа x86 изначально разваращает и в принципе провоцирует использование в С приведение типов, потому как у нее при чтении невыровненной памяти происходит два чтения смежных областей памяти (на 80x86 — 80x286 соответсвенно двух слов) и все пучком, время выполнения увеличивается только.
Re[4]: Умный вопрос по C/C++
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 23.08.07 08:21
Оценка:
Здравствуйте, Alexander Pazdnikov, Вы писали:

E>>Насколько я понимаю, в C++ стандарте такого ограничения нет. Тем не менее, GCC 3.4.4 для C++ генерирует такой же проблемный код, как и для C


E>>McSeem2 прав -- такая паранойя. Если уж C/C++ позиционируются как языки для работы непосредственно с железом, то запрещение простого свопинга байт/слов выглядит полным маразмом.


AP>Вообще, такая проблема наблюдается на процессорах, адресация в которых к данным должна быть выравнена по границе 2, 4 и т.д. (8 не встречал)

AP>Так вот, сразу же налетел на ARM (AT91RM9200) на выравнивание по границе кратной 2.
AP>Потратил на это порядка несольких часов, просто ушли в холостую.
AP>А произошло это из-за того,что надо было из буфера (char*)[1] получить uint32_t или наоборот в (char*)[1] положить uint32_t.
AP>Тут бы по выравниванию памяти вообще механизм блокировок придумать какой-то было бы просто замечательно.

Выравнивание -- это не новая проблема. Но как раз в приведенном McSeem2 механизме свопинга проблем быть не должно. Поскольку uint32_t* будет выравнен на кратную 4-м границу, uint16_t* на кратную 2-м границу, а char* на любой адрес. Такие заморочки были на SPARC-ах когда-то очень давно. И ничего, все работало.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[3]: Умный вопрос по C/C++
От: Bell Россия  
Дата: 23.08.07 08:24
Оценка:
Здравствуйте, Smal, Вы писали:

S>Тоже самое. Надо так.


S>
S>void swap_words(uint32_t* arg)
S>{
S>    union { uint16_t sp[2]; uint32_t v; } u;
S>    u.v = *arg;
S>    uint16_t  hi = u.sp[0];
S>    uint16_t  lo = u.sp[1];

S>    u.sp[1] = hi;
S>    u.sp[0] = lo;
S>    *arg = u.v;
S>} 
S>


Да, этот вариатн как раз подпадает под 9.2/16 .
Любите книгу — источник знаний (с) М.Горький
Re[5]: Умный вопрос по C/C++
От: Alexander Pazdnikov  
Дата: 23.08.07 08:29
Оценка:
Здравствуйте, eao197, Вы писали:

E>Выравнивание -- это не новая проблема. Но как раз в приведенном McSeem2 механизме свопинга проблем быть не должно. Поскольку uint32_t* будет выравнен на кратную 4-м границу, uint16_t* на кратную 2-м границу, а char* на любой адрес. Такие заморочки были на SPARC-ах когда-то очень давно. И ничего, все работало.


Мда... Сейчас перевожу проект под ARM с Си на С++, так что чувствую, если включить -O2, то в кусках могут появиться интересные глюки, невоспроизводимые при -g
Re[5]: Умный вопрос по C/C++
От: Smal Россия  
Дата: 23.08.07 08:32
Оценка:
Здравствуйте, eao197, Вы писали:

E>Здравствуйте, Smal, Вы писали:


S>>А еще лучше так (и короче, и переносимо).


S>>
S>>void swap_words(uint32_t* arg)
S>>{
S>>    uint16_t  hi = (uint16_t) ((*arg & 0xFFFF0000u)>>16);
S>>    uint16_t  lo = (uint16_t) ((*arg & 0x0000FFFFu));

S>>    *arg = hi | (lo << 16);
S>>} 
S>>


E>А по скорости?

Лениво тестировать. Но очень хочется верить, что это не bottle-neck %).
Оптимизировать нужно алгоритмы, а не битовые операции. Если окажется, что
данная операция сжирает хоть какое-то значимое время, то значит нужно
оптимизировать алгоритм, её вызывающий.
С уважением, Александр
Re[6]: Умный вопрос по C/C++
От: Alexander Pazdnikov  
Дата: 23.08.07 08:34
Оценка: -1
Здравствуйте, Smal, Вы писали:

Кто-нибудь!!!
Т.е. получается, что sp будет указывать по непонятному адресу? Т.е. реально вообще получить Segmentation Fault (при sp[0] = hi)?!!!
Правильно ли я понял?
Re[6]: Умный вопрос по C/C++
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 23.08.07 08:34
Оценка: +1
Здравствуйте, Smal, Вы писали:

S>>>А еще лучше так (и короче, и переносимо).


S>>>
S>>>void swap_words(uint32_t* arg)
S>>>{
S>>>    uint16_t  hi = (uint16_t) ((*arg & 0xFFFF0000u)>>16);
S>>>    uint16_t  lo = (uint16_t) ((*arg & 0x0000FFFFu));

S>>>    *arg = hi | (lo << 16);
S>>>} 
S>>>


E>>А по скорости?

S>Лениво тестировать. Но очень хочется верить, что это не bottle-neck %).
S>Оптимизировать нужно алгоритмы, а не битовые операции. Если окажется, что
S>данная операция сжирает хоть какое-то значимое время, то значит нужно
S>оптимизировать алгоритм, её вызывающий.

Угу. Только вот когда придется мегабайты данных преобразовывать из host byte order в network byte order разница в скорости двух простых решений может оказаться слишком существенной. Так что результаты замеров были бы очень интересны.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[4]: Умный вопрос по C/C++
От: Bell Россия  
Дата: 23.08.07 08:37
Оценка:
Здравствуйте, Smal, Вы писали:

S>А еще лучше так (и короче, и переносимо).

Первый вариант тоже вполне переносим. И его тоже можно записать достаточно коротко:

void swap_words(uint32_t* arg)
{
    union { uint32_t v; uint16_t sp[2]; } u = {*arg};
    std::swap(u.sp[0], u.sp[1]);
    *arg = u.v;
}
Любите книгу — источник знаний (с) М.Горький
Re[7]: Умный вопрос по C/C++
От: Smal Россия  
Дата: 23.08.07 08:49
Оценка: 20 (1)
Здравствуйте, eao197, Вы писали:

E>Угу. Только вот когда придется мегабайты данных преобразовывать из host byte order в network byte order разница в скорости двух простых решений может оказаться слишком существенной. Так что результаты замеров были бы очень интересны.


#include <stdio.h>

typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;

void swap_words1(uint32_t* arg)
{
    uint16_t* sp = (uint16_t*)arg;
    uint16_t  hi = sp[0];
    uint16_t  lo = sp[1];
    sp[1] = hi;
    sp[0] = lo;
} 

void swap_words2(uint32_t* arg)
{
    uint16_t  hi = (uint16_t) ((*arg & 0xFFFF0000u)>>16);
    uint16_t  lo = (uint16_t) ((*arg & 0x0000FFFFu));

    *arg = hi | (lo << 16);
} 

void swap_words3(uint32_t* arg)
{
    union { uint16_t sp[2]; uint32_t v; } u;
    u.v = *arg;
    uint16_t  hi = u.sp[0];
    uint16_t  lo = u.sp[1];

    u.sp[1] = hi;
    u.sp[0] = lo;
    *arg = u.v;
}

int main()
{
   uint32_t v = 0xFFFF0000u;
   int i = 0;

   for ( i = 0; i != 10000000; ++i )
       swap_words1(&v);

   for ( i = 0; i != 10000000; ++i )
       swap_words2(&v);

   for ( i = 0; i != 10000000; ++i )
       swap_words3(&v);


   printf("%08X\n", v);
   return 0;
}


gcc

Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls ns/call ns/call name
54.17 0.26 0.26 10000000 26.00 26.00 swap_words3
25.00 0.38 0.12 10000000 12.00 12.00 swap_words1
10.42 0.43 0.05 10000000 5.00 5.00 swap_words2
10.42 0.48 0.05 main


gcc -O1

Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls ns/call ns/call name
41.67 0.05 0.05 10000000 5.00 5.00 swap_words2
25.00 0.08 0.03 10000000 3.00 3.00 swap_words3
16.67 0.10 0.02 10000000 2.00 2.00 swap_words1
16.67 0.12 0.02 main


gcc -O2

Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls ns/call ns/call name
46.15 0.12 0.12 main
19.23 0.17 0.05 10000000 5.00 5.00 swap_words2
19.23 0.22 0.05 10000000 5.00 5.00 swap_words3
15.38 0.26 0.04 10000000 4.00 4.00 swap_words1


gcc.EXE (GCC) 3.4.4 (mingw special)
P4 3.2GHz, 2Gb RAM

Комментарии?
С уважением, Александр
Re[7]: Умный вопрос по C/C++
От: Smal Россия  
Дата: 23.08.07 08:54
Оценка: 2 (1)
Здравствуйте, Alexander Pazdnikov, Вы писали:

AP>Здравствуйте, Smal, Вы писали:


AP>Кто-нибудь!!!

AP>Т.е. получается, что sp будет указывать по непонятному адресу? Т.е. реально вообще получить Segmentation Fault (при sp[0] = hi)?!!!
AP>Правильно ли я понял?
Можно получить все что угодно, ибо UB.

В реальности я трейсил адреса. arg и sp совпадают.
Правда при трейсах меняется результат, ибо это гейзенбаг.
Что там внутри происходит, я не смотрел. Надо дизассемблировать и смотреть — лень.
Да и какая разница. А т.к. UB, то можно получить и SF .
С уважением, Александр
Re: Умный вопрос по C/C++
От: Аноним  
Дата: 23.08.07 08:56
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>void swap_words(uint32_t* arg)

MS>{
MS> uint16_t* sp = (uint16_t*)arg;
MS> uint16_t hi = sp[0];
MS> uint16_t lo = sp[1];
MS> sp[1] = hi;
MS> sp[0] = lo;
MS>}

А можно увидеть ассемблерный листинг этого чуда? Хочется понять почему для 2-х байтового значения потребовалось более другое выравнивание, чем для 4-х байтового.
Re[7]: Умный вопрос по C/C++
От: Erop Россия  
Дата: 23.08.07 09:17
Оценка:
Здравствуйте, Alexander Pazdnikov, Вы писали:

AP>Т.е. получается, что sp будет указывать по непонятному адресу? Т.е. реально вообще получить Segmentation Fault (при sp[0] = hi)?!!!

AP>Правильно ли я понял?

Нет. Не правильно.
sp будет указывать куда-то на стек. Но вот значение переменной v2 (кажется так её там звали?) может оказаться не на стеке, а в регистре, например, в этот момент.

Я думаю, что в приведённом коде происходит следующее. Функция подставляется, зависимость значения переменной v2 от манипуляций с sp компилятором не отслеживается благодаря обсуждаемому правилу, соответсвенно компилятор видит, что v2 инициализируется, потом от него берут адрес, не являющийся алиасом, потом печатают, и скорее всего просто печатает константу...

Можно код посмотреть, в принципе.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Умный вопрос по C/C++
От: Awaken Украина  
Дата: 23.08.07 09:32
Оценка:
А>А можно увидеть ассемблерный листинг этого чуда? Хочется понять почему для 2-х байтового значения потребовалось более другое выравнивание, чем для 4-х байтового.

я делал ассемблерные листинги обоих вариантов, скомпиленных GCC 4.1.x (linux)
интересно то что команды в дебажном и релизном варианте не отличаются вообще.
но в релизном некоторые переставлены местами (для выравнивания команд на границу слова?)
Re[8]: Умный вопрос по C/C++
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 23.08.07 09:32
Оценка:
Здравствуйте, Smal, Вы писали:

S>Комментарии?


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

На VC++ 7.1 вариант с union вообще самым медленным оказался.

И кстати, VC++ 7.1 не компилирует вариант swap_words3 (а GCC компилирует), поскольку переменные в функции нужно объявлять до использования:

void swap_words3(uint32_t* arg)
{
    union { unsigned short sp[2]; unsigned int v; } u;

    unsigned short  hi;
    unsigned short  lo;

    u.v = *arg;
    hi = u.sp[0];
    lo = u.sp[1];

    u.sp[1] = hi;
    u.sp[0] = lo;
    *arg = u.v;
}


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[9]: Умный вопрос по C/C++
От: Smal Россия  
Дата: 23.08.07 09:40
Оценка:
Здравствуйте, eao197, Вы писали:

E>Здравствуйте, Smal, Вы писали:


S>>Комментарии?


E>А я разве утверждал, что ваш вариант будет самым медленным?

Просто замеры для таких "мелких" операций меня всегда напрягают.
Мне только один раз действительно пришлось ускорять некоторую элементарную
операцию — вычисление барицентрических координат. Но я делал это уже после того, как
исчерпал все оптимизации по алгоритму, прикрутил кэши и т.п.

E>Вот приведенные вами цифры показывают, что на битовых операциях не только переносимее, но и быстрее.

Только если без оптимизаций. Хотя, если выкинуть первый вариант как не работающий, то да. .

E>На VC++ 7.1 вариант с union вообще самым медленным оказался.

.

E>И кстати, VC++ 7.1 не компилирует вариант swap_words3 (а GCC компилирует), поскольку переменные в функции нужно объявлять до использования:

Это С++-ные привычки .
С уважением, Александр
Re[8]: Умный вопрос по C/C++
От: CreatorCray  
Дата: 23.08.07 09:51
Оценка: 27 (2)
Здравствуйте, Smal, Вы писали:

S>Комментарии?


ICC 10 /O3
P4 630

Скорость в попугаях

swap_words1: 54.2
swap_words2: 94.8
swap_words3: 122.6

код (есессна все вызовы заинлайнило)
;;;             swap_words1(&v);
  00036 0f b7 54 24 08   movzx edx, WORD PTR [esp+8]            ;.\test.cpp:44.4
  0003b 0f b7 4c 24 0a   movzx ecx, WORD PTR [esp+10]           ;.\test.cpp:44.4
  00040 66 89 54 24 0a   mov WORD PTR [esp+10], dx              ;.\test.cpp:44.4
  00045 66 89 4c 24 08   mov WORD PTR [esp+8], cx               ;.\test.cpp:44.4


;;;             swap_words2(&v);
  0006c 8b 54 24 08      mov edx, DWORD PTR [esp+8]             ;.\test.cpp:53.16
$LN33:
  00070 8b da            mov ebx, edx                           ;.\test.cpp:53.4
  00072 81 e3 00 00 ff 
        ff               and ebx, -65536                        ;.\test.cpp:53.4
  00078 c1 eb 10         shr ebx, 16                            ;.\test.cpp:53.4
  0007b c1 e2 10         shl edx, 16                            ;.\test.cpp:53.4
  0007e 0b da            or ebx, edx                            ;.\test.cpp:53.4
$LN35:
  00080 89 5c 24 08      mov DWORD PTR [esp+8], ebx             ;.\test.cpp:53.16


;;;             swap_words3(&v);
  000a6 c1 44 24 08 10   rol DWORD PTR [esp+8], 16              ;.\test.cpp:62.4


Впечатлил результат компиляции третьего варианта...
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re: Умный вопрос по C/C++
От: Кодт Россия  
Дата: 23.08.07 10:39
Оценка: :)))
Здравствуйте, McSeem2, Вы писали:

<>

А ещё одна версия — правда, дикая — то, что на целевой платформе 32-битный байт!
Ты уверен, что не для БЭСМ-6 компилируешь?
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[2]: Умный вопрос по C/C++
От: elcste  
Дата: 23.08.07 11:11
Оценка:
Здравствуйте, Андрей Коростелев, Вы писали:

АК>Правило введенное в С99 и запрещающее создание алиаса объекта с типом отличного от типа объекта-оригинала (ISO/IEC 9899 6.5/7) поддерживается в gcc 3.4.1 и выше на уровнях оптимизации начиная со 2-го.


Почему "введенное в С99"? Если Вы о тексте из 6.5/7, то он представляет собой просто другую редакцию ISO/IEC 9899:1990, 6.3:

An object shall have its stored value accessed only by an lvalue that has one of the following types: 36
— the declared type of the object,
— a qualified version of the declared type of the object,
— a type that is the signed or unsigned type corresponding to the declared type of the object,
— a type that is the signed or unsigned type corresponding to a qualified version of the declared type of the object,
— an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
— a character type.


36 The intent of this list is to specify those circumstances in which an object may or may not be aliased.

Re[3]: Умный вопрос по C/C++
От: elcste  
Дата: 23.08.07 11:14
Оценка:
Здравствуйте, eao197, Вы писали:

E>Насколько я понимаю, в C++ стандарте такого ограничения нет. Тем не менее, GCC 3.4.4 для C++ генерирует такой же проблемный код, как и для C


В C++ все ровно то же самое.

5.17/8 If the value being stored in an object is accessed from another object that overlaps in any way the storage of the first object, then the overlap shall be exact and the two objects shall have the same type, otherwise the behavior is undefined.

Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.