Re[14]: sequence point (по мотивам инкремента)
От: folk Россия  
Дата: 05.06.04 06:06
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>>>Вот конкретный пример. Можете его откомпилировать под Itanium.


Ш>>>
Ш>>>int fun(int *i,int *j) { return ++(*i) + ++(*j); }
Ш>>>


Ш>>>Данная функция нормально себя ведет, если i и j указывают на разные переменные и в этом случае параллелизация инкрементов -- хорошая идея.

Ш>>>Но вот если они указывают на одну переменную...

F>>Ну так здесь неопределенное поведение в случае, когда i и j указывают на одну переменную.


Ш>Ага. Вопрос только -- зачем компилятору генерировать "плохой" код.


Потому что "плохой" быстрее, ибо полнее использует параллелизацию операций.

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


F>>Помню что некоторые процессоры с помощью какой-то магии умеют определять истинные зависимости по данным такого рода (чтение после записи) и в качестве контрмеры приостанавливают конвейер(ы), пока не будет завершено выполнение первой команды.


Ш>Не некоторые. Все современные процессоры -- конвейерные.


Ш>И все они осуществляют приостановку конвейера при возникновении зависимости между входом и выходом. Иначе такой процессор невозможно было бы использовать.


Ты уверен что это обязательное условие и что все современные процы это могут? Судя по приведенному dupaid'ом asm-листингу, точки, где нужно ожидать окончания выполнения предыдущих команд, определяются не процессором самостоятельно, а компилятором. Или я не так понял листинг?

Ш>Магии тут нет никакой -- просто схемотехника.


Схемотехника для меня — магия

Ш>Если интересно и есть свободное время, можешь глянуть вот этот документ.

Ш>Особенно главу Pipeline.

Никуда не спешу, так что попробую

F>>Может Itanium тоже так умеет и в ситуации, когда i и j указывают на один объект, инкременты будут выполнены последовательно?


Ш>Зависит от того, что сгенерирует компилятор.


Ш>Пример (условный). В одной строчке -- параллельно выполняющиеся команды.


Ш>i = [SP+offset i]

Ш>j = [SP+offset j]

Ш>R1 <- i R2 <- j

Ш>R3 <- [R1] R4 <- [R2]
Ш>R3++ R4++
Ш>R0 <- R3 + R4 // возвращаем значение в R0
Ш>i <- R3 j <- R4

Ш>В последнеё строчке конфликт доступа к памяти. Проц как-то разрешит его, но это не сделает результат работы функции осмысленным.


Ш>Пусть i и j указывают на одну ячейку со значением 0. Тогда функция вернет 2. При последоватнльном же выполнении, т.е.


Ш>
Ш>int i_res=++(*i); 
Ш>int j_res=++(*j);

Ш>return i_res+j_res; // Всё что мы сделали -- разбили выражение на два подвыражения.
Ш>


Ш>функция вернула бы 3.


Это понятно. Я имел ввиду, что может быть процу удастся последовательно выполнить инкременты даже для первого (параллельного) варианта. Но теперь думаю что это вряд ли.

Afaik, компилятор C++ вправе действовать по первому сценарию, т.е. генерировать более быстрый код. Перепишем второй вариант на псевдоасме, получится менее эффективно:
i = [SP+offset i]
j = [SP+offset j]

R1 <- i     R2 <- j
R3 <- [R1]    
R3++        
i <- R3
R4 <- [R2]
R4++
j <- R4
R0 <- R3 + R4 // возвращаем значение в R0
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[15]: sequence point (по мотивам инкремента)
От: folk Россия  
Дата: 05.06.04 07:10
Оценка:
Здравствуйте, folk, Вы писали:

Ш>>Если интересно и есть свободное время, можешь глянуть вот этот документ.

Ш>>Особенно главу Pipeline.

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

Но этот DSP не является хорошим примером. Насколько я понял, адрес операнда является частью команды, что позволяет легко засекать возникновение зависимостей.
А в контексте этого разговора скорее интересны механизмы определения зависимостей, характерных для RISC-архитектур. Т.е. когда операции загрузки/выгрузки регистров в память и операции над данными в регистрах разделены. На вскидку — можно для каждого регистра хранить соответствующий адрес памяти (если такой есть) для определения зависимостей.
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[15]: sequence point (по мотивам инкремента)
От: Шахтер Интернет  
Дата: 05.06.04 23:13
Оценка:
Здравствуйте, folk, Вы писали:

Ш>>И все они осуществляют приостановку конвейера при возникновении зависимости между входом и выходом. Иначе такой процессор невозможно было бы использовать.


F>Ты уверен что это обязательное условие и что все современные процы это могут?


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

F>Судя по приведенному dupaid'ом asm-листингу, точки, где нужно ожидать окончания выполнения предыдущих команд, определяются не процессором самостоятельно, а компилятором. Или я не так понял листинг?


Не могу сказать, я с Itanium ом не знаком.

Ш>>Магии тут нет никакой -- просто схемотехника.


F>Схемотехника для меня — магия


Да брось -- нет там никакой магии. И вообще -- каждому программеру по осцилографу на стол!
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[16]: sequence point (по мотивам инкремента)
От: Шахтер Интернет  
Дата: 05.06.04 23:33
Оценка:
Здравствуйте, folk, Вы писали:

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


Ш>>>Если интересно и есть свободное время, можешь глянуть вот этот документ.

Ш>>>Особенно главу Pipeline.

F>Прочитал Pipeline, поправь если чего не так понял.

F>Конфликты доступа к памяти там разрешаются с помощью приостановки конвейера.

Да.

F> Но такой конфликт, насколько я понял, происходит при доступе не только к одному адресу, но вообще при доступе к одному блоку памяти, т.е. разрешается именно структурный конфликт, а не зависимость по данным.


Это и есть зависимость по данным. Данные лежать в банках памяти. Доступ к банку, вообще говоря, осуществляется в монопольном режиме.

F>А в случае чтения после записи по одному и тому же адресу происходит чтение значения из внутреннего буфера — это уже оптимальное разрешение зависимости по данным.


Нет. Происходит задержка конвейера.

For example:

STL A, *AR1+ ; AR1 and AR3 points at the same SARAM block.

LD *AR3, B ; This instruction takes 1 additional cycle due to a memory access conflict.

F>Но этот DSP не является хорошим примером.

F>Насколько я понял, адрес операнда является частью команды, что позволяет легко засекать возникновение зависимостей.

Неправильно понял. Пример выше.
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[13]: sequence point (по мотивам инкремента)
От: Павел Кузнецов  
Дата: 06.06.04 14:54
Оценка:
>>> Пример я уже приводил f(i++), f(i++) все должно вычисляться с лева-на-право (это не нарушено), но аргументы следую твоей логике получаем такую последовательность i++ i++ f() f(). Где фундаментальное отличие.
>
> ПК>Фундаментальное отличие в том, что в случае наличия запятой, стандарт явно определяет порядок вычислений:
> ПК>

All side effects (1.9) of the left expression, except for the destruction of temporaries (12.2), are performed before the evaluation of the right expression.

> ПК>В примере без запятой какого-либо определенного порядка нет.
>
> А порядок и не нарушается, в начале вычисляется левый операнд (только в него подмешивается правый операнд ) все его побочные действия завершаются, потом довычисляется правый, и все его побочные действия завершаются. Так что порядок не нарушился в соответствии с этим пунктом. Мы просто начали вычислять второй операнд до точки следования.

Как видишь, в случае наличия запятой, это противоречит процитированной части стандарта, согласно которой, никакого подмешивания правого операнда в левый быть не может.
Posted via RSDN NNTP Server 1.9 alpha
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[12]: sequence point (по мотивам инкремента)
От: dupamid Россия  
Дата: 07.06.04 08:44
Оценка:
Здравствуйте, Шахтер, Вы писали:

Ш>Вот конкретный пример. Можете его откомпилировать под Itanium.

Ш>
Ш>int fun(int *i,int *j) { return ++(*i) + ++(*j); }
Ш>


fun:
{   .mmi
    alloc    r10=ar.pfs,2,0,0,0
    ld4    r9=[r32]
    nop.i    0 ;;
}
{   .mmi
    add    r8=1,r9 ;;
    st4    [r32]=r8 // записываем
    nop.i    0
}
{   .mmi
    ld4    r3=[r33] ;; // и читаем в одной группе
    add    r2=1,r3
    nop.i    0 ;;
}
{   .mib
    st4    [r33]=r2
    add    r8=r8,r2
    br.ret.sptk.many    b0 ;;
}

В данном случае архитектура гарантирует правильность исполнения (мы прочитаем, то что запишем), но может быть потеря производительности.
Re[9]: sequence point (по мотивам инкремента)
От: dupamid Россия  
Дата: 07.06.04 09:20
Оценка:
Здравствуйте, Ivan A. Kosarev, Вы писали:

IAK>Еще вспоминаю давнюю дискуссию между Павлом Кузнецовым и dupamid. Павел говорил о неатомарности присваиваний. Так вот кроме того, что об атомарности (кроме sig_atomic_t и смежного с ним) в стандартах ничего не говорится, существует значительная масса кода в духе

IAK>link = link -> next;
IAK>которая никакой неатомарности не потерпит.

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