Сообщение Re[8]: Производительность .Net на вычислительных задачах от 25.10.2020 7:17
Изменено 25.10.2020 8:04 Sinclair
Re[8]: Производительность .Net на вычислительных задачах
Здравствуйте, vdimas, Вы писали:
V>Соотв., векторизация — это использование векторных команд, например из семейства PCLMUL.
Просто непонятно, что такое использование файла регистров ymm, но без векторизации. С ними же работают simd инструкции.
V>Т.е., в чём тут фишка... Иногда под векторные операции выгодно выделять доп. промежуточную память, например, если эта выделенная память позволит применять векторные инструкции по прямому назначению.
Не очень понятно, каким образом лишняя память тут сможет помочь. Инструкций память-память в интеловском SIMD вроде бы нету.
А если я загрузил данные в регистр, то мне надо не переливать их в дополнительную память, а считать математику.
V>Т.е., порой быстрее будет не поэлементно делать все вычисления, а за раз сделать один тип вычислений над массивом данных, затем другой тип вычислений над промежуточным результатом и т.д., т.е. от поэлементных вычислений уходить в матричные/векторные.
Возможно, но пока что я себе такую ситуацию представить не могу — ну, в том случае, если у нас поэлементное вычисление в принципе возможно. В sauvola — да, там есть отдельный этап предварительного интегрирования, который плохо совмещается с вычислением порога. Ну, то есть известно, что при расчёте порога для [i, j] нам не надо заглядывать в интегралы дальше, чем [i+halfW, j+halfW], поэтому теоретически можно всё засунуть в один цикл, но вряд ли с этого будет как-то особенно много толку.
А вот если у нас есть какая-то поэлементно работающая формула, то я не понимаю, при каких условиях сохранение промежуточного результата даст хоть какой-то эффект.
Ну, вот вычисляем мы из трёх массивов поэлементно r = a + b * c.
Можно, конечно, сначала рассчитать t = b * c при помощи векторных инструкций, сложить его в память.
Потом векторно рассчитывать r = a + t при помощи векторных инструкций, выкинуть t.
Но это же гарантированно просадит производительность, потому что в "тупом" варианте у нас результат b * c уже лежит в регистре, и его нужно только прибавить к a, и в память сложить сразу результат.
То есть мы сначала из
искусственно делаем
, а потом ещё и выносим load(t)/load(a) в другой цикл, чтобы избежать кэширования
А в реальном SIMD есть ещё и комбинированные инструкции ADDMUL, которые вообще позволяют вычислить r в один приём.
Короче, нужны примеры кода, в которых сохранение промежуточного результата в память что-то даст.
V>Понятно, что если размеры векторов/матриц слишком большие, то начинает сказываться эффект охлаждения кеша, поэтому, в реальности граница подбирается экспериментально, т.е. большое изображение может быть обработано участками.
V>Соотв., векторизация — это использование векторных команд, например из семейства PCLMUL.
Просто непонятно, что такое использование файла регистров ymm, но без векторизации. С ними же работают simd инструкции.
V>Т.е., в чём тут фишка... Иногда под векторные операции выгодно выделять доп. промежуточную память, например, если эта выделенная память позволит применять векторные инструкции по прямому назначению.
Не очень понятно, каким образом лишняя память тут сможет помочь. Инструкций память-память в интеловском SIMD вроде бы нету.
А если я загрузил данные в регистр, то мне надо не переливать их в дополнительную память, а считать математику.
V>Т.е., порой быстрее будет не поэлементно делать все вычисления, а за раз сделать один тип вычислений над массивом данных, затем другой тип вычислений над промежуточным результатом и т.д., т.е. от поэлементных вычислений уходить в матричные/векторные.
Возможно, но пока что я себе такую ситуацию представить не могу — ну, в том случае, если у нас поэлементное вычисление в принципе возможно. В sauvola — да, там есть отдельный этап предварительного интегрирования, который плохо совмещается с вычислением порога. Ну, то есть известно, что при расчёте порога для [i, j] нам не надо заглядывать в интегралы дальше, чем [i+halfW, j+halfW], поэтому теоретически можно всё засунуть в один цикл, но вряд ли с этого будет как-то особенно много толку.
А вот если у нас есть какая-то поэлементно работающая формула, то я не понимаю, при каких условиях сохранение промежуточного результата даст хоть какой-то эффект.
Ну, вот вычисляем мы из трёх массивов поэлементно r = a + b * c.
Можно, конечно, сначала рассчитать t = b * c при помощи векторных инструкций, сложить его в память.
Потом векторно рассчитывать r = a + t при помощи векторных инструкций, выкинуть t.
Но это же гарантированно просадит производительность, потому что в "тупом" варианте у нас результат b * c уже лежит в регистре, и его нужно только прибавить к a, и в память сложить сразу результат.
То есть мы сначала из
load(b)
load(c)
t=mul(b, c)
load(a)
r=add(t, a)
save(r)
искусственно делаем
load(b)
load(c)
t=mul(b, c)
save(t)
load(t)
load(a)
r=add(t, a)
save(r)
, а потом ещё и выносим load(t)/load(a) в другой цикл, чтобы избежать кэширования
А в реальном SIMD есть ещё и комбинированные инструкции ADDMUL, которые вообще позволяют вычислить r в один приём.
Короче, нужны примеры кода, в которых сохранение промежуточного результата в память что-то даст.
V>Понятно, что если размеры векторов/матриц слишком большие, то начинает сказываться эффект охлаждения кеша, поэтому, в реальности граница подбирается экспериментально, т.е. большое изображение может быть обработано участками.
Re[8]: Производительность .Net на вычислительных задачах
Здравствуйте, vdimas, Вы писали:
V>Соотв., векторизация — это использование векторных команд, например из семейства PCLMUL.
Просто непонятно, что такое использование файла регистров ymm, но без векторизации. С ними же работают simd инструкции.
Всё, я понял, ткнули носом.
Я просто вообще был не в курсе про существование scalar инструкций с векторными регистрами.
V>Т.е., в чём тут фишка... Иногда под векторные операции выгодно выделять доп. промежуточную память, например, если эта выделенная память позволит применять векторные инструкции по прямому назначению.
Не очень понятно, каким образом лишняя память тут сможет помочь. Инструкций память-память в интеловском SIMD вроде бы нету.
А если я загрузил данные в регистр, то мне надо не переливать их в дополнительную память, а считать математику.
V>Т.е., порой быстрее будет не поэлементно делать все вычисления, а за раз сделать один тип вычислений над массивом данных, затем другой тип вычислений над промежуточным результатом и т.д., т.е. от поэлементных вычислений уходить в матричные/векторные.
Возможно, но пока что я себе такую ситуацию представить не могу — ну, в том случае, если у нас поэлементное вычисление в принципе возможно. В sauvola — да, там есть отдельный этап предварительного интегрирования, который плохо совмещается с вычислением порога. Ну, то есть известно, что при расчёте порога для [i, j] нам не надо заглядывать в интегралы дальше, чем [i+halfW, j+halfW], поэтому теоретически можно всё засунуть в один цикл, но вряд ли с этого будет как-то особенно много толку.
А вот если у нас есть какая-то поэлементно работающая формула, то я не понимаю, при каких условиях сохранение промежуточного результата даст хоть какой-то эффект.
Ну, вот вычисляем мы из трёх массивов поэлементно r = a + b * c.
Можно, конечно, сначала рассчитать t = b * c при помощи векторных инструкций, сложить его в память.
Потом векторно рассчитывать r = a + t при помощи векторных инструкций, выкинуть t.
Но это же гарантированно просадит производительность, потому что в "тупом" варианте у нас результат b * c уже лежит в регистре, и его нужно только прибавить к a, и в память сложить сразу результат.
То есть мы сначала из
искусственно делаем
, а потом ещё и выносим load(t)/load(a) в другой цикл, чтобы избежать кэширования
А в реальном SIMD есть ещё и комбинированные инструкции ADDMUL, которые вообще позволяют вычислить r в один приём.
Короче, нужны примеры кода, в которых сохранение промежуточного результата в память что-то даст.
V>Понятно, что если размеры векторов/матриц слишком большие, то начинает сказываться эффект охлаждения кеша, поэтому, в реальности граница подбирается экспериментально, т.е. большое изображение может быть обработано участками.
V>Соотв., векторизация — это использование векторных команд, например из семейства PCLMUL.
Всё, я понял, ткнули носом.
Я просто вообще был не в курсе про существование scalar инструкций с векторными регистрами.
V>Т.е., в чём тут фишка... Иногда под векторные операции выгодно выделять доп. промежуточную память, например, если эта выделенная память позволит применять векторные инструкции по прямому назначению.
Не очень понятно, каким образом лишняя память тут сможет помочь. Инструкций память-память в интеловском SIMD вроде бы нету.
А если я загрузил данные в регистр, то мне надо не переливать их в дополнительную память, а считать математику.
V>Т.е., порой быстрее будет не поэлементно делать все вычисления, а за раз сделать один тип вычислений над массивом данных, затем другой тип вычислений над промежуточным результатом и т.д., т.е. от поэлементных вычислений уходить в матричные/векторные.
Возможно, но пока что я себе такую ситуацию представить не могу — ну, в том случае, если у нас поэлементное вычисление в принципе возможно. В sauvola — да, там есть отдельный этап предварительного интегрирования, который плохо совмещается с вычислением порога. Ну, то есть известно, что при расчёте порога для [i, j] нам не надо заглядывать в интегралы дальше, чем [i+halfW, j+halfW], поэтому теоретически можно всё засунуть в один цикл, но вряд ли с этого будет как-то особенно много толку.
А вот если у нас есть какая-то поэлементно работающая формула, то я не понимаю, при каких условиях сохранение промежуточного результата даст хоть какой-то эффект.
Ну, вот вычисляем мы из трёх массивов поэлементно r = a + b * c.
Можно, конечно, сначала рассчитать t = b * c при помощи векторных инструкций, сложить его в память.
Потом векторно рассчитывать r = a + t при помощи векторных инструкций, выкинуть t.
Но это же гарантированно просадит производительность, потому что в "тупом" варианте у нас результат b * c уже лежит в регистре, и его нужно только прибавить к a, и в память сложить сразу результат.
То есть мы сначала из
load(b)
load(c)
t=mul(b, c)
load(a)
r=add(t, a)
save(r)
искусственно делаем
load(b)
load(c)
t=mul(b, c)
save(t)
load(t)
load(a)
r=add(t, a)
save(r)
, а потом ещё и выносим load(t)/load(a) в другой цикл, чтобы избежать кэширования
А в реальном SIMD есть ещё и комбинированные инструкции ADDMUL, которые вообще позволяют вычислить r в один приём.
Короче, нужны примеры кода, в которых сохранение промежуточного результата в память что-то даст.
V>Понятно, что если размеры векторов/матриц слишком большие, то начинает сказываться эффект охлаждения кеша, поэтому, в реальности граница подбирается экспериментально, т.е. большое изображение может быть обработано участками.