Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 15.09.21 09:23
Оценка:
Внезапно подумалось, почему оптимизаторы C/C++ традиционно исходят из возможности наложения (aliasing) указателей, позволяя явно указать его отсутствие (restrict, __declspec (noalias), __declspec (restrict) и т.п.), но явная возможность указать наличие наложения мало где есть? Соответственно, большинство компиляторов подходит к оптимизации достаточно осторожно, хотя можно было бы оптимизировать и лучше.

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

— Обсчет многомерных векторов/матриц, когда алгоритм предполагает разные выборки по размерностям, и это удобнее оформлять отдельными функциями.

— Формирование/преобразование изображений в [видео]памяти.

Но в подавляющем большинстве случаев наложения указателей не происходит, и осторожность явно лишняя.
compiler optimization aliasing pointer memory
Re: Как вышло, что наложение предполагается по умолчанию?
От: imh0  
Дата: 15.09.21 09:48
Оценка: -4
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Внезапно подумалось, ....


Хороший вопрос, на самом деле!

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


Думаю тут надо сначала разделить вопрос на СИ и С++, из-за того что в С++ есть ссылки, а в СИ нет.

То есть в С++ если программист хочет использовать указатели но также хочет, чтобы оптимизатор мог хорошо оптимизировать, то он должен не использовать указатели как таковые, а использовать ссылки. Ссылки строже, чем указатели, но в тоже время позволяют получить почти такой же эффект.
Поэтому в С++ этот вопрос теряет актуальность.

В СИ же, нет ссылок, поэтому действительно оптимизация может быть хуже.

Я думаю, СИ является низкоуровневым языком, поэтому от него требуется быть более предсказуемым. Кроме того на программиста он наклыдывает требование более высокой квалификации. И поэтому с одной стороны "пусть не эффективно но предсказуемо", а с другой "пусть программист сам скажет, в узких местах, что нужна более сильная оптимизация".
Re: Как вышло, что наложение предполагается по умолчанию?
От: Zhendos  
Дата: 15.09.21 09:58
Оценка: +2
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Внезапно подумалось, почему оптимизаторы C/C++ традиционно исходят из возможности наложения (aliasing) указателей, позволяя явно указать его отсутствие (restrict, __declspec (noalias), __declspec (restrict) и т.п.), но явная возможность указать наличие наложения мало где есть?


Игнорирование возможности наложения может привести к неправильно
работающей программе, а наоборот только к ухудшению производительности.
Выбор по-моему очевиден — предполагать везде наложение по умолчанию,
если не доказано обратное. По умолчанию надежность,
если пользовать говорит что нафиг надежность, то он за это отвечает,
что явно указано в коде. По-моему все разумно?

Ну и основная проблема конечно в том, что современные компиляторы
сами во многих случаях не могут докаать гипотезу что данные не перекрываются.
Re: Как вышло, что наложение предполагается по умолчанию?
От: Alexander G Украина  
Дата: 15.09.21 10:53
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Внезапно подумалось, почему оптимизаторы C/C++ традиционно исходят из возможности наложения (aliasing) указателей, позволяя явно указать его отсутствие (restrict, __declspec (noalias), __declspec (restrict) и т.п.), но явная возможность указать наличие наложения мало где есть? Соответственно, большинство компиляторов подходит к оптимизации достаточно осторожно, хотя можно было бы оптимизировать и лучше.


Большинство -- это MSVC и мимикрирующий под него clang-cl?

Здесь видно, что только MSVC предполагает возможность наложения short* и int*, остальные только предполагают наложение int* и int* (icc и gcc при этом создаёт ветку без наложения, и определяет наложение).

Наличчие наложения указывается через __attribute((__may_alias__)), хотя это может быть слишком пессимистично, может хотеться указать, что на что может накладываться.
Русский военный корабль идёт ко дну!
Re[2]: Как вышло, что наложение предполагается по умолчанию?
От: Zhendos  
Дата: 15.09.21 11:02
Оценка: +1
Здравствуйте, imh0, Вы писали:

I>Здравствуйте, Евгений Музыченко, Вы писали:


I>Поэтому в С++ этот вопрос теряет актуальность.


Почему это?

Возьмите

int f(int &a, int &b)
{
   a += 1;
   b += 1;
   return a + b;
}

int f2(int * a, int *  b)
{
    *a += 1;
    *b += 1;
    return *a + *b;
}


в обоих случаях комплиятор в оптимизируещем режиме сгенерирует одинаковый код,
и так же будет предполагать что "a" и "b" являются "алиасами" на один и тот же адрес.
А вот если добавить во втором случае "int * __restrict", то компилятор сможет
использовать тот факт что "a" и "b" указывают на разный адрес и код будет разный между
кодом со ссылками и "restrict" указателями.

Ссылки в C++ никакого отношения к "__restrict" не имеют.
Отредактировано 15.09.2021 12:33 Zhendos . Предыдущая версия .
Re: Как вышло, что наложение предполагается по умолчанию?
От: rg45 СССР  
Дата: 15.09.21 11:52
Оценка: +2
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Внезапно подумалось, почему оптимизаторы C/C++ традиционно исходят из возможности наложения (aliasing) указателей, позволяя явно указать его отсутствие (restrict, __declspec (noalias), __declspec (restrict) и т.п.), но явная возможность указать наличие наложения мало где есть?


Если нет уверенности, что наложение исключено, значит исходят из того, что наложение возможно. Корректность программы всегда была выше по приоритету, чем производительность. А как иначе?
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[3]: Как вышло, что наложение предполагается по умолчанию?
От: imh0  
Дата: 15.09.21 12:35
Оценка:
Здравствуйте, Zhendos, Вы писали:

I>>Поэтому в С++ этот вопрос теряет актуальность.


Z>Почему это?


Z>Возьмите

Z>

Z>int f(int &a, int &b)
Z>{
Z>   a += 1;
Z>   b += 1;
Z>   return a + b;
Z>}

Z>int f2(int * a, int *  b)
Z>{
Z>    *a += 1;
Z>    *b += 1;
Z>    return *a + *b;
Z>}
Z>



Даже не знаю, что тут сказать.... )

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

int f ( int & a,int &b )
{
    a+=1;
    b+=1;
    return a+b;
}

int f2 ( int * a )
{
    *(a+rand())+=1;
    *(a+rand())+=1;
    return *(a+rand()) + *(a+rand());
}

int main(int argc, char **argv) 
{
    int A1;
    int A2;
    int B2;
    int arr1[100];
    int arr2[100];
    int arr3[100];
    printf("f(A1,A1)=%d\n",f(A1,A1));
    printf("f(A2,B2)=%d\n",f(A2,B2));
    printf("f(arr1[10],arr1[10])=%d\n",f(arr1[10],arr1[10]));
    printf("f(arr2[10],arr2[11])=%d\n",f(arr2[10],arr2[11]));
    printf("f2(arr2[10])=%d\n",f2(&arr3[10]));
}


И посмотрим на код —

(gdb) disas main
Dump of assembler code for function main(int, char**):
=> 0x0000557e9c011080 <+0>: sub $0x198,%rsp
0x0000557e9c011087 <+7>: mov $0x4,%esi
0x0000557e9c01108c <+12>: lea 0xf71(%rip),%rdi # 0x557e9c012004
0x0000557e9c011093 <+19>: xor %eax,%eax
0x0000557e9c011095 <+21>: callq 0x557e9c011030 <printf@plt>
0x0000557e9c01109a <+26>: mov $0x2,%esi
0x0000557e9c01109f <+31>: lea 0xf6b(%rip),%rdi # 0x557e9c012011
0x0000557e9c0110a6 <+38>: xor %eax,%eax
0x0000557e9c0110a8 <+40>: callq 0x557e9c011030 <printf@plt>
0x0000557e9c0110ad <+45>: mov $0x4,%esi
0x0000557e9c0110b2 <+50>: lea 0xf65(%rip),%rdi # 0x557e9c01201e
0x0000557e9c0110b9 <+57>: xor %eax,%eax
0x0000557e9c0110bb <+59>: callq 0x557e9c011030 <printf@plt>
0x0000557e9c0110c0 <+64>: mov $0x2,%esi
0x0000557e9c0110c5 <+69>: lea 0xf6b(%rip),%rdi # 0x557e9c012037
0x0000557e9c0110cc <+76>: xor %eax,%eax
0x0000557e9c0110ce <+78>: callq 0x557e9c011030 <printf@plt>
0x0000557e9c0110d3 <+83>: lea 0x28(%rsp),%rdi
0x0000557e9c0110d8 <+88>: callq 0x557e9c011230 <f2(int*)>
0x0000557e9c0110dd <+93>: lea 0xf6c(%rip),%rdi # 0x557e9c012050
0x0000557e9c0110e4 <+100>: mov %eax,%esi
0x0000557e9c0110e6 <+102>: xor %eax,%eax
0x0000557e9c0110e8 <+104>: callq 0x557e9c011030 <printf@plt>
0x0000557e9c0110ed <+109>: xor %eax,%eax
0x0000557e9c0110ef <+111>: add $0x198,%rsp
0x0000557e9c0110f6 <+118>: retq 
End of assembler dump.
64^done


Что мы видим ?
1) Мы видим что компилятор прикрасно видит что идет ссылка на "одно и тоже"
2) Мы видим что по 0x0000557e9c0110d8 идет вызов f2. Причем понятно почему) Потому что мы МОЖЕМ заниматься адресной арифметикой с указателями, а со сылками какбы не особо)

Z>Ссылки в C++ никакого отношения к "__restrict" не имеют.


Что-то не туда уже куда-то поехало )
Re: Как вышло, что наложение предполагается по умолчанию?
От: watchmaker  
Дата: 15.09.21 12:35
Оценка: 5 (1) +1
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Внезапно подумалось, почему оптимизаторы C/C++ традиционно исходят из возможности наложения (aliasing) указателей


Ты сам написал верное слово "традиционно".
Это и ответ — C++ не дизайнился не с нуля, а итеративно и на базе С (который не ISO C, а более старый и кривой). Который тоже был сделан не с нуля, а унаследовал концепции из ещё более низкоуровневых языков. Вплоть до ассемблера, в котором есть только указатели и сырая память, а никаких знаний об объектах и их семантики нет совсем. Отсюда и в С (который ещё не ISO C) тоже не было массивов с семантикой массивов, а были замаскированные под них указатели (из-за чего до сих пор конструкции array[index] и index[array] компилируются и выдают одинаковый результат).
Те же классы в С++ базируются на структурах С, которые базируются на смещениях от указателей. И вот опять потерялось знание, что два класса могут быть или не быть независимыми.

Если бы можно было переделать С++ с нуля, то в него можно было бы добавить десяток quality-of-life улучшений, которые бы не изменили принципиально язык, но немедленно бы сделали его более быстрым, простым и надёжным. Сюда не только вошли бы более разумные правила на aliasing, но и такие вещи как move для всех типов по умолчанию, менее безумные правила octal-literals (когда одна цифра в числе меняет систему счисления), быстрые строки (с длиной, а не null-terminated), отсутствие неявных преобразований (как литеральный 0 в указатель) и т.п.

Но всё это почти не могло случится эволюционным путём:
1. Сразу написать правильно сложно, особенно когда ты почти первопроходец и не знаешь с какими проблемами столкнётся язык через 10 лет;
2. Если делать правильно и переделать всё кардинально, то потеряется совместимость с предыдущим кодом, и такой язык сильно потеряет в привлекательности — кому нужен язык, если нельзя использовать многочисленные наработки, а нужно всё переписывать под него заново? Нужно очень сильно вложится, чтобы сделать такой язык популярным.

Где-то там Страуструп в "Дизайне и эволюции С++" об подобном рассказывал: либо ты делаешь С-with-classes и получаешь всё тяжкое наследие С и ассемблера, либо ты делаешь новый язык, который несовместим ни с чем, и поэтому у него не будет ни пользователей, ни ресурсов довести его до ума.
Re[2]: Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 15.09.21 13:27
Оценка:
Здравствуйте, imh0, Вы писали:

I>в С++ есть ссылки, а в СИ нет.


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

Но подобное почти всегда происходит в рамках отдельной функции. Ситуации, когда функция получает указатель/ссылку на сложный объект в одном параметре, и на его подобъект — в другом, достаточно редки. Это или особые алгоритмы, или банальная криворукость.

I>Я думаю, СИ является низкоуровневым языком


С++ является почти столь же низкоуровневым языком, и это хорошо, это делает его уникальным и очень удобным. Некоторые не слишком умные люди предлагают оторвать от C++ низкоуровневые возможности, и двигать его исключительно в сторону высокого уровня, но они тупо не понимают сути языка, и очень хорошо, что их [пока] бьют по рукам.

I>поэтому от него требуется быть более предсказуемым.


Низкоуровневость ни разу не мешает предсказуемости. В случае неопределенного или платформ-зависимого поведения, дело компилятора — предупредить, и дать программисту возможность уточнить свою конструкцию. В этой области, чем меньше неконтролируемых предположений, тем лучше.
Re[2]: Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 15.09.21 13:31
Оценка:
Здравствуйте, Zhendos, Вы писали:

Z>если пользовать говорит что нафиг надежность, то он за это отвечает, что явно указано в коде.


Если программист отвечает за бОльшую часть кода — зачем заставлять его явно указывать это везде? Он мог бы указать, что в общем случае предположений делать не нужно, но в некоторых местах это будет явно отменено.

Придумали же давным-давно volatile, хотя могли бы объявить: раз какие-то переменные могут меняться извне текущего потока, то и никаких вам регистровых оптимизаций, только память.
Re[2]: Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 15.09.21 13:33
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Большинство -- это MSVC и мимикрирующий под него clang-cl?


Я ж не только о современных лидирующих — оптимизирующих компиляторов с C/C++ было достаточно. Кто, кроме GCC, давал возможность явно указывать возможность наложения?
Re[4]: Как вышло, что наложение предполагается по умолчанию?
От: Zhendos  
Дата: 15.09.21 14:11
Оценка: +2
Здравствуйте, imh0, Вы писали:

I>Даже не знаю, что тут сказать.... )


I>Ну давайте возьмем более осмысленный код, это как раз то, о чем я сообственно и говорил.


Я честно говоря тоже не знаю что сказать.
Здесь все вызовы будут встроенны, какое отношение приведенный
вами код вообще имеет к обсуждаемому вопросу?

I>Что мы видим ?


Мы видим что все заинлаилось, и все.

Давайте проще, допустим есть функция:
extern void f(Class &a, Class &b);


Я утверждаю что ее можно вызвать вот так "Class a; f(a, a);",
как я понимаю вы утверждаете, что компилятор для такого вызова выдаст ошибку?
Re[3]: Как вышло, что наложение предполагается по умолчанию?
От: Zhendos  
Дата: 15.09.21 14:24
Оценка: +1
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Здравствуйте, Zhendos, Вы писали:


ЕМ>Если программист отвечает за бОльшую часть кода — зачем заставлять его явно указывать это везде? Он мог бы указать, что в общем случае предположений делать не нужно, но в некоторых местах это будет явно отменено.


ЕМ>Придумали же давным-давно volatile, хотя могли бы объявить: раз какие-то переменные могут меняться извне текущего потока, то и никаких вам регистровых оптимизаций, только память.


Ну "volatile" память относительно редкое явление (имеется ввиду правильный
вариант его применения, когда "volatile" испольуется для указания части
которая может меняться не программой).

А вот то, что в функцию типа
"void append(Vector &arg1, const Vector &arg2)" в конце концов
засунут одну и ту же переменную и в качестве первого аргумента и в качестве
второго вероятность этого очень большая.
Отредактировано 15.09.2021 14:31 Zhendos . Предыдущая версия .
Re[5]: Как вышло, что наложение предполагается по умолчанию?
От: imh0  
Дата: 15.09.21 14:39
Оценка: -1
Здравствуйте, Zhendos, Вы писали:

Z>Я честно говоря тоже не знаю что сказать.


Да просто ты рефлексируешь на знакомые слова. ) Попробуй подумать.

Z>Здесь все вызовы будут встроенны, какое отношение приведенный

Z>вами код вообще имеет к обсуждаемому вопросу?

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

I>>Что мы видим ?


Z>Мы видим что все заинлаилось, и все.


Нет. Мы видим, что для одинаковых и разных заинлайнилось по разному. То есть для ссылок, нет нужды париться, то есть для С++ проблема не стоит.

Z>Давайте проще, допустим есть функция:

Z>
Z>extern void f(Class &a, Class &b);
Z>


Твой extern нафиг никого не напугает. Будет можно и это заинлайнится. )
Уж коли хочешь что-то такое продемонстрировать пиши что-то типа — __attribute__((noinline))

Z>Я утверждаю что ее можно вызвать вот так "Class a; f(a, a);",

Z>как я понимаю вы утверждаете, что компилятор для такого вызова выдаст ошибку?

С чего бы вдруг? Ты написал компилятор обязан выполнить.
==
Еще раз — для С++ лучше использовать сылки и не использовать указатели. В этом случае работать будет также быстро, но компилятор сам разберется что там перекрывается а что нет.
Re[4]: Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 15.09.21 14:54
Оценка:
Здравствуйте, Zhendos, Вы писали:

Z>Ну "volatile" память относительно редкое явление (имеется ввиду правильный

Z>вариант его применения, когда "volatile" испольуется для указания части
Z>которая может меняться не программой).

А какая разница, меняется оно железом, или параллельным потоком самой программы? Если логика правильная, то volatile корректно работает везде. Другое дело, что для программных изменений эффективнее барьеры, чтобы компилятор не делал кода, читающего переменную при каждом доступе.
Re[6]: Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 15.09.21 14:58
Оценка: +2
Здравствуйте, imh0, Вы писали:

I>Еще раз — для С++ лучше использовать сылки и не использовать указатели. В этом случае работать будет также быстро, но компилятор сам разберется что там перекрывается а что нет.


Если и ссылки, и указатели создаются в одном модуле, он и с указателями нередко разберется. А если приходят снаружи, то никакой разницы.
Re[3]: Как вышло, что наложение предполагается по умолчанию?
От: B0FEE664  
Дата: 15.09.21 15:00
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

Z>>если пользовать говорит что нафиг надежность, то он за это отвечает, что явно указано в коде.

ЕМ>Если программист отвечает за бОльшую часть кода — зачем заставлять его явно указывать это везде? Он мог бы указать, что в общем случае предположений делать не нужно, но в некоторых местах это будет явно отменено.

Т.е. если программист забыл отменить предположение об отмене наложения и получил очень странную, практически неуловимую ошибку, то его сразу призвать к ответу?

Правильно ли я понимаю, что под словом "некоторых" скрываются все стандартные алгоритмы из <algorithm>?

ЕМ>Придумали же давным-давно volatile, хотя могли бы объявить: раз какие-то переменные могут меняться извне текущего потока, то и никаких вам регистровых оптимизаций, только память.

Ага. А теперь volatile — deprecated. volatile имеет смысл только на однопроцессорной одноядерной архитектуре (что было давным давно), во всех остальных случаях это непонятно как работающая и что означающая конструкция.
И каждый день — без права на ошибку...
Re[5]: Как вышло, что наложение предполагается по умолчанию?
От: B0FEE664  
Дата: 15.09.21 15:06
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>А какая разница, меняется оно железом, или параллельным потоком самой программы? Если логика правильная, то volatile корректно работает везде. Другое дело, что для программных изменений эффективнее барьеры, чтобы компилятор не делал кода, читающего переменную при каждом доступе.


Это так, только если параллельный поток выполняется не параллельно, а последовательно. Для volatile нет гарантий атомарности.
И каждый день — без права на ошибку...
Re[4]: Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 15.09.21 15:36
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>если программист забыл отменить предположение об отмене наложения и получил очень странную, практически неуловимую ошибку, то его сразу призвать к ответу?


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

BFE>Правильно ли я понимаю, что под словом "некоторых" скрываются все стандартные алгоритмы из <algorithm>?


Положим, не все, но многие, да. Но много их лишь внутри <algorithm>, а в типичной программе — очень мало.

BFE>volatile имеет смысл только на однопроцессорной одноядерной архитектуре


Э-э-э... Когда железо меняет значение регистра в произвольные моменты времени — как это связано с количеством процессов/ядер, работающих с этим железом?
Re[6]: Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 15.09.21 15:37
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Для volatile нет гарантий атомарности.


А я что-то говорил за атомарность?
Re[2]: Как вышло, что наложение предполагается по умолчанию?
От: AndrewJD США  
Дата: 15.09.21 15:49
Оценка: +2
Здравствуйте, rg45, Вы писали:

R>Корректность программы всегда была выше по приоритету, чем производительность. А как иначе?


Да ладно, если бы это было так небыло бы баек про форматирование диска при доступе к нулевому указателю.
"For every complex problem, there is a solution that is simple, neat,
and wrong."
Re[4]: Как вышло, что наложение предполагается по умолчанию?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 15.09.21 17:12
Оценка:
Здравствуйте, B0FEE664, Вы писали:

ЕМ>>Придумали же давным-давно volatile, хотя могли бы объявить: раз какие-то переменные могут меняться извне текущего потока, то и никаких вам регистровых оптимизаций, только память.

BFE>Ага. А теперь volatile — deprecated. volatile имеет смысл только на однопроцессорной одноядерной архитектуре (что было давным давно), во всех остальных случаях это непонятно как работающая и что означающая конструкция.

Загляните например сюда. Все эти READ_ONCE, которые говорят "это чтение не кэшировать", сделаны внутри через volatile-указатель.

Да, оно не отменяет необходимость в явных барьерах. Но оно удобнее, чем делать какой-нибудь atomic_signal_fence на каждом углу, и эффективнее (действует точечно).
The God is real, unless declared integer.
Re[2]: Как вышло, что наложение предполагается по умолчанию?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 15.09.21 17:20
Оценка: +1
Здравствуйте, watchmaker, Вы писали:

W>Если бы можно было переделать С++ с нуля, то в него можно было бы добавить десяток quality-of-life улучшений, которые бы не изменили принципиально язык, но немедленно бы сделали его более быстрым, простым и надёжным. Сюда не только вошли бы более разумные правила на aliasing, но и такие вещи как move для всех типов по умолчанию, менее безумные правила octal-literals (когда одна цифра в числе меняет систему счисления), быстрые строки (с длиной, а не null-terminated), отсутствие неявных преобразований (как литеральный 0 в указатель) и т.п.


Это всё как раз можно и сейчас без коренной ломки, банальными мерами нужна только воля стандартизаторов. Типа так: шаг 1 — вводится поддержка "#pragma STDC good_octal on" в стандарт. Шаг 2 — основные компиляторы это сделали. Шаг 3 — вводится правило в стандарты типа MISRA. Лет 10 на полный цикл, да. Но — возможно.
Аналогично прагмами или [[контекстными пометками]] можно задать правила арифметики, алиасинга, работы с пустыми указателями, усиление типизации, и прочая и прочая.
Кстати, "быстрые строки" в виде "qwerty"sv есть в C++17.

А вот переделать синтаксис, чтобы было не int (*foo)(int), вот это уже сложнее — поддерживать десятилетями оба синтаксиса впараллель — легче таки новый язык создать.

W>2. Если делать правильно и переделать всё кардинально, то потеряется совместимость с предыдущим кодом, и такой язык сильно потеряет в привлекательности — кому нужен язык, если нельзя использовать многочисленные наработки, а нужно всё переписывать под него заново? Нужно очень сильно вложится, чтобы сделать такой язык популярным.


Ну вот всё что ты предлагаешь — не ломает прямую совместимость. Обратную ломает, но она и так ломается с каждым новым стандартом, поэтому не страшно.
The God is real, unless declared integer.
Re[2]: Как вышло, что наложение предполагается по умолчанию?
От: T4r4sB Россия  
Дата: 15.09.21 18:01
Оценка: :)
Здравствуйте, watchmaker, Вы писали:


W>Если бы можно было переделать С++ с нуля, то в него можно было бы добавить десяток quality-of-life улучшений, которые бы не изменили принципиально язык, но немедленно бы сделали его более быстрым, простым и надёжным. Сюда не только вошли бы более разумные правила на aliasing, но и такие вещи как move для всех типов по умолчанию, менее безумные правила octal-literals (когда одна цифра в числе меняет систему счисления), быстрые строки (с длиной, а не null-terminated), отсутствие неявных преобразований (как литеральный 0 в указатель) и т.п.


А ещё борроу-чекер, пугающий синтаксис с Vec::<String>, упоротые правила мутабельных ссылок, вычисление типа переменной в обе стороны и ну ты понял, на кого я намекаю. И знаешь, это тоже по итогу весьма спорно и не всегда очевидно, помогает вся эта фигня или мешает
Re[3]: Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 15.09.21 19:00
Оценка:
Здравствуйте, netch80, Вы писали:

N>Это всё как раз можно и сейчас без коренной ломки, банальными мерами нужна только воля стандартизаторов.


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

Так что нет особых оснований ожидать от языка подвижек в сторону удобства программирования, близкого к железу. Язык движется в сторону какого-нибудь Fortran-77, Algol-68 и подобного.
Re[3]: Как вышло, что наложение предполагается по умолчанию?
От: rg45 СССР  
Дата: 15.09.21 19:42
Оценка:
Здравствуйте, AndrewJD, Вы писали:

R>Корректность программы всегда была выше по приоритету, чем производительность. А как иначе?


AJD>Да ладно, если бы это было так небыло бы баек про форматирование диска при доступе к нулевому указателю.


Да но при этом четко сказано что доступ к памяти по нулевому указателю порождает неопределенное поведение. И если пользователь это делает, то он ССЗБ. Тогда как в рассматриваемом случае ответственность за корректность работы программы полностью лежит на компиляторе.

Ну то есть, я имел в виду корректность лишь в зоне ответственности компилятора, которая достаточно четко очерчена.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 15.09.2021 20:40 rg45 . Предыдущая версия . Еще …
Отредактировано 15.09.2021 20:25 rg45 . Предыдущая версия .
Re[7]: Как вышло, что наложение предполагается по умолчанию?
От: B0FEE664  
Дата: 16.09.21 08:21
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

BFE>>Для volatile нет гарантий атомарности.

ЕМ>А я что-то говорил за атомарность?

В том-то и дело, что нет.
И каждый день — без права на ошибку...
Re[5]: Как вышло, что наложение предполагается по умолчанию?
От: B0FEE664  
Дата: 16.09.21 08:48
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

BFE>>если программист забыл отменить предположение об отмене наложения и получил очень странную, практически неуловимую ошибку, то его сразу призвать к ответу?

ЕМ>Если перечислять ситуации, в которых программист что-то забыл, и получил странную ошибку, то мы очень быстро устанем.
Если последовательно применять best practice, то никаких странных ошибок не возникает.

ЕМ>А еще может быть, что программист явно указал отсутствие наложение, а через месяц или год изменил алгоритм так, что наложение возникло, но квалификатор убрать забыл. На все такие варианты соломы не напасешься.

Это почему же нет? Нет квалификатора — нет проблемы.

BFE>>Правильно ли я понимаю, что под словом "некоторых" скрываются все стандартные алгоритмы из <algorithm>?

ЕМ>Положим, не все, но многие, да. Но много их лишь внутри <algorithm>, а в типичной программе — очень мало.
В типичной программе всё очень похоже на функции из algorithm.

BFE>>volatile имеет смысл только на однопроцессорной одноядерной архитектуре

ЕМ>Э-э-э... Когда железо меняет значение регистра в произвольные моменты времени — как это связано с количеством процессов/ядер, работающих с этим железом?
Вот, допустим, программа читает 32-х битное значение в переменную из регистра, прочитала первые два байта и тут железо меняет значение регистра, поэтому прочтение третьего и четвёртого байта будут взяты от уже изменённого значения. Всё ведь так и задумано? Да?
И каждый день — без права на ошибку...
Re[8]: Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 16.09.21 09:02
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>>>Для volatile нет гарантий атомарности.

ЕМ>>А я что-то говорил за атомарность?

BFE>В том-то и дело, что нет.


Тогда в чем проблема? Атомарность требуется не всегда. Например, если потоку нужно сообщить другим потокам, что произошло некое событие (а не будить их из спячки), нередко достаточно просто установить значение переменной, снабдив ее volatile для надежного считывания из памяти. Или, когда один поток формирует даннне, а другой по таймеру отображает их в GUI, атомарность требуется только для связанных значений. Отдельные достаточно просто класть в память, а volatile указывается, чтобы операции считывания не выносились из цикла.
Re[6]: Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 16.09.21 09:30
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Вот, допустим, программа читает 32-х битное значение в переменную из регистра, прочитала первые два байта и тут железо меняет значение регистра, поэтому прочтение третьего и четвёртого байта будут взяты от уже изменённого значения.


Какая здесь связь с многопроцессорностью/многоядерностью? Такое возможно даже на 8-разрядных архитектурах, если флаги в регистрах выставляются асинхронно. Для борьбы с этим есть ряд способов, которые Вам должны быть известны.
Re[9]: Как вышло, что наложение предполагается по умолчанию?
От: B0FEE664  
Дата: 16.09.21 09:48
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

BFE>>>>Для volatile нет гарантий атомарности.

ЕМ>>>А я что-то говорил за атомарность?
BFE>>В том-то и дело, что нет.

ЕМ>Тогда в чем проблема? Атомарность требуется не всегда. Например, если потоку нужно сообщить другим потокам, что произошло некое событие (а не будить их из спячки), нередко достаточно просто установить значение переменной, снабдив ее volatile для надежного считывания из памяти. Или, когда один поток формирует даннне, а другой по таймеру отображает их в GUI, атомарность требуется только для связанных значений. Отдельные достаточно просто класть в память, а volatile указывается, чтобы операции считывания не выносились из цикла.


Так как нет гарантий, что операции чтения атомарны (даже для одного байта) и если "один поток формирует даннне, а другой по таймеру отображает их в GUI", то нет гарантий, что отображаемые данные в GUI отображают реальные значения. Более того, как вы понимаете, если есть два значения и операции над ними атомарны, тогда при отображении эти значений в GUI нет никаких гарантий их согласованности. Скажем строка принимающая два значения "OK" или "КО" в GUI может отобразится как "OO", "OK", "KO" или "KK". Т.е. нет никакого смысла передавать более одного данного из потока в поток таким способом.
И каждый день — без права на ошибку...
Re[7]: Как вышло, что наложение предполагается по умолчанию?
От: B0FEE664  
Дата: 16.09.21 10:03
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

BFE>>Вот, допустим, программа читает 32-х битное значение в переменную из регистра, прочитала первые два байта и тут железо меняет значение регистра, поэтому прочтение третьего и четвёртого байта будут взяты от уже изменённого значения.


ЕМ>Какая здесь связь с многопроцессорностью/многоядерностью?

Изначально речь шла про память, а не про регистры.

ЕМ>Такое возможно даже на 8-разрядных архитектурах, если флаги в регистрах выставляются асинхронно. Для борьбы с этим есть ряд способов, которые Вам должны быть известны.

Насколько мне известно, на всех архитектурах все мне известные способы сводятся ровно к одному — к разнесению по времени операций чтения и записи. А чем это в сути своей отличается от однопроцессорности?
И каждый день — без права на ошибку...
Re[10]: Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 16.09.21 13:22
Оценка: :)
Здравствуйте, B0FEE664, Вы писали:

BFE>Так как нет гарантий, что операции чтения атомарны (даже для одного байта)


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

BFE>если есть два значения и операции над ними атомарны, тогда при отображении эти значений в GUI нет никаких гарантий их согласованности.


Если обновление GUI не затрагивает его структуры (например, все отображается на одних и тех же местах), и это обновление происходит достаточно часто (хотя бы несколько раз в секунду), то и ладно. Ну, мелькнет иногда неправильное значение в одном из полей на долю секунды, и что с того? Не тот случай, чтобы заморачиваться со всеобщей атомарностью.

BFE>Скажем строка принимающая два значения "OK" или "КО" в GUI может отобразится как "OO", "OK", "KO" или "KK". Т.е. нет никакого смысла передавать более одного данного из потока в поток таким способом.


Может, смысла и нет, а я всю жизнь передаю, и отлично работает, ни разу не жаловались.
Re[8]: Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 16.09.21 14:33
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Изначально речь шла про память, а не про регистры.


Чем регистры любого контроллера, отображенные на адресное пространство, отличаются от памяти с точки зрения программы?

ЕМ>>Такое возможно даже на 8-разрядных архитектурах, если флаги в регистрах выставляются асинхронно.

BFE>Насколько мне известно, на всех архитектурах все мне известные способы сводятся ровно к одному — к разнесению по времени операций чтения и записи.

Операции чтения и записи физически не могут быть одновременными — их разносит, как минимум, сама аппаратура. Или о чем Вы?

BFE>А чем это в сути своей отличается от однопроцессорности?


А чем двухпроцессорная система, в которой параллельные потоки обмениваются данными через общую память, отличается от однопроцессорной, где поток обменивается данными с контроллером, фактически представляющим собой независимый процессор?
Re[11]: Как вышло, что наложение предполагается по умолчанию?
От: TailWind  
Дата: 16.09.21 15:36
Оценка:
BFE>>Так как нет гарантий, что операции чтения атомарны (даже для одного байта)

ЕМ>Где их нет? Для большинства конкретных архитектур они как раз есть. А задача сделать надежную программу для абстрактной, заранее неизвестной архитектуры, напоминает анекдот о сферической лошади в вакууме.


Про один байт можете быть совершенно спокойны

Микросхема памяти имеет только один порт. Более того минимальная единица записи — 1 байт

Писать и читать можно только по очереди, а не одновременно
Поэтому никто не сможет изменить часть бит, пока вы читаете
Никак не сможет получится, что вы считали байт, в котором часть бит от нового значения, а часть от старого
Целостность байта нарушить не получится
Re[12]: Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 16.09.21 15:48
Оценка:
Здравствуйте, TailWind, Вы писали:

TW>Микросхема памяти имеет только один порт. Более того минимальная единица записи — 1 байт


Какие архитектуры мы обсуждаем? Если сферические в вакууме, то микросхемы памяти бывают и одно-, и четырех-, и восьми-битовыми, и более широкими. А синхронизация чтения/записи определяется не битностью отдельных микросхем, а подаваемым на них синхросигналом. Так что можно построить архитектуру, где чтение и запись осуществляются побитно.

В реальных же архитектурах разрядность памяти стараются делать равной разрядности магистрали. Если читается/пишется не полное слово, то на магистрали указывается, какие части будут участвовать, а какие нет (обычно это делается на уровне байтов, но так просто удобнее — можно управлять группами любой разрядности).

TW>Поэтому никто не сможет изменить часть бит, пока вы читаете


Если сделать архитектуру с побитной адресацией — легко. А на нормальных современных всегда гарантируется атомарность чтения/записи в пределах ширины магистрали (общей или процессора, если его магистраль Уже магистрали памяти).
Re[13]: Как вышло, что наложение предполагается по умолчанию?
От: TailWind  
Дата: 16.09.21 16:41
Оценка:
ЕМ>В реальных же архитектурах разрядность памяти стараются делать равной разрядности магистрали. Если читается/пишется не полное слово, то на магистрали указывается, какие части будут участвовать, а какие нет (обычно это делается на уровне байтов, но так просто удобнее — можно управлять группами любой разрядности).

Не в разрядности дело
У нас адрес может указывать только на байт.
Поэтому битовые операции невозможны на аппаратном уровне
Re[14]: Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 16.09.21 18:08
Оценка: +1
Здравствуйте, TailWind, Вы писали:

TW>У нас адрес может указывать только на байт.


Тогда к чему все это пережевывание? На реальной архитектуре байт по определению атомарен. Поля, выровненные по ширине магистрали, тоже атомарны. О чем спич?
Re[4]: Как вышло, что наложение предполагается по умолчанию?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 17.09.21 06:52
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>У меня уже давно стойкое впечатление, что среди стандартизаторов преобладают сторонники понимания сути программирования, как процесса подбора освященных стандартом и мэтрами конструкций, в результате чего на выходе программы получается требуемый результат. При таком подходе от программиста не требуется понимания того, что именно будет делать железо по его программе — достаточно лишь, чтобы результат получался верным. Сторонники сохранения преемственности с Си из комитета постепенно вымываются (или выживаются).


Ну в общем-то именно так, и это неизбежное логичное развитие в современном мире.
Задачи "вывести 1 в порт" стали 0.001% от всех задач. Основные это таки что-то очень высокоуровневое.

Но это таки не мешает тому, что я предлагаю.

ЕМ>Так что нет особых оснований ожидать от языка подвижек в сторону удобства программирования, близкого к железу.


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

Но, да, даже attribute((packed)) пока не стандартизировали. В отличие даже от C#, где StructLayout в стандарте и позволяет сказать про точность до байтика.

А я хотел бы от этих средств даже больше — например, сказать

[[packed, bigendian]]
struct iphdr
  {
    unsigned int version:4;
    unsigned int ihl:4;
    uint8_t tos;
    uint16_t tot_len;
    uint16_t id;
    unsigned reserved:1;
    unsigned dont_fragment:1;
    unsigned more_fragments:1;
    unsigned frag_off:13;
    uint8_t ttl;
    uint8_t protocol;
    uint16_t check;
    uint32_t saddr;
    uint32_t daddr;
    /*The options start here. */
  };


и чтобы указание bigendian работало, как положено, на то, что version будет в старших битах байта по смещению 0, а не младших, как сработает автоматом на x86.
The God is real, unless declared integer.
Отредактировано 17.09.2021 6:58 netch80 . Предыдущая версия .
Re[5]: Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 17.09.21 09:23
Оценка:
Здравствуйте, netch80, Вы писали:

N>Задачи "вывести 1 в порт" стали 0.001% от всех задач. Основные это таки что-то очень высокоуровневое.


Да не в портах дело. Чем отличается типичный физик или инженер от типичного математика? У физика и инженера хорошо развито чувство адекватности, сообразности. Если установка, которую предполагается использовать мобильно, получается весом под сто тонн — у них автоматически срабатывает триггер, что это абсурдно. А у математика такого триггера нет: задача решена, и ладно.

Вот у меня телефон 2016-го года на Qualcomm Snapdragon 650. Шесть ядер в среднем по полтора гигагерца. Google Services на нем изначально работали достаточно быстро. А сейчас, когда я тапаю на Update All в списке обновлений, проходит семь-восемь секунд до того, как кнопка Update All превратится в Cancel All. Все это время экран сохраняет прежний вид, и я даже не знаю, сработал мой тап, или нет. Восемь секунд, Карл! На полутора гигагерцах и шести ядрах! Что нужно курить, чтобы так сделать? Я не знаю. Это возможно лишь путем "последовательной записи конструкций языка, в итоге приводящих к решению поставленной задачи". Программированием в его исходном понимании это назвать невозможно.

N>и чтобы указание bigendian работало, как положено, на то, что version будет в старших битах байта по смещению 0


Хм, а какой в этом может быть смысл? Где такое может пригодиться?
Re[6]: Как вышло, что наложение предполагается по умолчанию?
От: _NN_ www.nemerleweb.com
Дата: 17.09.21 14:59
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Хм, а какой в этом может быть смысл? Где такое может пригодиться?


Сетевые протоколы. Как бы название структуры намекает
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[9]: Как вышло, что наложение предполагается по умолчанию?
От: B0FEE664  
Дата: 17.09.21 16:04
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

BFE>>Изначально речь шла про память, а не про регистры.

ЕМ>Чем регистры любого контроллера, отображенные на адресное пространство, отличаются от памяти с точки зрения программы?
Не знаю, никогда не работал с отображением.

ЕМ>>>Такое возможно даже на 8-разрядных архитектурах, если флаги в регистрах выставляются асинхронно.

BFE>>Насколько мне известно, на всех архитектурах все мне известные способы сводятся ровно к одному — к разнесению по времени операций чтения и записи.
ЕМ>Операции чтения и записи физически не могут быть одновременными — их разносит, как минимум, сама аппаратура. Или о чем Вы?
Во-первых, физически возможно сделать одновременное чтение и запись (стирание). Если не говорить о самой физике, то можно так: берём две ячейки и рассматриваем её как одну. Пишем в одну ячейку — читаем из другой, по окончании записи — перенаправляем следующие чтение на записанную ячейку, а запись — на прочитанную. Но я не об этом, а всё о том же, о синхронизации двух и более данных.

BFE>>А чем это в сути своей отличается от однопроцессорности?

ЕМ>А чем двухпроцессорная система, в которой параллельные потоки обмениваются данными через общую память, отличается от однопроцессорной, где поток обменивается данными с контроллером, фактически представляющим собой независимый процессор?

Вроде бы ничем.
И каждый день — без права на ошибку...
Re[11]: Как вышло, что наложение предполагается по умолчанию?
От: B0FEE664  
Дата: 17.09.21 16:15
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

BFE>>Так как нет гарантий, что операции чтения атомарны (даже для одного байта)

ЕМ>Где их нет?
В стандарте.

ЕМ>Для большинства конкретных архитектур они как раз есть.

Знаете почему? А потому, что многие не умеют в параллельность.

ЕМ>А задача сделать надежную программу для абстрактной, заранее неизвестной архитектуры, напоминает анекдот о сферической лошади в вакууме.

Только вот в отличии от анекдотов, в жизни, программы написанные по правилам стандарта проще изменять и работают они быстрее.

BFE>>если есть два значения и операции над ними атомарны, тогда при отображении эти значений в GUI нет никаких гарантий их согласованности.

ЕМ>Если обновление GUI не затрагивает его структуры (например, все отображается на одних и тех же местах), и это обновление происходит достаточно часто (хотя бы несколько раз в секунду), то и ладно. Ну, мелькнет иногда неправильное значение в одном из полей на долю секунды, и что с того? Не тот случай, чтобы заморачиваться со всеобщей атомарностью.

И это вы называете надёжностью?

BFE>>Скажем строка принимающая два значения "OK" или "КО" в GUI может отобразится как "OO", "OK", "KO" или "KK". Т.е. нет никакого смысла передавать более одного данного из потока в поток таким способом.

ЕМ>Может, смысла и нет, а я всю жизнь передаю, и отлично работает, ни разу не жаловались.

Хмм... Точно не жаловались? Вот возьмём, к примеру, известную бухгалтерскую программу Horizon...
И каждый день — без права на ошибку...
Re[7]: Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 17.09.21 19:04
Оценка:
Здравствуйте, _NN_, Вы писали:

ЕМ>>Где такое может пригодиться?


_NN>Сетевые протоколы.


А такое точно будет работать хотя бы не медленнее, чем обычная структура с "местным" порядком байтов, с переворотом после после получения и перед отправкой? Я несколько раз пробовал баловаться в C/C++ с битовыми полями — код получается страшноватый. Для предельной экономии памяти годится, для быстродействия — уже нет.
Re[10]: Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 17.09.21 19:12
Оценка:
Здравствуйте, B0FEE664, Вы писали:

ЕМ>>Чем регистры любого контроллера, отображенные на адресное пространство, отличаются от памяти с точки зрения программы?


BFE>Не знаю, никогда не работал с отображением.


В общем случае, программа вообще никак не может отличить обычную память от регистров, отображенных на АП. И там, и там при обращении выполняются стандартные магистральные циклы.

BFE>физически возможно сделать одновременное чтение и запись (стирание).


Понятно, что возможно, но это сделано фактически на какой-либо архитектуре, для которой есть компиляторы C/C++?

ЕМ>>А чем двухпроцессорная система, в которой параллельные потоки обмениваются данными через общую память, отличается от однопроцессорной, где поток обменивается данными с контроллером, фактически представляющим собой независимый процессор?


BFE>Вроде бы ничем.


Вот именно. Но и в однопроцессорных системах легко делается обмен данными с любым контроллером так, чтобы не возникало гонок, блокировок и прочего. Атомарность операций (кроме банальных чтения и записи) для этого не нужна.
Re[8]: Как вышло, что наложение предполагается по умолчанию?
От: _NN_ www.nemerleweb.com
Дата: 18.09.21 04:47
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Здравствуйте, _NN_, Вы писали:


ЕМ>>>Где такое может пригодиться?


_NN>>Сетевые протоколы.


ЕМ>А такое точно будет работать хотя бы не медленнее, чем обычная структура с "местным" порядком байтов, с переворотом после после получения и перед отправкой? Я несколько раз пробовал баловаться в C/C++ с битовыми полями — код получается страшноватый. Для предельной экономии памяти годится, для быстродействия — уже нет.


Ну я уточнил, что хотел автор.
Конечно может ударить по производительности.
С другой стороны функции сокетов итак работают с сетевым порядком байтов и ничего делать для них не нужно.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[12]: Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 18.09.21 09:23
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>>>Так как нет гарантий, что операции чтения атомарны (даже для одного байта)

ЕМ>>Где их нет?
BFE>В стандарте.

В стандарте нет и того, что при определенной комбинации значений в памяти на программу может возбудиться системный антивирус. Что с этим делать? Программа полностью соответствует стандарту, но фактически не работает.

ЕМ>>Для большинства конкретных архитектур они как раз есть.


BFE>Знаете почему? А потому, что многие не умеют в параллельность.


Да многие вообще не умеют ничего, кроме как записывать конструкции языка из справочника или подходящего примера. К сожалению, стандарт нынче делается прежде всего для них. Но подозреваю, что изучить тот же C++20 досконально, чтобы помнить каждую мелочь и писать абсолютно переносимые программы, таки будет сложнее, чем добиться удовлетворительной практической переносимости, пользуясь спецификациями 90-х.

BFE>программы написанные по правилам стандарта проще изменять


Только при условии всеобъемлющего знания стандарта, когда любой нюанс помнишь или навскидку, или можешь быстро и уверенно найти по тексту. Какая доля современных программистов так может?

BFE>и работают они быстрее.


На каком основании? Ряд ограничений стандарта, угрожающих UB при их нарушении, на большинстве архитектур фактически нет нужды соблюдать, и можно сделать более эффективный код.

ЕМ>>Если обновление GUI не затрагивает его структуры (например, все отображается на одних и тех же местах), и это обновление происходит достаточно часто (хотя бы несколько раз в секунду), то и ладно. Ну, мелькнет иногда неправильное значение в одном из полей на долю секунды, и что с того? Не тот случай, чтобы заморачиваться со всеобщей атомарностью.


BFE>И это вы называете надёжностью?


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

BFE>Точно не жаловались?


Мои — точно.

BFE>Вот возьмём, к примеру, известную бухгалтерскую программу Horizon...


Ну, я ее не делал, и вообще впервые о ней слышу.
Re[6]: Как вышло, что наложение предполагается по умолчанию?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 19.09.21 06:23
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

N>>Задачи "вывести 1 в порт" стали 0.001% от всех задач. Основные это таки что-то очень высокоуровневое.


ЕМ>Да не в портах дело. Чем отличается типичный физик или инженер от типичного математика? У физика и инженера хорошо развито чувство адекватности, сообразности. Если установка, которую предполагается использовать мобильно, получается весом под сто тонн — у них автоматически срабатывает триггер, что это абсурдно. А у математика такого триггера нет: задача решена, и ладно.


Это потому ты так пишешь, что путаешь чистого математика с прикладным. Чистый действительно думает в терминах "задача решена, дальше не волнует". Прикладной ещё и понимает цену решения.
Задача выбора правильного подмножества прикладной математики для обучения на "инженера-программиста", как тут предложили, сложна, но решается. Типовой курс содержит, например, оценки скорости сходимости разных методов численного интегрирования. Это уже хотя бы намёк на то, что надо смотреть на количественные характеристики.

ЕМ>Вот у меня телефон 2016-го года на Qualcomm Snapdragon 650. Шесть ядер в среднем по полтора гигагерца. Google Services на нем изначально работали достаточно быстро. А сейчас, когда я тапаю на Update All в списке обновлений, проходит семь-восемь секунд до того, как кнопка Update All превратится в Cancel All. Все это время экран сохраняет прежний вид, и я даже не знаю, сработал мой тап, или нет. Восемь секунд, Карл! На полутора гигагерцах и шести ядрах! Что нужно курить, чтобы так сделать? Я не знаю. Это возможно лишь путем "последовательной записи конструкций языка, в итоге приводящих к решению поставленной задачи". Программированием в его исходном понимании это назвать невозможно.


Вполне возможно, что там вообще проблема не в программировании, а в управлении. Я не знаю конкретно тут причину. Но я знаю аналогичные случаи. Например, есть заявка решить проблему. Програмисты решают, уточняя в документации: "тут O(N^3), не расширяйте тут слишком сильно". Кто-то в менеджменте плюёт и даёт 1000 входных значений вместо ожидаемого предела 10. Кто виноват?
Ну да, можно сказать, что раз менеджмент был от программирования, то это программирование. Но IMHO это таки кривой менеджмент.

N>>и чтобы указание bigendian работало, как положено, на то, что version будет в старших битах байта по смещению 0


ЕМ>Хм, а какой в этом может быть смысл? Где такое может пригодиться?


Это был пример на заголовок IPv4 пакета. Там ровно эта проблема — порядок битов (даже не байтов). Сейчас из-за отсутствия таких определений приходится писать так:

struct iphdr
  {
#if __BYTE_ORDER == __LITTLE_ENDIAN
    unsigned int ihl:4;
    unsigned int version:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
    unsigned int version:4;
    unsigned int ihl:4;
#else
# error "Please fix <bits/endian.h>"
#endif


ну и далее по тексту.

Мало того, в IPv6 ещё злобнее получилось — поле flow label занимает в BE нумерации биты 12-31 (не знаю, нафига им столько), и если смотреть по байтам или шекам, то на LE машине оно разорвано на два несвязанных куска.
The God is real, unless declared integer.
Re[6]: Как вышло, что наложение предполагается по умолчанию?
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 19.09.21 06:26
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Да не в портах дело. Чем отличается типичный физик или инженер от типичного математика? У физика и инженера хорошо развито чувство адекватности, сообразности. Если установка, которую предполагается использовать мобильно, получается весом под сто тонн — у них автоматически срабатывает триггер, что это абсурдно. А у математика такого триггера нет: задача решена, и ладно.


Оффтоп, конечно.

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

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

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

Хотя, если взять систему управления сделок с недвижимостью, которую я спроектировал в начале нулевых — там походу было наоброт. Ресурсов было реально мало и надо было исхитрится так, чтобы сократить объем работ и таки суметь довести проект конца.

Возможно не последнюю роль сыграли навыки приобретенные при решении математических задач ... ну правда не в ВУЗе, а в школе. Был там у меня особо тяжелый период борьбы с собственной тупостью

UPD. И кстати. Сейчас когда обнаруживаю проблемы/нестыковки в окружении, с которым приходится работать, все чаще думаю "да пусть они в #овне утонут со своими 'реальными' задачами.".
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Отредактировано 19.09.2021 6:38 DDDX . Предыдущая версия . Еще …
Отредактировано 19.09.2021 6:27 DDDX . Предыдущая версия .
Re[8]: Как вышло, что наложение предполагается по умолчанию?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 19.09.21 06:57
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

_NN>>Сетевые протоколы.


ЕМ>А такое точно будет работать хотя бы не медленнее, чем обычная структура с "местным" порядком байтов, с переворотом после после получения и перед отправкой?


Ты имеешь в виду то, что поле какого-то полного размера (2, 4, 8 байт) хранится постоянно в памяти в чужом порядке (обычно — в BE при машине в LE; обратный вариант крайне редок) и переворачивается при чтении или записи?

Последние лет 10 на x86 практически во всех процессорах есть инструкция MOVBE — для чтения/записи именно памяти. Ещё с 486-го была BSWAP над регистром. Поэтому тут оно происходит на полной скорости без задержки. Для ARM нужна дополнительная REV между регистрами, это затянет ну ещё один такт в самом тяжёлом случае (часто и без него). В общем, дёшево.

Но я имел в виду не столько оптимизацию или её отсутствие, сколько переносимость описания. И обрати внимание, что первая пара значений — в одном байте. Ты там вообще переворотом порядка байт ничего не добьёшься. Если не иметь таких тегов и не делать зависимости от дефайна — читать/писать можно только явными смещениями и масками. Да, работает. Но неудобно.

EM> Я несколько раз пробовал баловаться в C/C++ с битовыми полями — код получается страшноватый. Для предельной экономии памяти годится, для быстродействия — уже нет.


Может, это проблема MSVC. А ещё это проблема x86. Хороший пример — представление float:
typedef struct sfloat32 {
  unsigned significand : 23;
  unsigned exponent : 8;
  unsigned sign : 1;
} sfloat32;
sfloat32 insert_exponent(sfloat32 input, unsigned new_exponent) {
  input.exponent = new_exponent;
  return input;
}


Обычная сборка gcc9 для x86 (Unix конвенция, первый параметр в di):

insert_exponent:
        movzx   eax, sil
        and     edi, -2139095041
        sal     eax, 23
        or      eax, edi
        ret


ну не так страшно — сдвиг и маска. Хотя можно было оптимизировать до двух rol и копирования sil. А вот смотрим на ARM:

insert_exponent:
        bfi     w0, w1, 23, 8
        ret


ну да, работает только для константных позиций, но таких случаев реально >99.9%.

Не знаю, что ты там видел в MSVC, может, страшнее в разы. Но вообще по сравнению с прочими операциями над данными в этих полях — почти ерунда.
The God is real, unless declared integer.
Re[6]: Как вышло, что наложение предполагается по умолчанию?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 19.09.21 07:17
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>>>volatile имеет смысл только на однопроцессорной одноядерной архитектуре

ЕМ>>Э-э-э... Когда железо меняет значение регистра в произвольные моменты времени — как это связано с количеством процессов/ядер, работающих с этим железом?
BFE>Вот, допустим, программа читает 32-х битное значение в переменную из регистра, прочитала первые два байта и тут железо меняет значение регистра, поэтому прочтение третьего и четвёртого байта будут взяты от уже изменённого значения. Всё ведь так и задумано? Да?

Для таких архитектур всегда есть гарантии от производителей, типа: "операции чтения и записи порциями по 1, 2, 4, 8 байт, выполняемые на соответствующих границах, атомарны".
Как именно это обеспечивает архитектура — её дело. В типичном варианте это достигается за счёт кэша. Но это не обязательно.

Гарантии атомарности чтения/записи у атомарных переменных (грубо говоря, atomic<T> в C++) уже основаны на этих гарантиях архитектуры, а не наоборот. (Но это не выполняется для более широких типов — там подложка может хоть мьютексами обеспечивать атомарность.)

И с volatile в компиляторе это никак не связано. volatile не создаёт атомарность — оно запрещает кэшировать чтение и запись подобной переменной на уровне самого компилятора.
The God is real, unless declared integer.
Re[9]: Как вышло, что наложение предполагается по умолчанию?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 19.09.21 07:20
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

BFE>>Изначально речь шла про память, а не про регистры.


ЕМ>Чем регистры любого контроллера, отображенные на адресное пространство, отличаются от памяти с точки зрения программы?


На уровне C/C++ ты вообще отображённые на память регистры (если это те регистры процессора, в которые компилятор кладёт рабочие данные) не влазят в основную концепцию и с ними работать нельзя, если не понимаешь всех последствий.

ЕМ>>>Такое возможно даже на 8-разрядных архитектурах, если флаги в регистрах выставляются асинхронно.

BFE>>Насколько мне известно, на всех архитектурах все мне известные способы сводятся ровно к одному — к разнесению по времени операций чтения и записи.

ЕМ>Операции чтения и записи физически не могут быть одновременными — их разносит, как минимум, сама аппаратура. Или о чем Вы?


Ну может и не разнести, если, например, у регистра есть порт чтения и порт записи, и доступ идёт одновременно. Это тот случай, который был, например, с PIIX timer.

BFE>>А чем это в сути своей отличается от однопроцессорности?


ЕМ>А чем двухпроцессорная система, в которой параллельные потоки обмениваются данными через общую память, отличается от однопроцессорной, где поток обменивается данными с контроллером, фактически представляющим собой независимый процессор?


Тем, что нет причин делать синхронизацию в памяти? Или как? Тут сложно понять вопрос.
The God is real, unless declared integer.
Re[8]: Как вышло, что наложение предполагается по умолчанию?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 19.09.21 07:34
Оценка: 3 (2)
Здравствуйте, B0FEE664, Вы писали:

ЕМ>>Такое возможно даже на 8-разрядных архитектурах, если флаги в регистрах выставляются асинхронно. Для борьбы с этим есть ряд способов, которые Вам должны быть известны.

BFE>Насколько мне известно, на всех архитектурах все мне известные способы сводятся ровно к одному — к разнесению по времени операций чтения и записи. А чем это в сути своей отличается от однопроцессорности?

Речь немного о другом, насколько я понимаю.
Вот в какой-то момент Intel ввёл в своих чипсетах PIIX timer (позже был назван ACPI-fast). Это 4 байта по некоторому адресу, которые значение счётчика с частотой 1/4 таймерного кварца (3579545.5 Гц), в коротком варианте валидны только 24 бита, в полном — 32.
Но на чтение из этого таймера они не поставили защёлку, а волна переворотов битов идёт медленно, поэтому возможны, например, такие ситуации:
— в какой-то момент значение 7 (0111 в двоичке)
— пришёл сигнал "добавить 1", пошла волна переворотов, младший бит перевернулся, следующий — ещё нет
— тут процессор читает таймер, видит значение 6 (0110)
— волна доходит дальше, в таймере 4 (0100)
— волна доходит дальше, в таймере 0 (0000)
— волна доходит дальше, в таймере 8 (1000), волна остановилась.

Соответственно, если процессор прочитал в неподходящий момент, он увидит явное "не то".
Защита чисто программная и выглядит так: читаем не один раз, а 3 подряд. Пусть прочли x1, x2, x3. Если x1 <= x2 <= x3, чтение было корректно и возвращаем x3. Иначе идём на следующий круг.

В следующем варианте "ACPI-safe" есть защёлка (дополнительный регистр, в который, в простейшем варианте, переписывается значение счётчика в противофазе — например, если инкремент происходит по фронту, то запись в защёлку — по спаду; возможно также делать пред-запись увеличенного значения). Там таких проблем нет. Какой вариант таймера доступен — читается в таблицах ACPI. В HPET защёлки декларированы изначально, в TSC — тоже.

Аналогичная проблема возникает, например, при чтении 64-битного значения двумя 32-битными операциями. Можно сделать так: прочитать дважды и сравнить две пары чисел, если где-то расхождение, то чтение было неатомарно, потому что кто-то влез посредине.
The God is real, unless declared integer.
Re[6]: Как вышло, что наложение предполагается по умолчанию?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 19.09.21 07:39
Оценка:
Здравствуйте, B0FEE664, Вы писали:

ЕМ>>А еще может быть, что программист явно указал отсутствие наложение, а через месяц или год изменил алгоритм так, что наложение возникло, но квалификатор убрать забыл. На все такие варианты соломы не напасешься.

BFE>Это почему же нет? Нет квалификатора — нет проблемы.

Как раз проблема в том, что квалификатор restrict остался, когда не должен был оставаться.

Поймать такую проблему, да, сложно — только глубоким анализом кода.
The God is real, unless declared integer.
Re[12]: Как вышло, что наложение предполагается по умолчанию?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 19.09.21 07:46
Оценка:
Здравствуйте, TailWind, Вы писали:

BFE>>>Так как нет гарантий, что операции чтения атомарны (даже для одного байта)


ЕМ>>Где их нет? Для большинства конкретных архитектур они как раз есть. А задача сделать надежную программу для абстрактной, заранее неизвестной архитектуры, напоминает анекдот о сферической лошади в вакууме.


TW>Про один байт можете быть совершенно спокойны


TW>Микросхема памяти имеет только один порт. Более того минимальная единица записи — 1 байт


TW>Писать и читать можно только по очереди, а не одновременно

TW>Поэтому никто не сможет изменить часть бит, пока вы читаете
TW>Никак не сможет получится, что вы считали байт, в котором часть бит от нового значения, а часть от старого
TW>Целостность байта нарушить не получится

Для обычной памяти — да, так. (На самом деле, стандартные модули DRAM давно уже оперируют порциями в 8 байт. Кэш в x86 — 64 байта. Так что тут и больше атомарность. Но — только по выровненным границам. Читать и писать двухбайтовое значение по адресам 63 и 64 — имеет в большинстве случаев законное право порваться на две независимые операции.)

Но вот для более хитрых объектов типа регистров ввода-вывода — я описал
Автор: netch80
Дата: 19.09.21
ситуацию, где по сути атомарность доступа — 1 бит, даже при чтении порцией в 32 бита. Это из реального железа, которое ещё должно быть доступно, и для процессора это таки данные в памяти (а не I/O пространстве).
The God is real, unless declared integer.
Re[12]: Как вышло, что наложение предполагается по умолчанию?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 19.09.21 08:14
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>>>Так как нет гарантий, что операции чтения атомарны (даже для одного байта)

ЕМ>>Где их нет?
BFE>В стандарте.

ЕМ>>Для большинства конкретных архитектур они как раз есть.

BFE>Знаете почему? А потому, что многие не умеют в параллельность.

Такое впечатление, что вы на принципиальном уровне путаете требования уровня архитектуры и уровня языка.

На уровне архитектуры гарантии предоставляются для операций при определённых условиях (например, что это реальная память или что-то адекватно её имитирующее, операции определённого размера и соответственно выровнены). Требования синхронизации, где они возникают из одновременного доступа, OoO исполнения и т.п., чётко определены на уровне инструкций и их свойств.

На уровне уже языка типа C/C++, во-первых, вмешивается кэширование и реордеринг от компилятора (это то, против чего защищаются или volatile, или atomic_signal_fence). Во-вторых, гарантии упорядочения сведены к точкам синхронизации и операциям перед и после них, а ключевое понятие "synchronized with" определено вообще вокруг использования одного и того же объекта синхронизации. Там уже будут операции атомарны до байта или бита — не имеет значение (для хоть до 1/2 бита, если где-то такое есть). Битовые поля усугубляют картину — где они участвуют, про атомарность до байта уже нельзя говорить.

Рассматривать эти два контекста надо похожим образом, но обязательно раздельно.

ЕМ>>А задача сделать надежную программу для абстрактной, заранее неизвестной архитектуры, напоминает анекдот о сферической лошади в вакууме.

BFE>Только вот в отличии от анекдотов, в жизни, программы написанные по правилам стандарта проще изменять и работают они быстрее.

1) Не проще — см. проблему переполнения, вызванного изменением кода в другом углу огромного проекта.
2) Не "быстрее". Надёжнее — да. Но скорость как раз очень часто достигается отходом от жёстких рамок стандарта.

BFE>>>Скажем строка принимающая два значения "OK" или "КО" в GUI может отобразится как "OO", "OK", "KO" или "KK". Т.е. нет никакого смысла передавать более одного данного из потока в поток таким способом.

ЕМ>>Может, смысла и нет, а я всю жизнь передаю, и отлично работает, ни разу не жаловались.

BFE>Хмм... Точно не жаловались? Вот возьмём, к примеру, известную бухгалтерскую программу Horizon...


А что там?
The God is real, unless declared integer.
Re[9]: Как вышло, что наложение предполагается по умолчанию?
От: TailWind  
Дата: 19.09.21 15:07
Оценка:
Здравствуйте, netch80

N>Вот в какой-то момент Intel ввёл в своих чипсетах PIIX timer


Спасибо за интересную историю
Получил удовольствие соображая, как инженер Intel должен был сделать схему синхронизации чтобы таких проблем не было

N>В следующем варианте "ACPI-safe" есть защёлка (дополнительный регистр, в который, в простейшем варианте, переписывается значение счётчика в противофазе — например, если инкремент происходит по фронту, то запись в защёлку — по спаду;


Так эту проблему не решить

Тут фишка в том, что триггеры контроллера PCI работают от своего клока
А триггеры счётчика от своего

В результате, есть вероятность, что изменение значения счётчика попадёт точно под клок PCI, что переведёт его триггеры в бистабильное состояние (они начнут генерить (постоянно менять значения))
Re[10]: Как вышло, что наложение предполагается по умолчанию
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 19.09.21 18:05
Оценка:
Здравствуйте, TailWind, Вы писали:

N>>В следующем варианте "ACPI-safe" есть защёлка (дополнительный регистр, в который, в простейшем варианте, переписывается значение счётчика в противофазе — например, если инкремент происходит по фронту, то запись в защёлку — по спаду;


TW>Так эту проблему не решить

TW>Тут фишка в том, что триггеры контроллера PCI работают от своего клока
TW>А триггеры счётчика от своего

Да. Но это решаемо. Конечно, я упростил описание ситуации.

TW>В результате, есть вероятность, что изменение значения счётчика попадёт точно под клок PCI, что переведёт его триггеры в бистабильное состояние (они начнут генерить (постоянно менять значения))


Именно такое с бистабильностью — я не знаю, как достигнуть
Проблема понятна, и есть несколько вариантов решения. В случае значительного превышения одной частоты над другой — а тут именно так, у таймера, грубо говоря, 3.5 МГц, а у шины 33 МГц и выше — идёт синхронизация по большей частоте. Примерно так:
Три регистра: int_value, out_value, temp1 — все три — группы синхронных D-триггеров с записью по фронту.
1. В любой момент времени, когда в таймере (int_value) значение N, на выходе сумматора готово N+1. Синхронность тут ещё не нужна.
2. По фронту сигнала инкремента таймера взводится однобитовый флажок want_set и выход сумматора копируется в полноразмерный регистр temp1.
3. По комбинации фронта тактового сигнала шины и флажка обновления — значение temp1 сохраняется в out_value и want_set сбрасывается в 0.

Или чуть экономнее: temp1 удаляем, но делаем ещё один однобитовый флаг need_inc.
2. По фронту сигнала инкремента таймера взводится однобитовый флажок want_set.
3. По комбинации фронта тактового сигнала шины и want_set — выход сумматора записывается в out_value и взводится флажок need_inc; want_set сбрасывается в 0.
4. По любому перепаду тактового сигнала и need_inc — выход сумматора записывается в int_value, need_inc сбрасывается.

Повторюсь, для надёжности этого нужно, чтобы частота шины превышала частоту таймера (более чем в 2 раза), но тут это выполняется.

Вот если частоты близки или соотношение непредсказуемо — тогда суши вёсла Есть отдельная теория разработки полностью асинхронных и самосинхронных схем. Я знаю, кто в ней реально работает (хоть и на хобби), но сам не осилил.
The God is real, unless declared integer.
Отредактировано 19.09.2021 18:06 netch80 . Предыдущая версия .
Re[11]: Как вышло, что наложение предполагается по умолчанию
От: TailWind  
Дата: 19.09.21 19:13
Оценка:
N>Повторюсь, для надёжности этого нужно, чтобы частота шины превышала частоту таймера (более чем в 2 раза), но тут это выполняется.

Не обязательно

Синхронизировать 1 сигнал просто:
Нужно поставить ряд последовательных D триггеров на частоте счётчика
Когда с шины PCI приходит запрос на чтение, она изменяет состояние сигнала на входе первого триггера на обратное
Бистабильное состояние не сможет пройти через 3 последовательных триггера, в результате изменение увидит управляющая схема на частоте счётчика, как переход 1->0 или 0->1 (просто изменение значения)

Схема счётчика сделает копию значения счётчика в отдельный регистр. На частоте счётчика с этим проблем нет. Все биты будут точными
Через такую же последовательность D триггеров отправит уведомление шине PCI обратно, что сообщение получено (на частоте шины PCI)
Копия регистра не изменится за это время. И PCI сможет его спокойно считать без проблем с синхронизацией
Re[12]: Как вышло, что наложение предполагается по умолчанию
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 19.09.21 20:02
Оценка:
Здравствуйте, TailWind, Вы писали:

N>>Повторюсь, для надёжности этого нужно, чтобы частота шины превышала частоту таймера (более чем в 2 раза), но тут это выполняется.

TW>Не обязательно

Ну я говорил про те схемы. Они прямые и надёжные. Хотя про 2 раза перегнул: достаточно просто больше.

TW>Синхронизировать 1 сигнал просто:

TW>Нужно поставить ряд последовательных D триггеров на частоте счётчика
[...]

Я совсем не понял логику этого решения. Можно переформулировать?
По попыткам понять получилось что-то сильно более сложное, чем у меня.
Можно написать на условном Verilog/VHDL, разберу.
The God is real, unless declared integer.
Re[13]: Как вышло, что наложение предполагается по умолчанию
От: TailWind  
Дата: 19.09.21 20:22
Оценка:
N>Я совсем не понял логику этого решения. Можно переформулировать?
N>По попыткам понять получилось что-то сильно более сложное, чем у меня.
N>Можно написать на условном Verilog/VHDL, разберу.

В одну сторону и обратно:

module tSync ( ResetA_, ClkA, SelectA, AckA,
               ResetB_, ClkB, SelectB );
/////////////////////////////////////////
input  ResetA_, ClkA, SelectA;
output AckA; 
input  ResetB_, ClkB;
output SelectB;  
/////////////////////////////////////////
parameter hold = 2;
/////////////////////////////////////////
wire SelectA;
reg  SelectA_Toggle;
reg  SelectA_Toggle_d;
reg  SelectA_Toggle_dd;
reg  SelectB;
reg  SelectB_Toggle;
reg  SelectB_Toggle_d;
reg  SelectB_Toggle_dd;
reg  AckA;
/////////////////////////////////////////
always @(posedge ClkA or negedge ResetA_)
if (!ResetA_)
begin
  SelectA_Toggle    <= #hold 0;
  SelectB_Toggle_d  <= #hold 0;
  SelectB_Toggle_dd <= #hold 0;
  AckA              <= #hold 0;
end else
begin
  if (SelectA) SelectA_Toggle    <= #hold !SelectA_Toggle;
               //
               SelectB_Toggle_d  <= #hold  SelectB_Toggle;  
               SelectB_Toggle_dd <= #hold  SelectB_Toggle_d;
               AckA              <= #hold (SelectB_Toggle_d != SelectB_Toggle_dd);
end
/////////////////////////////////////////
always @(posedge ClkB or negedge ResetB_)
if (!ResetB_)
begin
  SelectA_Toggle_d  <= #hold 0;
  SelectA_Toggle_dd <= #hold 0;
  SelectB           <= #hold 0;  
  SelectB_Toggle    <= #hold 0;
end else
begin
  if (SelectB) SelectB_Toggle    <= #hold !SelectB_Toggle;
               //
               SelectA_Toggle_d  <= #hold  SelectA_Toggle;
               SelectA_Toggle_dd <= #hold  SelectA_Toggle_d;               
               SelectB           <= #hold (SelectA_Toggle_d != SelectA_Toggle_dd);  
end
/////////////////////////////////////////
endmodule
Re[13]: Как вышло, что наложение предполагается по умолчанию
От: andyp  
Дата: 19.09.21 20:27
Оценка: 2 (1)
Здравствуйте, netch80, Вы писали:

N>Я совсем не понял логику этого решения. Можно переформулировать?

N>По попыткам понять получилось что-то сильно более сложное, чем у меня.
N>Можно написать на условном Verilog/VHDL, разберу.

Поищите по словам clock domain synchronization.

Например
https://www.verilogpro.com/clock-domain-crossing-part-1/
Re[7]: Как вышло, что наложение предполагается по умолчанию?
От: Videoman Россия https://hts.tv/
Дата: 20.09.21 16:20
Оценка:
Здравствуйте, netch80, Вы писали:

N>Это был пример на заголовок IPv4 пакета. Там ровно эта проблема — порядок битов (даже не байтов). Сейчас из-за отсутствия таких определений приходится писать так:


N>
N>struct iphdr
N>  {
N>#if __BYTE_ORDER == __LITTLE_ENDIAN
N>    unsigned int ihl:4;
N>    unsigned int version:4;
N>#elif __BYTE_ORDER == __BIG_ENDIAN
N>    unsigned int version:4;
N>    unsigned int ihl:4;
N>#else
N># error "Please fix <bits/endian.h>"
N>#endif
N>


N>ну и далее по тексту.


N>Мало того, в IPv6 ещё злобнее получилось — поле flow label занимает в BE нумерации биты 12-31 (не знаю, нафига им столько), и если смотреть по байтам или шекам, то на LE машине оно разорвано на два несвязанных куска.


Ну было бы странно из-за одного IP заголовка тащить в стандарт такое сложное описание всяких возможных раскладок в памяти. Будет проще, если проблему big-endian/little-endial рассматривать просто как вариант очередной упаковки при сериализации. Мне кажется идея сразу работать с сетевым порядком пакетов в памяти не работает в общем виде. Дальше у нас появляются пакеты, где переменная (в битах) длина полей или наличие отсутствие полей зависит от каких-то дополнительных условий и что делать в этом случае?
Часто, лучше "распаковать" пакет, поработать с ним, изменить как угодно, и "запаковать" обратно, чем пытаться работать с маппингом в памяти. Конечно, если у нас есть какая-то уже готовая огромная структура (несколько ГБ), например на диске, и в ней нужно заменить один бит, тогда подход с распаковкой/запаковкой не сработает эффективно.
Отредактировано 20.09.2021 19:26 Videoman . Предыдущая версия . Еще …
Отредактировано 20.09.2021 16:22 Videoman . Предыдущая версия .
Отредактировано 20.09.2021 16:21 Videoman . Предыдущая версия .
Re[9]: Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 20.09.21 18:44
Оценка: +1
Здравствуйте, netch80, Вы писали:

N>Ты имеешь в виду то, что поле какого-то полного размера (2, 4, 8 байт) хранится постоянно в памяти в чужом порядке (обычно — в BE при машине в LE; обратный вариант крайне редок) и переворачивается при чтении или записи?


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

N>я имел в виду не столько оптимизацию или её отсутствие, сколько переносимость описания.


Для чего такие описания делать непременно на ЯВУ? Ну хорошо, C/C++ позволяет описать битовые поля в структуре, а как станете описывать параметры сигнала на линии? Все равно придется делать отдельное техническое описание, так что возможность определить структуру на ЯВУ ничего к этому не добавит. Поэтому такие вещи всегда определяются независимо: для сигналов в линии — амплитуды, длительности, промежутки, двоичная интерпретация и т.п., для битовой последовательности — порядок раскладки по байтам/словам на конкретной архитектуре, и только с этого уровня имеет смысла определять структуры.
Re[10]: Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 20.09.21 18:53
Оценка:
Здравствуйте, netch80, Вы писали:

N>На уровне C/C++ ты вообще отображённые на память регистры (если это те регистры процессора, в которые компилятор кладёт рабочие данные) не влазят в основную концепцию


Нет, я про регистры контроллеров внешних устройств. На PDP, для которого изначально делался C, вообще не было отдельных команд типа IN/OUT — каждый контроллер отображал группу своих регистров в адресное пространство, и для программ они были видны, как обычные ячейки памяти. Но с развитием кэширования и прочих оптимизаций от этого отказались, теперь в адресное пространство отображают только обычную память (основную и внешних устройств).
Re[9]: Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 20.09.21 18:57
Оценка:
Здравствуйте, netch80, Вы писали:

N>на чтение из этого таймера они не поставили защёлку


Выглядит, кстати, крайне странно. Как будто проектирование этой части схемы поручили новичку, он накосячил, начальник не проконтролировал, и оно так и пошло в продакшн, а когда спохватились — решили сохранить лицо и объявить, будто так и задумано.
Re[11]: Как вышло, что наложение предполагается по умолчанию?
От: Zhendos  
Дата: 20.09.21 19:16
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Нет, я про регистры контроллеров внешних устройств. На PDP, для которого изначально делался C, вообще не было отдельных команд типа IN/OUT — каждый контроллер отображал группу своих регистров в адресное пространство, и для программ они были видны, как обычные ячейки памяти. Но с развитием кэширования и прочих оптимизаций от этого отказались, теперь в адресное пространство отображают только обычную память (основную и внешних устройств).


Не знаю кто от этого отказался, но в ARM (по крайней мере 32бит)
все управление IP блоками отображаются в память.
Нужно тебе узнать что за прерывание, читаешь с такого-то адреса,
нужна тебе послать по DMA N байт, в один определенный адрес пишешь
откуда, в другой куда, в третий сколько слов, по четвертому адресу записаываешь 1,
чтобы передача началась,
и так со всем остальным NAND, SPI, UART/RS232.

При включенной виртаульной памяти просто помечаешь диапазаны адресов
как некэшируемые и все.
Re[12]: Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 20.09.21 20:21
Оценка:
Здравствуйте, Zhendos, Вы писали:

Z>Не знаю кто от этого отказался, но в ARM


В ARM используется memory-mapped IO, для программиста это удобнее. Отказались прежде всего на "больших" архитектурах, где многоуровневая память, кэширование, тэги и прочее. Возможно, так проще рулить магистралью. Команды типа IN/OUT по определению выставляют сигнал обращения ко внешнему устройству, а в MMIO надо выделять зоны, декодировать адреса, использовать разные протоколы при работе с памятью и ВУ, дабы не усложнять жизнь контроллерам, и т.п.
Re[13]: Как вышло, что наложение предполагается по умолчанию
От: TailWind  
Дата: 20.09.21 21:03
Оценка:
ЕМ>Команды типа IN/OUT по определению выставляют сигнал обращения ко внешнему устройству, а в MMIO надо выделять зоны, декодировать адреса, использовать разные протоколы при работе с памятью и ВУ, дабы не усложнять жизнь контроллерам, и т.п.

Для системного контроллера никакой разницы
И там и там надо декодировать адреса, выделять зоны, и использовать разные протоколы для общения с устройствами

Обычная рутина. Сидишь себе и пишешь state машины

ЕМ>Возможно, так проще рулить магистралью.

Не..
В процессоре обычно все сложности со временем
Отредактировано 20.09.2021 21:06 TailWind . Предыдущая версия .
Re[11]: Как вышло, что наложение предполагается по умолчанию?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 20.09.21 21:13
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Нет, я про регистры контроллеров внешних устройств. На PDP, для которого изначально делался C, вообще не было отдельных команд типа IN/OUT — каждый контроллер отображал группу своих регистров в адресное пространство, и для программ они были видны, как обычные ячейки памяти. Но с развитием кэширования и прочих оптимизаций от этого отказались, теперь в адресное пространство отображают только обычную память (основную и внешних устройств).


Всё как раз наоборот. Наличие отдельного пространства I/O — специфика, насколько я знаю, только линии 8080 -> x86, и изначально была вызвана просто разными методами подключения памяти и шины устройств. Потом в x86 их объединили, но отдельное I/O пространство сохранялось ради легаси.

Уже на PCI старались в существенной мере выносить вполне себе I/O на память. Сейчас есть варианты без I/O пространства вообще. Вот мне lspci рассказывает:

01:00.0 USB controller: Advanced Micro Devices, Inc. [AMD] 300 Series Chipset USB 3.1 xHCI Controller (rev 02) (prog-if 30 [XHCI])
        Subsystem: ASMedia Technology Inc. 300 Series Chipset USB 3.1 xHCI Controller
        Flags: bus master, fast devsel, latency 0, IRQ 36
        Memory at fcea0000 (64-bit, non-prefetchable) [size=32K]

01:00.1 SATA controller: Advanced Micro Devices, Inc. [AMD] 300 Series Chipset SATA Controller (rev 02) (prog-if 01 [AHCI 1.0])
        Subsystem: ASMedia Technology Inc. 300 Series Chipset SATA Controller
        Flags: bus master, fast devsel, latency 0, IRQ 55
        Memory at fce80000 (32-bit, non-prefetchable) [size=128K]


и так далее. В I/O к этим устройствам вообще нет доступа. (Часть настройки делается через configuration space, это третье адресное пространство — но самые базовые вещи.)

У этого подхода есть ещё несколько вкусностей, например:
1. Устройство можно целиком отдать в пользование виртуальному гостю, просто разрешив ему маппинг соответствующей области памяти.
2. Устройство можно отдать на чтение в userland. Это типовая манера для HPET таймера. В таком случае получение текущего времени вообще не требует переключения в ядро.

Обратная сторона — что то, что размещается в памяти, желательно чтобы не имело побочных эффектов от случайного чтения.
The God is real, unless declared integer.
Re[13]: Как вышло, что наложение предполагается по умолчанию?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 20.09.21 21:16
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Здравствуйте, Zhendos, Вы писали:


Z>>Не знаю кто от этого отказался, но в ARM


ЕМ>В ARM используется memory-mapped IO, для программиста это удобнее. Отказались прежде всего на "больших" архитектурах, где многоуровневая память, кэширование, тэги и прочее. Возможно, так проще рулить магистралью. Команды типа IN/OUT по определению выставляют сигнал обращения ко внешнему устройству, а в MMIO надо выделять зоны, декодировать адреса, использовать разные протоколы при работе с памятью и ВУ, дабы не усложнять жизнь контроллерам, и т.п.


У x86 это всё тоже есть. Только даже обычному системщику с драйверами не нужно.
Что какой-то регион пространства памяти объявлен uncacheable — задаётся в сервисных MTRR регистрах процессора тем кодом, что настраивает PCI мосты — обычно это ещё BIOS.

Что очень много реального I/O переносят в пространство памяти — я написал рядом.
The God is real, unless declared integer.
Re[10]: Как вышло, что наложение предполагается по умолчанию?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 21.09.21 06:48
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Здравствуйте, netch80, Вы писали:


N>>на чтение из этого таймера они не поставили защёлку


ЕМ>Выглядит, кстати, крайне странно. Как будто проектирование этой части схемы поручили новичку, он накосячил, начальник не проконтролировал, и оно так и пошло в продакшн, а когда спохватились — решили сохранить лицо и объявить, будто так и задумано.


Вполне возможно — у Intel (особенно тогда, середина 90-х) очень неровная политика в деталях. В процессорах это новые фичи — половина из них сделана, как будто кто-то запретил даже на полшага думать вперёд.
В 90-х они как раз создавали свои сетевухи ряда 8255x, там тоже ой не с первого раза получилось надёжно.

Но зато уже к середине 2000-х они отшлифовали средства разработки, заодно помогя индустрии сформировать всякие SystemVerilog...
The God is real, unless declared integer.
Re[10]: Как вышло, что наложение предполагается по умолчанию?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 21.09.21 06:55
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Здравствуйте, netch80, Вы писали:


N>>Ты имеешь в виду то, что поле какого-то полного размера (2, 4, 8 байт) хранится постоянно в памяти в чужом порядке (обычно — в BE при машине в LE; обратный вариант крайне редок) и переворачивается при чтении или записи?


ЕМ>Хранить и обрабатывать надо как раз в родном для архитектуры порядке, а переворачивать при отправке и приеме. Так оно вроде и делается в сетевых протоколах.


Ну ладно, поля размером в 2 или 4 байта ты перевернёшь так. А вот это вот "старшие 4 бита — версия, младшие — длина"?
А flow label в IPv6, который при рассмотрении в LE оказывается разрезан пополам? Переворачивать всё 4-байтное значение и резать на части?
Ну и ещё и не забыть сделать это вовремя во всех случаях (вроде бы просто, но можно пропустить).

N>>я имел в виду не столько оптимизацию или её отсутствие, сколько переносимость описания.


ЕМ>Для чего такие описания делать непременно на ЯВУ? Ну хорошо, C/C++ позволяет описать битовые поля в структуре, а как станете описывать параметры сигнала на линии?


А при чём тут параметры сигнала на линии? Это вообще напрямую никак не доступно ЦП, только периферии, а для неё уже свои языки типа Verilog. Куда-то ты тут загнался не туда.

EM> Все равно придется делать отдельное техническое описание, так что возможность определить структуру на ЯВУ ничего к этому не добавит. Поэтому такие вещи всегда определяются независимо: для сигналов в линии — амплитуды, длительности, промежутки, двоичная интерпретация и т.п., для битовой последовательности — порядок раскладки по байтам/словам на конкретной архитектуре, и только с этого уровня имеет смысла определять структуры.


Ну а вот авторы C# так не думают, раз ввели LayoutKind аж с двумя специализированными вариантами — упакованным и с конкретными смещениями.
Потому что копировать из одного в другое на каждый чих — дорого в рантайме. Легче чуть-чуть уточнить компилятору метод доступа.
The God is real, unless declared integer.
Re[8]: Как вышло, что наложение предполагается по умолчанию?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 21.09.21 06:59
Оценка:
Здравствуйте, Videoman, Вы писали:

V>Ну было бы странно из-за одного IP заголовка тащить в стандарт такое сложное описание всяких возможных раскладок в памяти.


Почему из-за одного IP заголовка? Таких структур десяток только у IETF и несколько сотен включая остальные вполне распространённые протоколы.

V> Будет проще, если проблему big-endian/little-endial рассматривать просто как вариант очередной упаковки при сериализации.


И гонять байты в памяти только ради финальной упаковки или начальной распаковки.

V> Мне кажется идея сразу работать с сетевым порядком пакетов в памяти не работает в общем виде. Дальше у нас появляются пакеты, где переменная (в битах) длина полей или наличие отсутствие полей зависит от каких-то дополнительных условий и что делать в этом случае?


И такие есть. Ну на такое двигают указатели.

V>Часто, лучше "распаковать" пакет, поработать с ним, изменить как угодно, и "запаковать" обратно, чем пытаться работать с маппингом в памяти.


И сколько таких случаев вы реально видели?
Даже на x86 прочесть другой порядок бит или байт банально. На каком-нибудь ARM ещё проще.

V> Конечно, если у нас есть какая-то уже готовая огромная структура (несколько ГБ), например на диске, и в ней нужно заменить один бит, тогда подход с распаковкой/запаковкой не сработает эффективно.


Ну такие и читают/пишут по блоку, там время даже полного копирования в памяти заведомо меньше времени I/O.
The God is real, unless declared integer.
Re[14]: Как вышло, что наложение предполагается по умолчанию
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 21.09.21 08:23
Оценка:
Здравствуйте, TailWind, Вы писали:

TW>Для системного контроллера никакой разницы

TW>И там и там надо декодировать адреса, выделять зоны, и использовать разные протоколы для общения с устройствами

Под "разными протоколами" имеются в виду протоколы работы процессора с обычной памятью и областями ВУ. Традиционно в такой архитектуре и основная память, и ВУ висят на общей магистрали, устроены примитивно и асинхронно, и контроллеру, конечно, по барабану — увидел сигнал, опознал адрес, выставил ответ, ничего сложного. А когда добавляются особые режимы доступа к памяти (те же сигналы выборки/записи отдельных байтов), каждому контроллеру приходится все это отрабатывать.

TW>Обычная рутина. Сидишь себе и пишешь state машины


Это сейчас. А в 60-70-х все делалось практически вручную.
Re[11]: Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 21.09.21 08:26
Оценка:
Здравствуйте, netch80, Вы писали:

N>Ну ладно, поля размером в 2 или 4 байта ты перевернёшь так. А вот это вот "старшие 4 бита — версия, младшие — длина"?


А насколько часто это встречается, чтобы оправдать внесение в стандарт и реализацию в каждом компиляторе?
Re[12]: Как вышло, что наложение предполагается по умолчанию?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 21.09.21 08:32
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

N>>Ну ладно, поля размером в 2 или 4 байта ты перевернёшь так. А вот это вот "старшие 4 бита — версия, младшие — длина"?


ЕМ>А насколько часто это встречается, чтобы оправдать внесение в стандарт и реализацию в каждом компиляторе?


Битовые поля, если ты не заметил, уже есть в стандарте и в любом компиляторе. Значит, оправдано.
The God is real, unless declared integer.
Re[9]: Как вышло, что наложение предполагается по умолчанию?
От: Videoman Россия https://hts.tv/
Дата: 21.09.21 10:08
Оценка:
Здравствуйте, netch80, Вы писали:

N>Почему из-за одного IP заголовка? Таких структур десяток только у IETF и несколько сотен включая остальные вполне распространённые протоколы.

Я не спорю, что есть частные случаи, когда можно читать или менять данные сохраняя раскладку, но таких < 1%. Во всех остальных протоколах нужно, как минимум, собрать несколько пакетов, что бы получить из них целиковое полезное содержимое и что-то там менять.

N>И гонять байты в памяти только ради финальной упаковки или начальной распаковки.

По скорости будет одинаково, т.к. по сравнению с памятью сеть это тормоз. Во всяком случае, это не медленнее чем каждый раз при работе с полем вызывать htol() + ltoh().

N>И такие есть. Ну на такое двигают указатели.

Только в каких-то уж очень частных случаях. В общем виде никакими указателями не отделаешься. Возьмем какой-нибудь mpeg — там просто меняешь значение поля и его длина в битах тут же меняется, да и еще где-нибудь в конце CRC нужно будет пересчитать.

N>И сколько таких случаев вы реально видели?

N>Даже на x86 прочесть другой порядок бит или байт банально. На каком-нибудь ARM ещё проще.
Видимо мне так не везет, но почти все протоколы мультимедиа так устроены: сжатие (переменная длина), поля в битах, СRC, всякие маски сверху и т.д.

N>Ну такие и читают/пишут по блоку, там время даже полного копирования в памяти заведомо меньше времени I/O.

Полностью согласен, но тогда и формат данных стараются подобрать удобным для этого, выровнять структуры на границы секторов и т.д.
Отредактировано 21.09.2021 11:33 Videoman . Предыдущая версия .
Re[13]: Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 21.09.21 15:59
Оценка:
Здравствуйте, netch80, Вы писали:

N>Битовые поля, если ты не заметил, уже есть в стандарте и в любом компиляторе. Значит, оправдано.


Я-то заметил, но определены они там чисто формально, фактическое размещение зависит от реализации. Как при таком подходе определить в стандарте размещения для различных архитектур? Если просто стандартизировать атрибуты с благими пожеланиями по их реализации, то бОльшая часть компиляторов на это забьет.

А если это все-таки протащить в стандарт, то сразу же всплывут и предложения атрибутов для LE/BE. Затем кто-то захочет (и наверняка уже захотел), чтобы на любой архитектуре он мог автоматом читать/писать float/double в формате любой другой архитектуры. И где будет пора остановиться?
Re[10]: Как вышло, что наложение предполагается по умолчанию?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 21.09.21 16:50
Оценка:
Здравствуйте, Videoman, Вы писали:

N>>И сколько таких случаев вы реально видели?

N>>Даже на x86 прочесть другой порядок бит или байт банально. На каком-нибудь ARM ещё проще.
V>Видимо мне так не везет, но почти все протоколы мультимедиа так устроены: сжатие (переменная длина), поля в битах, СRC, всякие маски сверху и т.д.

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

Ну да, ваша реплика была к другому — к ситуации типа "при наличии бита Z в позиции X возникает дополнительное двухбайтовое поле по смещению Y". Вот про это я и говорил, что указателями оно (обычно) разбирается.

N>>Почему из-за одного IP заголовка? Таких структур десяток только у IETF и несколько сотен включая остальные вполне распространённые протоколы.

V>Я не спорю, что есть частные случаи, когда можно читать или менять данные сохраняя раскладку, но таких < 1%. Во всех остальных протоколах нужно, как минимум, собрать несколько пакетов, что бы получить из них целиковое полезное содержимое и что-то там менять.

Пакетов чего?
Если речь про какие-нибудь данные TCP, это уже не задача прикладного уровня.

N>>И гонять байты в памяти только ради финальной упаковки или начальной распаковки.

V>По скорости будет одинаково, т.к. по сравнению с памятью сеть это тормоз. Во всяком случае, это не медленнее чем каждый раз при работе с полем вызывать htol() + ltoh().

Боюсь, как раз в случае всяких видеокодеков это уже совсем не так. Иначе Intel не занимался бы введением всяких BMI2.
Но я согласен, что конкретный выхлоп там ещё мерять надо. Мой поинт был за то, насколько удобство описания для программиста помогает верификации программы.

N>>И такие есть. Ну на такое двигают указатели.

V>Только в каких-то уж очень частных случаях. В общем виде никакими указателями не отделаешься. Возьмем какой-нибудь mpeg — там просто меняешь значение поля и его длина в битах тут же меняется, да и еще где-нибудь в конце CRC нужно будет пересчитать.

Ну так я и не претендовал на решение всех проблем. Но как по мне проблема с выбором порядка описания весьма типична.

N>>Ну такие и читают/пишут по блоку, там время даже полного копирования в памяти заведомо меньше времени I/O.

V>Полностью согласен, но тогда и формат данных стараются подобрать удобным для этого, выровнять структуры на границы секторов и т.д.

Или просто подровнять адрес позиции read/write под типовой размер блока.
The God is real, unless declared integer.
Re[14]: Как вышло, что наложение предполагается по умолчанию?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 21.09.21 16:55
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

N>>Битовые поля, если ты не заметил, уже есть в стандарте и в любом компиляторе. Значит, оправдано.


ЕМ>Я-то заметил, но определены они там чисто формально, фактическое размещение зависит от реализации. Как при таком подходе определить в стандарте размещения для различных архитектур?


Если есть такой атрибут, порядок жёстко фиксируется. Если нет, компилятор имеет прежнюю свободу.

EM> Если просто стандартизировать атрибуты с благими пожеланиями по их реализации, то бОльшая часть компиляторов на это забьет.


Почему забьёт? Сколько лет уже в MSC есть `#pragma pack`?

ЕМ>А если это все-таки протащить в стандарт, то сразу же всплывут и предложения атрибутов для LE/BE.


Да, это естественно.

EM> Затем кто-то захочет (и наверняка уже захотел), чтобы на любой архитектуре он мог автоматом читать/писать float/double в формате любой другой архитектуры.


А вот "в формате любой другой" уже нет.
Более реально иметь интринсики типа put_ieee754_be32(char *target, float value), при наличии поддержки соотв. стандарта в платформе (будет в 99% таковых). И это уже есть, как минимум в виде предложений (см. комплект ISO/IEC TS18661) — значит, кому-то оно реально нужно.

EM> И где будет пора остановиться?


Как везде и всегда, это вопрос баланса интересов и цены. Тут — просто, дёшево и полезно всем.
The God is real, unless declared integer.
Re[15]: Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 21.09.21 19:55
Оценка:
Здравствуйте, netch80, Вы писали:

EM>>Если просто стандартизировать атрибуты с благими пожеланиями по их реализации, то бОльшая часть компиляторов на это забьет.


N>Почему забьёт? Сколько лет уже в MSC есть `#pragma pack`?


MS всю жизнь пилил MSVC прежде всего для своих продуктов, и pack там много где используется. А на то, что им лично не нужно, они забивают десятилетиями. Если таки реализовать описанные Вами атрибуты — в какой доле имеющегося программного кода они пригодятся? Сколько нулей будет перед точкой в процентном выражении? Да и сколько Вашего собственного кода это сэкономит? Хоть сотая процента наберется?

EM>> Затем кто-то захочет (и наверняка уже захотел), чтобы на любой архитектуре он мог автоматом читать/писать float/double в формате любой другой архитектуры.


N>А вот "в формате любой другой" уже нет.


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

N>это вопрос баланса интересов и цены. Тут — просто, дёшево и полезно всем.


Всем — это какой доле программистов в мире?
Re[11]: Как вышло, что наложение предполагается по умолчанию?
От: Videoman Россия https://hts.tv/
Дата: 21.09.21 20:27
Оценка:
Здравствуйте, netch80, Вы писали:

N>Вот представим себе ситуацию: в байте 3 битовых поля, начиная со старшего: в 1, 4 и 3 бита. Думаю, в каком-нибудь аудио-видеокодеке найдёте что-то очень похожее.

N>Наверняка для чтения/записи подобной структуры двигаете значения операторами сдвига и читаете/пишете масками? А почему, если это заморочно? (ну да, я давно привык, и вы наверняка тоже. а другим?)
Иногда двигаю биты с масками, а иногда, не поверите, прям байтом пишу, сразу все значения. Причем, если скорость вдруг в такой мелочи важна, то она разительно отличается от метода записи. Слишком много всяких разных вариантов и частных случаев, что бы давать оптимальное решение в общем виде в стандарте.

N>Ну да, ваша реплика была к другому — к ситуации типа "при наличии бита Z в позиции X возникает дополнительное двухбайтовое поле по смещению Y". Вот про это я и говорил, что указателями оно (обычно) разбирается.

Да в том то и дело что не обязательно поле в байтах. Возможно в битах и не кратно байтам, ну и как тут указатели помогут, я не пойму

N>Пакетов чего?

N>Если речь про какие-нибудь данные TCP, это уже не задача прикладного уровня.
Не обязательно TCP. Часто бывает куча протоколов друг в друге, как матрешка. Структура пакетов нижнего уровня зависит от изменений в данных верхнего уровня и всё равно приходится все переупаковывать при каких-то изменениях.

N>Но я согласен, что конкретный выхлоп там ещё мерять надо. Мой поинт был за то, насколько удобство описания для программиста помогает верификации программы.

Вот иногда бывает везёт, можно срезать углы и копировать данные целиком, меняя только нужные поля, но это скорее исключение. Чаше приходится менять всю структуру пакета.
Re[6]: Как вышло, что наложение предполагается по умолчанию?
От: IID Россия  
Дата: 22.09.21 16:37
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Вот у меня телефон 2016-го года на Qualcomm Snapdragon 650.

ЕМ>...
ЕМ>Восемь секунд, Карл! На полутора гигагерцах и шести ядрах! Что нужно курить, чтобы так сделать? Я не знаю.

А ты профилировал ? Они загружены вообще ?
У тебя, возможно, флешка дохнет. И тупит поэтому. Отдавая сектор не с первого раза, а с пятого, с таймаутами. Всё тормозит, но процессор совершенно непричём.
kalsarikännit
Re[7]: Как вышло, что наложение предполагается по умолчанию?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 22.09.21 17:46
Оценка:
Здравствуйте, IID, Вы писали:

ЕМ>>Восемь секунд, Карл! На полутора гигагерцах и шести ядрах!


IID>А ты профилировал ?


Чем можно профилировать на самом андроиде? Я знаю только способ через Android Studio, но ставить и разбираться ради такого лень.

IID>Они загружены вообще ?


Но чем еще можно заниматься столько времени? Если тапать на списках и лентах приложений, то страницы приложений открываются почти мгновенно, разве что дорисовываются в процессе. Тормозит именно переделка надписи на кнопке.

IID>У тебя, возможно, флешка дохнет.


Нет, с этим все в порядке. То, что давно не обновлялось, работает так же быстро, как и в начале, файлы копируются с нормальной скоростью. Так что код у GApps или неимоверно тормозной, или неимоверно кривой.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.