Здравствуйте, Pzz, Вы писали:
N>>Ещё можно явно барьеры компилятору ставить через atomic_signal_fence().
N>>Записал в одно поле union, поставил барьер, прочитал другое поле.
N>>Оптимизация чуть пострадает, но для задачи разбора таких структур, кажется, без разницы, затраты на сеть будут больше.
N>>Или WRITE_ONCE + READ_ONCE образца Linux (которые внутри превращаются в volatile-доступы).
Pzz>Мне как-то даже в голову не приходило делать это через volatile (или эквиавалент).
Ну вот странно, потому что самый прямой вариант
Pzz>В принципе, правила этой весёлой игры говорят, что если кастировать через (char*), компилятор должен понять намёк и перечитывать поля.
Насколько я понял стандарт, не так. Доступ через char* просто никогда не алиасится с другим таким же доступом через char*. Но это не мешает оптимизировать доступ к тому же адресу через другие указатели. Берём код:
void foo(int *x, char *c)
{
*x = 1;
*c = 0;
*x = 2;
}
Компилируем gcc с -O2:
foo:
movb $0, (%rsi)
movl $2, (%rdi)
ret
Первая запись в *x съедена оптимизацией.
N>>Опять же, по сравнению с затратами на диск и сеть это копеечное время.
N>>А если где-то реально становится узким местом... таких немного, их можно и специально обработать.
Pzz>Я как-то разбирался, почему на какой-то армовской (или PPC? уже не помню...) железке с линухом внутри сеть медленно работает. Оказалось, какой-то альтернативно одаренный (1) включил опцию в ядре, которая ловит исключения по невыровненному доступу к 32-битным данным и эмулироет поведение в стиле x86 (2) не учел, что в заголовке ethernet 14 байт, в результате все IP-заголовки были выровнены на 4N + 2 байта.
Pzz>Просадка скорости была в два раза. Как только я выключил эмуляцию невыровненного доступа, мне ядро сразу напечатало стек, показав пальцем на источник проблемы, ну а дальше было уже совсем просто.
Вообще в современных процессорах все доступы кроме атомарных стараются допускать невыровненными. Затраты на это копеечные, пользы достаточно много.
Но пример, да, показательный.