Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.77/22: Рейтинг темы: голосов - 22, средняя оценка - 4.77
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30

Избыточное копирование объекта при реализации оператора умножения и оператора присваивания

21.03.2016, 18:43. Показов 5615. Ответов 84
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Есть класс работы с матрицами. Есть операция умножения матриц, описанная как оператор класса. В данном коротком примере я просто моделирую ситуацию. Реальное наполнение класса принципиальной разницы не играет, нужно просто понимать, что оператор умножения будет иметь большой код, оператор присваивания в реализации тоже будет не пустым. Эти места в примере засвечены комментариями

C++
#include <cstdio>
 
class Matrix
{
  private:
    // внутренние данные матрицы
 
  public:
    Matrix ();
    Matrix (const Matrix&);
    ~Matrix ();
 
    Matrix& operator=(const Matrix& a);
    Matrix operator*(const Matrix& a) const;
};
 
Matrix::Matrix ()
{
  printf ("Matrix ()\n");
};
 
Matrix::Matrix (const Matrix&)
{
  printf ("Matrix (const Matrix&)\n");
};
 
Matrix::~Matrix ()
{
  printf ("~Matrix ()\n");
};
 
Matrix& Matrix::operator=(const Matrix& a)
{
  printf ("operator=(const Matrix&)\n");
 
  // тут как бы код, копирущий данные из "a" в "this"
 
  return *this;
}
 
Matrix Matrix::operator*(const Matrix& a) const
{
  printf ("operator*(const Matrix&)\n");
 
  Matrix result;
 
  // тут как бы код, умножающий "a" и "this" и записывающий
  // данные в "result"
 
  return result;
}
 
Matrix a, b, c;
 
int main (void)
{
  printf ("------------------\n");
  a = b * c;
  printf ("------------------\n");
}
Исполнение:

Code
$ g++-4.8 t.cc
$ ./a.out
Matrix ()
Matrix ()
Matrix ()
------------------
operator*(const Matrix&)
Matrix ()
operator=(const Matrix&)
~Matrix ()
------------------
~Matrix ()
~Matrix ()
~Matrix ()
Нас интересует только фрагмент печати внутри функции main (т.е. между палками)

Посмотрим на ассемблерный код. Компилирую с опцией -fno-inline, чтобы оставаться с короткой программой и не разводить геморрой по борьбе с inline'ом со стороны компилятора. В общем случае тела операторов класса Matrix будут в отдельном файле и НЕ будут доступны для inline'а. Опцию -fno-exceptions подаю, чтобы было меньше мусора в коде

Code
$ g++ t.cc -O2 -fno-inline -fno-exceptions
$ cat t.s
...
    leal    -9(%ebp), %ebx
    subl    $32, %esp
    movl    %ebx, (%esp)
    movl    $c, 8(%esp)
    movl    $b, 4(%esp)
    call    _ZN6MatrixmlERKS_  <- operator*
 
    subl    $4, %esp
    movl    %ebx, 4(%esp)
    movl    $a, (%esp)
    call    _ZN6MatrixaSERKS_  <- operator=
...
Таким образом мы видим, что построился код, схематично эквивалентный следующему примеру на Си. На всякий случай напоминаю, что с точки зрения семантики C++ выражение "a = b * c" трактуется как "a.operator= (b.operator* (c))"

C
typedef struct { /* внутренности */ } Matrix;
 
extern void operator_assign (Matrix *this, const Matrix *value);
extern void operator_mul (Matrix *result, const Matrix *this, const Matrix *operand2);
 
Matrix a, b, c;
 
int main (void)
{
  Matrix tmp;
 
  operator_mul (&tmp, &b, &c); /* tmp = b.operator* (c) */
  operator_assign (&a, &tmp);  /* a.operator= (tmp) */
}
Мы видим, что в этом коде делается ненужное действие в виде лишнего оператора присваивания. Для умножения матриц эффективный код на Си выглядел бы как

C
operator_mul (&a, &b, &c);
т.е. без заведения промежуточной переменной и дополнительного копирования (которое представляет собой ненужные накладные расходы)

Вопрос. Как правильно написать текст на C++, чтобы получить код, эквивалентный вышеприведённой эффективной реализации на C? Оставаясь при этом в объёме стандарта C++98. Оставляя исходник в понятном и читабельном виде, без использования извращений типа семиэтажных шаблонов и т.п.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
21.03.2016, 18:43
Ответы с готовыми решениями:

Неправильная работа оператора присваивания после работы оператора суммирования
Доброго времени суток. У меня есть класс вектор class TVector {//ewde public: TVector(); //Vector(Vector &amp;v); ...

От каких ошибок страхует Const при перегрузке оператора присваивания
Здравствуйте. Вопрос имею теоретический. В классе A перегружается оператор присваивания, объявление выглядит так: const A operator =...

Почему при перегрузке оператора присваивания, возвращаемое значение не константно?
Почему при перегрузке оператора присваивания, возвращаемое значение - someClass &amp; operator=(const someClass&amp; rhl), а не const...

84
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
23.03.2016, 15:08  [ТС]
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Nosey Посмотреть сообщение
Далеко не только избавится компилятор от копирования, он сделает гораздо больше. И планировать там в 99% ситуациях ничего не надо:
флаги: -O3 -flto
Оптимизации бывают разные. Я говорил совсем о другом. Для простоты возьмём твой код, выкинем оттуда всё ненужное и оставим только горячий фрагмент - умножение матриц

Кликните здесь для просмотра всего текста
C++
struct Matrix4
{
private: 
  float mat[16];
public:
  Matrix4();
  float operator[](int ind) const { return mat[ind]; }
  float& operator[](int ind) { return mat[ind]; }
 
  static void operator_mul(Matrix4& ret, const Matrix4& mat, const Matrix4& m);
};
 
void Matrix4::operator_mul(Matrix4& ret, const Matrix4& mat, const Matrix4& m)
{
  ret[0] = mat[0] * m[0] + mat[4] * m[1] + mat[8] * m[2] + mat[12] * m[3];
  ret[1] = mat[1] * m[0] + mat[5] * m[1] + mat[9] * m[2] + mat[13] * m[3];
  ret[2] = mat[2] * m[0] + mat[6] * m[1] + mat[10] * m[2] + mat[14] * m[3];
  ret[3] = mat[3] * m[0] + mat[7] * m[1] + mat[11] * m[2] + mat[15] * m[3];
  ret[4] = mat[0] * m[4] + mat[4] * m[5] + mat[8] * m[6] + mat[12] * m[7];
  ret[5] = mat[1] * m[4] + mat[5] * m[5] + mat[9] * m[6] + mat[13] * m[7];
  ret[6] = mat[2] * m[4] + mat[6] * m[5] + mat[10] * m[6] + mat[14] * m[7];
  ret[7] = mat[3] * m[4] + mat[7] * m[5] + mat[11] * m[6] + mat[15] * m[7];
  ret[8] = mat[0] * m[8] + mat[4] * m[9] + mat[8] * m[10] + mat[12] * m[11];
  ret[9] = mat[1] * m[8] + mat[5] * m[9] + mat[9] * m[10] + mat[13] * m[11];
  ret[10] = mat[2] * m[8] + mat[6] * m[9] + mat[10] * m[10] + mat[14] * m[11];
  ret[11] = mat[3] * m[8] + mat[7] * m[9] + mat[11] * m[10] + mat[15] * m[11];
  ret[12] = mat[0] * m[12] + mat[4] * m[13] + mat[8] * m[14] + mat[12] * m[15];
  ret[13] = mat[1] * m[12] + mat[5] * m[13] + mat[9] * m[14] + mat[13] * m[15];
  ret[14] = mat[2] * m[12] + mat[6] * m[13] + mat[10] * m[14] + mat[14] * m[15];
  ret[15] = mat[3] * m[12] + mat[7] * m[13] + mat[11] * m[14] + mat[15] * m[15];
}


Скомпилируем его "не думая":

Code
$ g++ t.cc -O3 -S
$ cat t.s
Получим такой код:

Кликните здесь для просмотра всего текста
Code
_ZN7Matrix412operator_mulERS_RKS_S2_:
.LFB2:
    .cfi_startproc
    movss   (%rsi), %xmm0
    movss   (%rdx), %xmm1
    mulss   %xmm0, %xmm1
    movss   16(%rsi), %xmm0
    mulss   4(%rdx), %xmm0
    addss   %xmm1, %xmm0
    movss   32(%rsi), %xmm1
    mulss   8(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   48(%rsi), %xmm1
    mulss   12(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   %xmm0, (%rdi)
    movss   4(%rsi), %xmm0
    movss   (%rdx), %xmm1
    mulss   %xmm0, %xmm1
    movss   20(%rsi), %xmm0
    mulss   4(%rdx), %xmm0
    addss   %xmm1, %xmm0
    movss   36(%rsi), %xmm1
    mulss   8(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   52(%rsi), %xmm1
    mulss   12(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   %xmm0, 4(%rdi)
    movss   8(%rsi), %xmm0
    movss   (%rdx), %xmm1
    mulss   %xmm0, %xmm1
    movss   24(%rsi), %xmm0
    mulss   4(%rdx), %xmm0
    addss   %xmm1, %xmm0
    movss   40(%rsi), %xmm1
    mulss   8(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   56(%rsi), %xmm1
    mulss   12(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   %xmm0, 8(%rdi)
    movss   12(%rsi), %xmm0
    movss   (%rdx), %xmm1
    mulss   %xmm0, %xmm1
    movss   28(%rsi), %xmm0
    mulss   4(%rdx), %xmm0
    addss   %xmm1, %xmm0
    movss   44(%rsi), %xmm1
    mulss   8(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   60(%rsi), %xmm1
    mulss   12(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   %xmm0, 12(%rdi)
    movss   (%rsi), %xmm0
    movss   16(%rdx), %xmm1
    mulss   %xmm0, %xmm1
    movss   16(%rsi), %xmm0
    mulss   20(%rdx), %xmm0
    addss   %xmm1, %xmm0
    movss   32(%rsi), %xmm1
    mulss   24(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   48(%rsi), %xmm1
    mulss   28(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   %xmm0, 16(%rdi)
    movss   4(%rsi), %xmm0
    movss   16(%rdx), %xmm1
    mulss   %xmm0, %xmm1
    movss   20(%rsi), %xmm0
    mulss   20(%rdx), %xmm0
    addss   %xmm1, %xmm0
    movss   36(%rsi), %xmm1
    mulss   24(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   52(%rsi), %xmm1
    mulss   28(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   %xmm0, 20(%rdi)
    movss   8(%rsi), %xmm0
    movss   16(%rdx), %xmm1
    mulss   %xmm0, %xmm1
    movss   24(%rsi), %xmm0
    mulss   20(%rdx), %xmm0
    addss   %xmm1, %xmm0
    movss   40(%rsi), %xmm1
    mulss   24(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   56(%rsi), %xmm1
    mulss   28(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   %xmm0, 24(%rdi)
    movss   12(%rsi), %xmm0
    movss   16(%rdx), %xmm1
    mulss   %xmm0, %xmm1
    movss   28(%rsi), %xmm0
    mulss   20(%rdx), %xmm0
    addss   %xmm1, %xmm0
    movss   44(%rsi), %xmm1
    mulss   24(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   60(%rsi), %xmm1
    mulss   28(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   %xmm0, 28(%rdi)
    movss   (%rsi), %xmm0
    movss   32(%rdx), %xmm1
    mulss   %xmm0, %xmm1
    movss   16(%rsi), %xmm0
    mulss   36(%rdx), %xmm0
    addss   %xmm1, %xmm0
    movss   32(%rsi), %xmm1
    mulss   40(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   48(%rsi), %xmm1
    mulss   44(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   %xmm0, 32(%rdi)
    movss   4(%rsi), %xmm0
    movss   32(%rdx), %xmm1
    mulss   %xmm0, %xmm1
    movss   20(%rsi), %xmm0
    mulss   36(%rdx), %xmm0
    addss   %xmm1, %xmm0
    movss   36(%rsi), %xmm1
    mulss   40(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   52(%rsi), %xmm1
    mulss   44(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   %xmm0, 36(%rdi)
    movss   8(%rsi), %xmm0
    movss   32(%rdx), %xmm1
    mulss   %xmm0, %xmm1
    movss   24(%rsi), %xmm0
    mulss   36(%rdx), %xmm0
    addss   %xmm1, %xmm0
    movss   40(%rsi), %xmm1
    mulss   40(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   56(%rsi), %xmm1
    mulss   44(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   %xmm0, 40(%rdi)
    movss   12(%rsi), %xmm0
    mulss   32(%rdx), %xmm0
    movaps  %xmm0, %xmm1
    movss   28(%rsi), %xmm0
    mulss   36(%rdx), %xmm0
    addss   %xmm1, %xmm0
    movss   44(%rsi), %xmm1
    mulss   40(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   60(%rsi), %xmm1
    mulss   44(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   %xmm0, 44(%rdi)
    movss   (%rsi), %xmm0
    movss   48(%rdx), %xmm1
    mulss   %xmm0, %xmm1
    movss   16(%rsi), %xmm0
    mulss   52(%rdx), %xmm0
    addss   %xmm1, %xmm0
    movss   32(%rsi), %xmm1
    mulss   56(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   48(%rsi), %xmm1
    mulss   60(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   %xmm0, 48(%rdi)
    movss   4(%rsi), %xmm0
    mulss   48(%rdx), %xmm0
    movaps  %xmm0, %xmm1
    movss   20(%rsi), %xmm0
    mulss   52(%rdx), %xmm0
    addss   %xmm1, %xmm0
    movss   36(%rsi), %xmm1
    mulss   56(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   52(%rsi), %xmm1
    mulss   60(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   %xmm0, 52(%rdi)
    movss   8(%rsi), %xmm0
    movss   48(%rdx), %xmm1
    mulss   %xmm0, %xmm1
    movss   24(%rsi), %xmm0
    mulss   52(%rdx), %xmm0
    addss   %xmm1, %xmm0
    movss   40(%rsi), %xmm1
    mulss   56(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   56(%rsi), %xmm1
    mulss   60(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   %xmm0, 56(%rdi)
    movss   12(%rsi), %xmm0
    mulss   48(%rdx), %xmm0
    movaps  %xmm0, %xmm1
    movss   28(%rsi), %xmm0
    mulss   52(%rdx), %xmm0
    addss   %xmm1, %xmm0
    movss   44(%rsi), %xmm1
    mulss   56(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   60(%rsi), %xmm1
    mulss   60(%rdx), %xmm1
    addss   %xmm1, %xmm0
    movss   %xmm0, 60(%rdi)
    ret
    .cfi_endproc
.LFE2:
    .size   _ZN7Matrix412operator_mulERS_RKS_S2_, .-_ZN7Matrix412operator_mulERS_RKS_S2_


Скомпилируем его "по умному" (под конкретную архитектуру):

Code
$ g++ t.cc -O3 -march=haswell -S
$ cat t.s
Получим совсем другой код, с использованием комбинированных операций:

Кликните здесь для просмотра всего текста
Code
_ZN7Matrix412operator_mulERS_RKS_S2_:
.LFB2:
    .cfi_startproc
    vmovss  (%rsi), %xmm1
    vmovss  32(%rsi), %xmm2
    vmovss  48(%rsi), %xmm3
    vmovss  16(%rsi), %xmm0
    vmulss  4(%rdx), %xmm0, %xmm0
    vfmadd231ss (%rdx), %xmm1, %xmm0
    vfmadd231ss 8(%rdx), %xmm2, %xmm0
    vfmadd231ss 12(%rdx), %xmm3, %xmm0
    vmovss  %xmm0, (%rdi)
    vmovss  4(%rsi), %xmm4
    vmovss  52(%rsi), %xmm6
    vmovss  20(%rsi), %xmm0
    vmovss  36(%rsi), %xmm5
    vmulss  4(%rdx), %xmm0, %xmm0
    vfmadd231ss (%rdx), %xmm4, %xmm0
    vfmadd231ss 8(%rdx), %xmm5, %xmm0
    vfmadd231ss 12(%rdx), %xmm6, %xmm0
    vmovss  %xmm0, 4(%rdi)
    vmovss  8(%rsi), %xmm7
    vmovss  40(%rsi), %xmm1
    vmovss  56(%rsi), %xmm2
    vmovss  24(%rsi), %xmm0
    vmulss  4(%rdx), %xmm0, %xmm0
    vfmadd231ss (%rdx), %xmm7, %xmm0
    vfmadd231ss 8(%rdx), %xmm1, %xmm0
    vfmadd231ss 12(%rdx), %xmm2, %xmm0
    vmovss  %xmm0, 8(%rdi)
    vmovss  12(%rsi), %xmm3
    vmovss  44(%rsi), %xmm4
    vmovss  28(%rsi), %xmm0
    vmulss  4(%rdx), %xmm0, %xmm0
    vfmadd231ss (%rdx), %xmm3, %xmm0
    vfmadd231ss 8(%rdx), %xmm4, %xmm0
    vmovss  60(%rsi), %xmm5
    vfmadd231ss 12(%rdx), %xmm5, %xmm0
    vmovss  %xmm0, 12(%rdi)
    vmovss  (%rsi), %xmm6
    vmovss  32(%rsi), %xmm7
    vmovss  48(%rsi), %xmm1
    vmovss  16(%rsi), %xmm0
    vmulss  20(%rdx), %xmm0, %xmm0
    vfmadd231ss 16(%rdx), %xmm6, %xmm0
    vfmadd231ss 24(%rdx), %xmm7, %xmm0
    vfmadd231ss 28(%rdx), %xmm1, %xmm0
    vmovss  %xmm0, 16(%rdi)
    vmovss  4(%rsi), %xmm2
    vmovss  36(%rsi), %xmm3
    vmovss  52(%rsi), %xmm4
    vmovss  20(%rsi), %xmm0
    vmulss  20(%rdx), %xmm0, %xmm0
    vfmadd231ss 16(%rdx), %xmm2, %xmm0
    vfmadd231ss 24(%rdx), %xmm3, %xmm0
    vfmadd231ss 28(%rdx), %xmm4, %xmm0
    vmovss  %xmm0, 20(%rdi)
    vmovss  8(%rsi), %xmm5
    vmovss  40(%rsi), %xmm6
    vmovss  56(%rsi), %xmm7
    vmovss  24(%rsi), %xmm0
    vmulss  20(%rdx), %xmm0, %xmm0
    vfmadd231ss 16(%rdx), %xmm5, %xmm0
    vfmadd231ss 24(%rdx), %xmm6, %xmm0
    vfmadd231ss 28(%rdx), %xmm7, %xmm0
    vmovss  %xmm0, 24(%rdi)
    vmovss  28(%rsi), %xmm0
    vmovss  12(%rsi), %xmm1
    vmulss  20(%rdx), %xmm0, %xmm0
    vfmadd231ss 16(%rdx), %xmm1, %xmm0
    vmovss  44(%rsi), %xmm2
    vfmadd231ss 24(%rdx), %xmm2, %xmm0
    vmovss  60(%rsi), %xmm3
    vfmadd231ss 28(%rdx), %xmm3, %xmm0
    vmovss  %xmm0, 28(%rdi)
    vmovss  (%rsi), %xmm4
    vmovss  32(%rsi), %xmm5
    vmovss  48(%rsi), %xmm6
    vmovss  16(%rsi), %xmm0
    vmulss  36(%rdx), %xmm0, %xmm0
    vfmadd231ss 32(%rdx), %xmm4, %xmm0
    vfmadd231ss 40(%rdx), %xmm5, %xmm0
    vfmadd231ss 44(%rdx), %xmm6, %xmm0
    vmovss  %xmm0, 32(%rdi)
    vmovss  4(%rsi), %xmm7
    vmovss  36(%rsi), %xmm1
    vmovss  52(%rsi), %xmm2
    vmovss  20(%rsi), %xmm0
    vmulss  36(%rdx), %xmm0, %xmm0
    vfmadd231ss 32(%rdx), %xmm7, %xmm0
    vfmadd231ss 40(%rdx), %xmm1, %xmm0
    vfmadd231ss 44(%rdx), %xmm2, %xmm0
    vmovss  %xmm0, 36(%rdi)
    vmovss  8(%rsi), %xmm3
    vmovss  40(%rsi), %xmm4
    vmovss  56(%rsi), %xmm5
    vmovss  24(%rsi), %xmm0
    vmulss  36(%rdx), %xmm0, %xmm0
    vfmadd231ss 32(%rdx), %xmm3, %xmm0
    vfmadd231ss 40(%rdx), %xmm4, %xmm0
    vfmadd231ss 44(%rdx), %xmm5, %xmm0
    vmovss  %xmm0, 40(%rdi)
    vmovss  28(%rsi), %xmm0
    vmovss  12(%rsi), %xmm6
    vmovss  44(%rsi), %xmm7
    vmovss  60(%rsi), %xmm1
    vmulss  36(%rdx), %xmm0, %xmm0
    vfmadd231ss 32(%rdx), %xmm6, %xmm0
    vfmadd231ss 40(%rdx), %xmm7, %xmm0
    vfmadd231ss 44(%rdx), %xmm1, %xmm0
    vmovss  %xmm0, 44(%rdi)
    vmovss  (%rsi), %xmm2
    vmovss  48(%rsi), %xmm4
    vmovss  16(%rsi), %xmm0
    vmovss  32(%rsi), %xmm3
    vmulss  52(%rdx), %xmm0, %xmm0
    vfmadd231ss 48(%rdx), %xmm2, %xmm0
    vfmadd231ss 56(%rdx), %xmm3, %xmm0
    vfmadd231ss 60(%rdx), %xmm4, %xmm0
    vmovss  %xmm0, 48(%rdi)
    vmovss  4(%rsi), %xmm5
    vmovss  36(%rsi), %xmm6
    vmovss  20(%rsi), %xmm0
    vmovss  52(%rsi), %xmm7
    vmulss  52(%rdx), %xmm0, %xmm0
    vfmadd231ss 48(%rdx), %xmm5, %xmm0
    vfmadd231ss 56(%rdx), %xmm6, %xmm0
    vfmadd231ss 60(%rdx), %xmm7, %xmm0
    vmovss  %xmm0, 52(%rdi)
    vmovss  24(%rsi), %xmm0
    vmovss  8(%rsi), %xmm1
    vmulss  52(%rdx), %xmm0, %xmm0
    vfmadd231ss 48(%rdx), %xmm1, %xmm0
    vmovss  40(%rsi), %xmm2
    vfmadd231ss 56(%rdx), %xmm2, %xmm0
    vmovss  56(%rsi), %xmm3
    vfmadd231ss 60(%rdx), %xmm3, %xmm0
    vmovss  %xmm0, 56(%rdi)
    vmovss  28(%rsi), %xmm0
    vmovss  12(%rsi), %xmm4
    vmulss  52(%rdx), %xmm0, %xmm0
    vfmadd231ss 48(%rdx), %xmm4, %xmm0
    vmovss  44(%rsi), %xmm5
    vfmadd231ss 56(%rdx), %xmm5, %xmm0
    vmovss  60(%rsi), %xmm6
    vfmadd231ss 60(%rdx), %xmm6, %xmm0
    vmovss  %xmm0, 60(%rdi)
    ret
    .cfi_endproc
.LFE2:
    .size   _ZN7Matrix412operator_mulERS_RKS_S2_, .-_ZN7Matrix412operator_mulERS_RKS_S2_


Я не разбираюсь в intel'овской архитектуре и мне совершенно впадлу разбираться с опциями компилятора, чтобы получить максимально быстро работающий код конкретно под мою модель процессора. Но если библиотека работы с матрицами предоставлена мне в виде файла *.h, внутри которого написано тело (для инлайна со стороны компилятора), то я, как простой пользователь, скорее всего не смогу получить предельной производительности. Потому что для работы с этим файлом *.h мне придётся прочитать кучу мануалов, чтобы понять, с какими же опциями мне надо собирать. Да и неизвестно ещё, может получиться так, что эти опции ускорят код умножения матрицы, но замедлят что-нибудь другое. А вот если мне уже выдана библиотека в виде бинарника, над которой уже поработали профессионалы, то я с очень большой вероятностью получу более быстрый код, чем когда буду корячиться самостоятельно с файлом *.h. К тому же вариант с файлом *.h очень сильно зависит от компилятора: один умеет эффективно инлайнить, другой не умеет, в одном уже появилась поддержка топовых версий процессора, в другом ещё не появилась. Т.е. оптимизации в жизни бывают разных уровней. Инлайн - это машинно-НЕзависимая оптимизация, использование всяких векторных аппаратных инструкций - уже машинно-зависимая. И при написании эффективного кода нужно учитывать в том числе и такие вещи
0
 Аватар для avgoor
1550 / 877 / 179
Регистрация: 05.12.2015
Сообщений: 2,555
23.03.2016, 15:29
Цитата Сообщение от Evg Посмотреть сообщение
Но если библиотека работы с матрицами предоставлена мне в виде файла *.h, внутри которого написано тело (для инлайна со стороны компилятора), то я, как простой пользователь, скорее всего не смогу получить предельной производительности.
Это C++. Тут, в отличае от C, нет бинарной совместимости. Т.е. по-другому никак.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
23.03.2016, 15:32  [ТС]
Цитата Сообщение от avgoor Посмотреть сообщение
Это C++. Тут, в отличае от C, нет бинарной совместимости. Т.е. по-другому никак
Так через технологию того, что в теле оператора вызывается функция в стиле Си сие же нормально реализуется. Таким образом, снимаем с пользователя геморрой с оптимизациями под процессор
0
 Аватар для avgoor
1550 / 877 / 179
Регистрация: 05.12.2015
Сообщений: 2,555
23.03.2016, 15:37
Цитата Сообщение от Evg Посмотреть сообщение
Так через технологию того, что в теле оператора вызывается функция в стиле Си сие же нормально реализуется.
Так а я про что?
Если библиотека поставляется в бинарном виде - то наружу торчат extern "C" + хедер с инлайн обертками. Просто эти обертки - более высокая абстракция и оптимизации там могут быть платформо-независимыми с шаблонной магией. А весь низкоуровневый код упрятан внутрь.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
23.03.2016, 15:42  [ТС]
Это понятно. Я просто рассказывал Nosey'у про оптимизации (а точнее, их разные виды). Если inline должен выполнять любой более-менее приличный компилятор C++ (без этого с C++ никак), то с платформо-зависимыми оптимизациями всё намного сложнее. И упрятав такой оптимизированный код в бинарник, поставщик библиотеки в общем случае для пользователя гарантирует более эффективный код, чем в варианте, когда пользователю выдаётся хидер в чистом стиле Си++ (т.е. со всеми потрохами), а пользователь сам не сумеет применить к нему платформо-зависимые оптимизации
0
 Аватар для avgoor
1550 / 877 / 179
Регистрация: 05.12.2015
Сообщений: 2,555
23.03.2016, 15:49
Evg, Есть 2 но:
1) Интел поймали за ж..у с их "платформо-зависимыми оптимизациями".
2) Если пользователь использует "плохой" компилятор, то и на оптимальность реализации ему покласть.
0
 Аватар для Nosey
1379 / 406 / 144
Регистрация: 22.10.2014
Сообщений: 872
23.03.2016, 16:05
Цитата Сообщение от avgoor Посмотреть сообщение
Возможно и так. Если библиотека скомпилирована в g++, например, а вы используете ms (который правила декорирования вообще не публикует)
Наверное, со студией практически не работал.

Цитата Сообщение от Evg Посмотреть сообщение
Я пока не читал, но подозреваю, что там опять всё построено на том же принципе, что компилятор должен видеть потроха операторов
Нет, это не обязательно, там просто враппер реализующий ленивые вычисления. Он сам конечно должен быть доступен для инлайнинга. Т.е. код вида a = b+c, враппер после простого инлайна(который сможет любой компилятор) превратит в С подход opAdd(a,b,c); но этот код уже не будет инициализацией, а будет "присваиванием" переменной а, следовательно не каждый компилятор сможет это оптимизировать также хорошо, как Mat a = b + c;. Но в случае с С подходом с уже выделенной памятью, это не проблема конечно.

Цитата Сообщение от Evg Посмотреть сообщение
Оптимизации бывают разные. Я говорил совсем о другом. Для простоты возьмём твой код, выкинем оттуда всё ненужное и оставим только горячий фрагмент - умножение матриц
....
Получим совсем другой код, с использованием комбинированных операций:
Однозначно согласен, но это крайности. Очень редкие крайности.
Незабываем что разговор о статической линковке. В динамике используем С подход и ни как иначе.

Цитата Сообщение от Evg Посмотреть сообщение
Я не разбираюсь в intel'овской архитектуре и мне совершенно впадлу разбираться с опциями компилятора, чтобы получить максимально быстро работающий код конкретно под мою модель процессора. Но если библиотека работы с матрицами предоставлена мне в виде файла *.h, внутри которого написано тело (для инлайна со стороны компилятора), то я, как простой пользователь, скорее всего не смогу получить предельной производительности. Потому что для работы с этим файлом *.h мне придётся прочитать кучу мануалов, чтобы понять, с какими же опциями мне надо собирать. Да и неизвестно ещё, может получиться так, что эти опции ускорят код умножения матрицы, но замедлят что-нибудь другое.
Вы поставляете обычный клиентский софт под каждую архитектуру процессора? так что вам нужна сотня библиотек специально собранных? Это риторический вопрос )
Также если вы пишите воистину что-то требующее такой производительности, то незнание целевой архитектуры будет меньшая из ваших бед, ибо это просто недельное чтение мануалов. И вам придется их прочитать.
Если же это не клиентский софт а бэкенд, то тут точно придется прочитать мануалы, ибо писать под определенное железо и лень в прочтении мануалов по 10 флагам - плохо сочетаются )

Но самое важное в нашей дискуссии, это соотношение затрат на работу с интерфейсом к затратам на саму внутреннюю работу библиотеки.
Например, openGl, помните изменения его интерфейса от версии к версии? Правильно, ранее в Gl1 когда мы не могли себе позволить разрешение 800*600, мы рисовали по точкам, а сейчас в Gl4 мы просим oGL отрисовать нам VAO включающий в себя гору данных для отрисовки. Интерфейс скрывает за собой все больше и больше, так почему вы желаете вынести перемножение матриц в библиотеку? Это опять же риторический вопрос.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
23.03.2016, 16:09  [ТС]
Цитата Сообщение от avgoor Посмотреть сообщение
1) Интел поймали за ж..у с их "платформо-зависимыми оптимизациями".
Не знаю, при чём тут это. К тому же помимо интела в мире есть и другие платформы, для которых действуют в общем-то те же законы взаимодействия между поставщиками и пользователями

Цитата Сообщение от avgoor Посмотреть сообщение
2) Если пользователь использует "плохой" компилятор, то и на оптимальность реализации ему покласть.
Как я уже писал выше, что если программа живет основную часть времени внутри библиотек (как это имеет место быть, например, для opengl или qt), то при использовании бинарников у пользователя получится быстрый код даже на плохом компиляторе.

Есть ещё один момент. Когда код описан в файле *.h, то, например, при работе под отладчиком код нужно собирать в режиме -O0 -g, а такой код будет на порядок (а и то и больше) медленнее работать за счёт того, что инлайн уже работать не будет, и эффект от его отсутствия будет выглядеть как большое количество мусорного кода, которое есть побочный выхлоп C++, который базируется на инлайне со стороны компилятора. В итоге, если в боевой версии программы происходит падение через минуту после старты программы, то в отладочной версии падение может быть и через 10 минут, и через час. При этом пользователю режим -O0 -g нужен в общем-то только для своих собственных кодов, а не библиотечных, но т.к. библиотечные коды представлены в виде потрохов, то начинают медленно работать ещё и они (да ещё и занимают основную часть времени работы)

Добавлено через 1 минуту
Цитата Сообщение от avgoor Посмотреть сообщение
то и на оптимальность реализации ему покласть
Вовсе не обязательно. Для те, кто много занимается разработкой, характерно то, что они крайне редко меняют версии компилятора, в отличие от студентов, которым делать нечего и которые по три раза на дню меняют целый дистрибутив
0
 Аватар для avgoor
1550 / 877 / 179
Регистрация: 05.12.2015
Сообщений: 2,555
23.03.2016, 16:18
Цитата Сообщение от Evg Посмотреть сообщение
К тому же помимо интела в мире есть и другие платформы
Я про их компилятор.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
23.03.2016, 16:21  [ТС]
Цитата Сообщение от Nosey Посмотреть сообщение
Незабываем что разговор о статической линковке. В динамике используем С подход и ни как иначе
Это не играет никакой роли. Пользователь захочет так, а захочет и сяк

Цитата Сообщение от Nosey Посмотреть сообщение
Вы поставляете обычный клиентский софт под каждую архитектуру процессора? так что вам нужна сотня библиотек специально собранных? Это риторический вопрос )
Да. И так делают многие. Даже в колхозном glibc уже взяли на вооружение такой подход. Причём весь паровоз реализаций под разные процессоры физически зашит в одну библиотеку по технологии типа "indirect function", где в runtime происходит распознание текущей модели процессора и настройка на конкретную из реализаций

Цитата Сообщение от Nosey Посмотреть сообщение
Также если вы пишите воистину что-то требующее такой производительности, то незнание целевой архитектуры будет меньшая из ваших бед, ибо это просто недельное чтение мануалов. И вам придется их прочитать.
Если же это не клиентский софт а бэкенд, то тут точно придется прочитать мануалы, ибо писать под определенное железо и лень в прочтении мануалов по 10 флагам - плохо сочетаются )
Допустим, я эксперт по 3-мерной графике. Я работаю с условной библиотекой opengl. Мне глубоко начхать на то, как устроен интеловский процессор и как правильно под него писать оптимизации. Я просто хочу реализацию opengl, которая возьмёт на себя все заботы о машинно-зависимой производительности, потому что основное время жизни моя программа будет проводить именно внутри библиотеки. Ну и в общем случае я пишу переносимый код, который мне хотелось бы запускать на множестве различных машин, не заморачиваясь тем, чтобы заниматься зависимыми оптимизациями под каждую машину. Мне намного дешевле купить хорошую библиотеку, которая возьмёт всё это на себя

Цитата Сообщение от Nosey Посмотреть сообщение
Например, openGl, помните изменения его интерфейса от версии к версии?
Не знаю, я им не пользовался

Цитата Сообщение от Nosey Посмотреть сообщение
так почему вы желаете вынести перемножение матриц в библиотеку?
Перемножение матриц было ведь всего-навсего понятным примером, и не более того

Добавлено через 1 минуту
Цитата Сообщение от avgoor Посмотреть сообщение
Я про их компилятор
А.. ну хз. Но когда у меня, как у пользователя, есть библиотека, в которой профессионалы сделали всё как надо, то мне в общем-то будет начхать на корявость интеловского компилятора. Горячий код у меня уже есть в предельно оптимизированном виде и мне не надо его повторно самому пересобирать
0
 Аватар для avgoor
1550 / 877 / 179
Регистрация: 05.12.2015
Сообщений: 2,555
23.03.2016, 16:37
Цитата Сообщение от Evg Посмотреть сообщение
в которой профессионалы сделали всё как надо
Интел сделал все как надо: если он детектил, что софт исполняется на AMD - он выбирал самую неоптимальную реализацию.

Добавлено через 56 секунд
Дипетчер в рантайме.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
23.03.2016, 16:38  [ТС]
Цитата Сообщение от avgoor Посмотреть сообщение
Интел сделал все как надо: если он детектил, что софт исполняется на AMD - он выбирал самую неоптимальную реализацию
Ну тут уже залезли в область политики, я думаю это немного из другой оперы
0
 Аватар для avgoor
1550 / 877 / 179
Регистрация: 05.12.2015
Сообщений: 2,555
23.03.2016, 16:43
Цитата Сообщение от Evg Посмотреть сообщение
я думаю это немного из другой оперы
Согласен. Но в любом случае все упирается в то, кто умнее - разработчик библиотеки или ее пользователь и, следовательно, кому оптимизировать. В результате минусы есть и у того и у другого подхода.
0
 Аватар для Nosey
1379 / 406 / 144
Регистрация: 22.10.2014
Сообщений: 872
23.03.2016, 19:22
Цитата Сообщение от Evg Посмотреть сообщение
Есть ещё один момент. Когда код описан в файле *.h, то, например, при работе под отладчиком код нужно собирать в режиме -O0 -g, а такой код будет на порядок (а и то и больше) медленнее работать за счёт того, что инлайн уже работать не будет, и эффект от его отсутствия будет выглядеть как большое количество мусорного кода, которое есть побочный выхлоп C++, который базируется на инлайне со стороны компилятора. В итоге, если в боевой версии программы происходит падение через минуту после старты программы, то в отладочной версии падение может быть и через 10 минут, и через час. При этом пользователю режим -O0 -g нужен в общем-то только для своих собственных кодов, а не библиотечных, но т.к. библиотечные коды представлены в виде потрохов, то начинают медленно работать ещё и они (да ещё и занимают основную часть времени работы)
Дебаг конечно это некая сложность, но вполне преодолимая, и с часовыми оценками я не согласен, преувеличили вы барин ))
Собственно справляться можно с длительностью работы : корректировкой входных данных и тестами. С длительностью работы определённого кода - билд системой, никто вас не заставляет библиотеку тоже собирать в дебаг режиме если вам ее дебажить не надо.

Цитата Сообщение от Evg Посмотреть сообщение
Это не играет никакой роли. Пользователь захочет так, а захочет и сяк
Я к тому, что какие нафиг инлайн оптимизации при динамической линковке ) И раз их нет, то нужно выбирать интерфейс который будет работать максимально производительно в этой ситуации, т.е. С подход. Ну и конечно, в общем случае, просто адский геморой с ABI С++ интерфейса.

Цитата Сообщение от Evg Посмотреть сообщение
Да. И так делают многие. Даже в колхозном glibc уже взяли на вооружение такой подход. Причём весь паровоз реализаций под разные процессоры физически зашит в одну библиотеку по технологии типа "indirect function", где в runtime происходит распознание текущей модели процессора и настройка на конкретную из реализаций
Спасибо, не знал что такая штука есть из коробки в gcc. И у меня появилась пара вопросов по ней.
1) Есть ли у студии и шланга технология подобная "--enable-gnu-indirect-function" из коробки?
2) У меня ни один gcc не сконфигурирован с этим флагом, что подталкивает на мысль, а работает ли вообще эта технология в gcc, или это модная приблуда работающая только при свете луны?

Цитата Сообщение от Evg Посмотреть сообщение
Допустим, я эксперт по 3-мерной графике. Я работаю с условной библиотекой opengl. Мне глубоко начхать на то, как устроен интеловский процессор и как правильно под него писать оптимизации. Я просто хочу реализацию opengl, которая возьмёт на себя все заботы о машинно-зависимой производительности, потому что основное время жизни моя программа будет проводить именно внутри библиотеки. Ну и в общем случае я пишу переносимый код, который мне хотелось бы запускать на множестве различных машин, не заморачиваясь тем, чтобы заниматься зависимыми оптимизациями под каждую машину. Мне намного дешевле купить хорошую библиотеку, которая возьмёт всё это на себя
Ну во-первых opengl это наверное самый плохой пример в данном случае )). Поскольку библиотека openGl это по факту малюсенькая обертка над драйвером видеокарты, который соответственно и выполняет основную работу. А уж драйверы я точно не предлагаю пересобирать разработчикам софта. И собственно основной рабочий код соответственно "линкуется динамически" через подобие "indirect function", там жеш все покрыто плагинами от вендоров видео, а апи просто делегирует им вызовы предоставляя стандартизированный интерфейс для пользователя.
Но идею, что вам таки придется почитать мануалы это не отменяет ни в какой ситуации, ну разве что ваш код это "Hello World" на основе адской библиотеки, или же вы нашли библиотеку которая умеет "делать мне хорошо"?
Если библиотека доставляется к клиенту не вами, то см. динамическую линковку выше. Если вами и статическая линковка, то возвращаемся к прошлым сообщениям, но я уже устал об этом говорить, я не сомневаюсь что вы меня поняли

Цитата Сообщение от Evg Посмотреть сообщение
Перемножение матриц было ведь всего-навсего понятным примером, и не более того
Подведем итог:
1) Если рассматривать шарообразное произведение матриц в вакууме, то перечитать все с первого поста.
2) Если перемножение миллиона раз примерочных матриц занимает 1нс, то есть три варианта:
1) инлайниг.
2) В случае выноса в библиотеку без возможности инлайнинга - оторвать ноги архитектору, при повторении - оторвать руки.
3) С подход, как самый нежелательный в контексте использования, да, лучше оторвать ноги , но всеядный способ.
3) Если одно перемножение матриц занимает миллион секунд, то есть один вариант:
1) предлагаю в интерфейс перемножения в параметр обязательно передавать по значению всю санту барбару в raw качестве, на скорость это не повлияет, а разработчики улыбнутся, да и будет что посмотреть во время рассчетов.
4) В средних ситуациях одна фигня - что инлайн, что С подход, ибо общее время рассчетов будет такое, что я даже вспомнить название "санта барбара" не успею.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
23.03.2016, 20:07  [ТС]
Цитата Сообщение от Nosey Посмотреть сообщение
никто вас не заставляет библиотеку тоже собирать в дебаг режиме если вам ее дебажить не надо
А библиотеки как таковой в варианте С++ как бы и нет. Библиотека представляет собой хидер, который придётся перекомпиливать в контексте всей программы, а не по отдельности

Цитата Сообщение от Nosey Посмотреть сообщение
Я к тому, что какие нафиг инлайн оптимизации при динамической линковке
Наличие инлайна никак не зависит от типа линковки. Я считаю, что библиотеку никто в здравом уме не будет поставлять в виде LTO, потому что это сопливая технология и нормально будет работать только в тех условиях, когда и библиотеку и программу разрабатывает одно и то же рыло с использованием одного и того же компилятора. А я рассматриваю именно такой вариант, когда библиотеку делает один разработчик, а пользуется ею другой (пользователь, покупатель)

Цитата Сообщение от Nosey Посмотреть сообщение
1) Есть ли у студии и шланга технология подобная "--enable-gnu-indirect-function" из коробки?
indirect function в той редакции, в которой оно есть в gcc в первую очередь представляет собой расширение линкера и загрузчика, которые в свою очередь расширяют формат ELF. Так что не посредственно gnu indirect function в MSVS скорее всего нет, но не исключаю, что есть другая аналогичная технология

Цитата Сообщение от Nosey Посмотреть сообщение
2) У меня ни один gcc не сконфигурирован с этим флагом, что подталкивает на мысль, а работает ли вообще эта технология в gcc, или это модная приблуда работающая только при свете луны?
Как я же говорил, требуется совместная поддержка в компиляторе, в линкере, в ассемблере и glibc. При сборке gcc из исходников запросто может не включиться, если что-то из перечисленного не поддерживает

Цитата Сообщение от Nosey Посмотреть сообщение
Ну во-первых opengl это наверное самый плохой пример в данном случае )). Поскольку библиотека openGl это по факту малюсенькая обертка над драйвером видеокарты, который соответственно и выполняет основную работу
А чем тебе (условное) умножение матриц не задача для исполнения на GPU? Задачи такого класса распаралеливаются ну очень хорошо, и GPU - идеальное устройство для подобных вычислений

Цитата Сообщение от Nosey Посмотреть сообщение
Но идею, что вам таки придется почитать мануалы это не отменяет ни в какой ситуации
И много нужно читать мануалов по устройству GPU, чтобы работать с opengl? Нет. Вот потому я и беру opengl как условный пример реализации библиотеки, у которой горячий весь код находится внутри библиотеки, а не в хидерах, и где никакой LTO не поможет

Цитата Сообщение от Nosey Посмотреть сообщение
Подведем итог:
Всё остальное не понял вообще
0
 Аватар для Nosey
1379 / 406 / 144
Регистрация: 22.10.2014
Сообщений: 872
23.03.2016, 21:25
Цитата Сообщение от Evg Посмотреть сообщение
Наличие инлайна никак не зависит от типа линковки.
Расскажите подробней, как для бухгалтера, как вы собрались инлайнить при динамической линковке? )) раз уж это совершенно независимые понятия.
Цитата Сообщение от Evg Посмотреть сообщение
Я считаю, что библиотеку никто в здравом уме не будет поставлять в виде LTO, потому что это сопливая технология и нормально будет работать только в тех условиях, когда и библиотеку и программу разрабатывает одно и то же рыло с использованием одного и того же компилятора. А я рассматриваю именно такой вариант, когда библиотеку делает один разработчик, а пользуется ею другой (пользователь, покупатель)
В общем случае я согласен. Но в случае внутренней разработки - вполне можно собрать с LTO для релиза. В случае покупки библиотеки, в зависимости от цены лицензии и критичности кода можно попросить и LTO версию.
Цитата Сообщение от Evg Посмотреть сообщение
но не исключаю, что есть другая аналогичная технология
Я надеялся на однозначный ответ, ибо гуглинг ничего не показал. Если читающие знают эту тему - расскажите плз парой букв.
Цитата Сообщение от Evg Посмотреть сообщение
А чем тебе (условное) умножение матриц не задача для исполнения на GPU? Задачи такого класса распаралеливаются ну очень хорошо, и GPU - идеальное устройство для подобных вычислений
Перемножение шарообразных матриц в вакууме - плохо паралелятся на самом деле.
А обычные матрицы, хорошо, да. Но если вы желаете паралелить на GPU умножение матриц через интерфейс a = b*c. То я предлагаю пари, что я на SIMD инструкциях это сделаю быстрее, чем вы будете ожидать синхронизации GPU и CPU. Или же мы уже где-то незаметно перешли от еденичного интерфейса к пакетному? Или же я просто не понял вопроса?
Цитата Сообщение от Evg Посмотреть сообщение
И много нужно читать мануалов по устройству GPU, чтобы работать с opengl? Нет. Вот потому я и беру opengl как условный пример реализации библиотеки, у которой горячий весь код находится внутри библиотеки, а не в хидерах, и где никакой LTO не поможет
Если ваша цель не просто закрасить экран одним цветом 50 раз и потом спросить "почему моя топовая GPU не рисует больше 100 треугольников за кадр", а сделать что-то приличное, то тыщенку страниц спецификаций по opengl прочитать придется, которые в общем-то включают в себя информацию о GPU. Конечно можно создавать темы в этом разделе.
А если отвечать "по-теме", то интерфейс opengl рассчитан на то чтобы никакого lto в помине не надо было, ибо это капля в море.
А мной приводимый код показывал на умножении матриц 30%'ый буст между С подходом и С++ подходом, если для вас 30% это недостаточно, чтобы отказаться от одной технологии в пользу другой, или хотя бы рассмотреть её, принимая во внимание что это синтетический тест в тепличных условиях, то я могу лишь посочувствовать.
Цитата Сообщение от Evg Посмотреть сообщение
Всё остальное не понял вообще
Обидно, чо
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
23.03.2016, 22:02  [ТС]
Цитата Сообщение от Nosey Посмотреть сообщение
Расскажите подробней, как для бухгалтера, как вы собрались инлайнить при динамической линковке?
Расскажи подробно, как ты собрался инлайнить при статической линковке. LTO сразу в топку

Цитата Сообщение от Nosey Посмотреть сообщение
Но в случае внутренней разработки - вполне можно собрать с LTO для релиза
В случае внутренней разработки в общем-то нет необходимости закрывать код. Тем более, если внутри конторы есть специалист, способный написать эффективную библиотеку, то он уж разберётся, как с ней быть в случае реализации через хидера

Цитата Сообщение от Nosey Посмотреть сообщение
Перемножение шарообразных матриц в вакууме - плохо паралелятся на самом деле.
А обычные матрицы, хорошо, да. Но если вы желаете паралелить на GPU умножение матриц через интерфейс a = b*c. То я предлагаю пари, что я на SIMD инструкциях это сделаю быстрее, чем вы будете ожидать синхронизации GPU и CPU. Или же мы уже где-то незаметно перешли от еденичного интерфейса к пакетному? Или же я просто не понял вопроса?
Забей. Я уже устал ходить по кругу и объяснять на пальцах, зачем и для чего нужна библиотека, поставляемая в виде машинного кода, а не в виде текста в хидерах. Уже появилось стойкое ощущение, что мы не понимаем друг друга

Цитата Сообщение от Nosey Посмотреть сообщение
А мной приводимый код показывал на умножении матриц 30%'ый буст между С подходом и С++ подходом
Твои тесты "as is" явно не пригодны для замера, а взять, вникнуть, и переписать правильно мне уже неохота (запал потух). Что с чем сравнивалось, и кто победил в неравной борьбе с совсем неэквивалентными кодами, честно говоря, я так и не понял, да и не важно это в условиях неправильных замеров.

Твой замер выглядел как (чтобы было перед глазами):

99999999 196025-fill
99999999 1958025-cpp
99999999 2202373-cpp no-inline + 1 copy ctor
99999999 2784633-c

Мой замер в режиме -O3:

99999999 248-fill
99999999 4150-cpp
99999999 4259-cpp no-inline + 1 copy ctor
99999999 2870-c

Мой замер в режиме -O3 -flto:

99999999 218-fill
99999999 1732-cpp
99999999 2090-cpp no-inline + 1 copy ctor
99999999 3120-c

Из этих цифр я могу сделать только один вывод - что делает режим -flto, непонятно, как он ухитряется пессимизировать код, тоже непонятно, как в таких условиях вообще можно что-то сравнивать - тоже не понятно. В режиме без -flto (что эквивалентно модели, в которой я изначально работаю в этой теме) код в стиле Си++ ожидаемо более медленный
0
 Аватар для Nosey
1379 / 406 / 144
Регистрация: 22.10.2014
Сообщений: 872
23.03.2016, 22:47
Цитата Сообщение от Evg Посмотреть сообщение
Расскажи подробно, как ты собрался инлайнить при статической линковке. LTO сразу в топку
Да в лёгкую, я инлайнить даже без копилятора могу, ctrl+c -> ctrl->v, делов то

Цитата Сообщение от Evg Посмотреть сообщение
В случае внутренней разработки в общем-то нет необходимости закрывать код.
В явном виде закрывать код - нет смысла. Но(как всегда, есть но ) как же ускорение компиляции путем переноса кода в другую единицу трансляции? ведь LTO включаем только для релиза, а в дебаге без LTO, при этом пишем код как обычно, не задумываясь об инлайне, а потом добрый компилятор нам поможет. Глупо отказывать от помощи, если есть такая возможность, не правда ли?

Но в случае библиотек, мы уже все обсудили и я согласен

Цитата Сообщение от Evg Посмотреть сообщение
Из этих цифр я могу сделать только один вывод - что делает режим -flto, непонятно, как он ухитряется пессимизировать код, тоже непонятно
Да, мне тоже очень лень было две страницы назад разбираться с асмом, чтобы прекратить эту вакханалию.
Но я могу привести простое доказательство что эти измерения верны, и объяснение(точнее подтверждение слов DrOffset'a на первой странице в 8-ом сообщении) :
При изменении моего кода с
C++
1
2
3
4
5
6
7
8
....
ru::math::Matrix4 mat2 { 20, 30, 40 };
 
void fc(const ru::math::Matrix4& mat)
{
    ru::math::Matrix4::operator_mul(mat3, mat, mat2);
}
....
на
C++
1
2
3
4
5
6
7
....
void fc(const ru::math::Matrix4& mat)
{
    ru::math::Matrix4 mat2 { 20, 30, 40 };
    ru::math::Matrix4::operator_mul(mat3, mat, mat2);
}
....
Мы получаем одинаковое время в C++(инлайн версия) и С реализациях.

Цитата Сообщение от Evg Посмотреть сообщение
В режиме без -flto (что эквивалентно модели, в которой я изначально работаю в этой теме) код в стиле Си++ ожидаемо более медленный
Однозначно.

В завершение цитата сегодняшнего дня:
Цитата Сообщение от DrOffset Посмотреть сообщение
Хочу отметить, что переиспользование одного и того же объекта для разных операций уже не вписывается в концепцию С++.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
24.03.2016, 09:38  [ТС]
Цитата Сообщение от Nosey Посмотреть сообщение
Да в лёгкую, я инлайнить даже без копилятора могу, ctrl+c -> ctrl->v, делов то
А к чему ты ctrl-c применять будешь? К бинарному коду из статической библиотеки?

Цитата Сообщение от Nosey Посмотреть сообщение
В явном виде закрывать код - нет смысла. Но(как всегда, есть но ) как же ускорение компиляции путем переноса кода в другую единицу трансляции? ведь LTO включаем только для релиза, а в дебаге без LTO, при этом пишем код как обычно, не задумываясь об инлайне, а потом добрый компилятор нам поможет. Глупо отказывать от помощи, если есть такая возможность, не правда ли?
Такую постановку задачи я бы решал совсем другими методами. Конечно с точки зрения Си++ использование макросов считается антипацанским стилем, но жить в расчёте на LTO - это ещё хуже

Цитата Сообщение от Nosey Посмотреть сообщение
Да, мне тоже очень лень было две страницы назад разбираться с асмом, чтобы прекратить эту вакханалию
Зачем там чего-то разбирать? Там беглого взгляда было достаточно, что вместо цепочки операций умножения и сложения используются более короткие комбинированные операции, которые одновременно делают умножение и сложение

Цитата Сообщение от Nosey Посмотреть сообщение
Но я могу привести простое доказательство что эти измерения верны, и объяснение(точнее подтверждение слов DrOffset'a на первой странице в 8-ом сообщении) :
Когда я вижу, что один и тот же код с LTO работает хуже, чем без него, для меня это очень сильный сигнал, что не надо этим пользоваться. Хотя я и без этого не пользовался бы им. Ну и в очередной раз хочу сказать: неправильно поставленный замер, результатом которого идут далеко идущие выводы без какого бы то ни было анализа кода - это одна из самых стандартных ошибок. Непонимание принципов работы опции - ещё одна из стандартных ошибок. А ты, я уверен, не понимаешь принципа работы -flto, потому как не можешь объяснить мой замер: в режиме -flto вариант "c" сильно замедлился. Если ты не можешь объяснить этого факта и будешь проектировать программы в надежде на опцию -ftlo, то с большой вероятностью наступишь на тот же эффект замедления на стиле Си++, и даже этого не заметишь

Добавлено через 3 минуты
Цитата Сообщение от Nosey Посмотреть сообщение
В завершение цитата сегодняшнего дня:

Сообщение от DrOffset
Хочу отметить, что переиспользование одного и того же объекта для разных операций уже не вписывается в концепцию С++
Подозреваю, что при таком раскладе в языке не было бы возможности перегрузить оператор присваивания, т.к. с такой концепцией нужен только конструктор. Но здесь я спорить не буду, т.к. с языком плохо знаком
0
 Аватар для Nosey
1379 / 406 / 144
Регистрация: 22.10.2014
Сообщений: 872
24.03.2016, 11:51
Цитата Сообщение от Evg Посмотреть сообщение
А к чему ты ctrl-c применять будешь? К бинарному коду из статической библиотеки?
Ну да, а ты что не можешь так?
Цитата Сообщение от Evg Посмотреть сообщение
использование макросов считается
Чем же макросы в этой задаче помогут?
Цитата Сообщение от Evg Посмотреть сообщение
Зачем там чего-то разбирать? Там беглого взгляда было достаточно, что вместо цепочки операций умножения и сложения используются более короткие комбинированные операции, которые одновременно делают умножение и сложение
Может для тебя оно и так, мои познания асма не далеко ушли с момента института.
Цитата Сообщение от Evg Посмотреть сообщение
Когда я вижу, что один и тот же код с LTO работает хуже, чем без него, для меня это очень сильный сигнал, что не надо этим пользоваться.
Не заметил твои странные результаты
У меня таких результатов не было, у меня результаты с разными погрешностями вот такие:
< означает быстрее, то что слева - быстрее.
без lto : (C-подход) < (CPP inline) < (CPP noInline) - тут везде минимальный отрыв с максимумом в 5%.
с lto : (CPP inline) < (CPP noInline) < (C-подход) - тут ровно то что я указывал ранее, C-подход отстает очень знатно.
Но таких адских результатов как у тебя я не видел.
Откуда вопросы есть: Точно ли адекватно проводился тест (cpu был свободен)? Что за версия gcc? Что за cpu? Как насчет -march=native для всех тестов?
У меня lto версия ускоряет весь код на 40%, как С, так и С++.
Цитата Сообщение от Evg Посмотреть сообщение
А ты, я уверен, не понимаешь принципа работы -flto, потому как не можешь объяснить мой замер: в режиме -flto вариант "c" сильно замедлился.
А ты можешь объяснить хотябы -О2? Ну тогда давай ко мне, будешь копилятором подрабатывать?
Цитата Сообщение от Evg Посмотреть сообщение
сли ты не можешь объяснить этого факта и будешь проектировать программы в надежде на опцию -ftlo, то с большой вероятностью наступишь на тот же эффект замедления на стиле Си++, и даже этого не заметишь
Что-то не понял о чем это ты.
Цитата Сообщение от Evg Посмотреть сообщение
Подозреваю, что при таком раскладе в языке не было бы возможности перегрузить оператор присваивания, т.к. с такой концепцией нужен только конструктор. Но здесь я спорить не буду, т.к. с языком плохо знаком
Ах, этот идеальный мир в котором "машина состояний" не зависит от входных данных.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
24.03.2016, 11:51

Какое значение получит переменная p при выполнении следующего оператора присваивания?
var p: set of 0..9; i, j: integer; Если i=2 и j=5, то какое значение получит переменная p при выполнении следующего оператора...

Ошибка при выполнении оператора присваивания производного класса через указатель на базовый
Здравствуйте, не могу понять из-за чего ошибка. Надо в производном классе объявить оператор сложения и обратится к нему через базовый. ...

Ошибка при реализации перегрузки оператора <<
Добрый день. Прошу помощи. Имеется такой класc. class DList { ... public: ... void Save(std::ofstream &amp;b_out); //...

Ошибка в вводе данных из HTML и переносе их в JavaScript, при выполнении оператора IF или оператора swithc
доброго времени суток, при выполнении одной учебной задачи столкнулся с проблемой: при введении любого значения в поле, код выдает только...

Переопределение оператора присваивания
Имеется такой простой класс: class TClass { private: float* A; int N; public: TClass(int _N) ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
80
Ответ Создать тему
Новые блоги и статьи
Море в объективе
kumehtar 06.07.2026
Хотел написать много проникновенных слов, но передумал. Оно само - говорит. Кто слышит тот слышит.
Оказывается, Unreal Engine позволяет качество на порядки выше, чем было в Lineedge
Etyuhibosecyu 05.07.2026
Жаль, конечно, что я не узнал об этом, пока Lineedge существовала, а то бы Noname2331 написал, что волки превращаются в пиксельную кашу, а я бы его попросил скачать какую-нибудь бриллиантовую или Pro. . .
Doom для терминала без стрельбы и монстров. 3D Raycasting на ascii.
dcc0 05.07.2026
Попросил нейронную сеть deepai. org написать рейкастинг 3D с библиотекой ncurses для Linux. Чтобы можно было ходить на стрелочки. Чтобы стены были отрисованы символами. Справилась. Первый вариант. . .
Установка статуса документа по условию
Maks 05.07.2026
Алгоритм из решения ниже реализован на нетиповом документе "НарядПутевка" разработанного в КА2. Задача: в табличной части "Материалы" документа при записи автоматически устанавливать статус. . .
Сезонность и суточность закисления почв
anaschu 04.07.2026
200 часов это все равно моловато. Есть ситуации, но нестандартные, когда смена происходит за 5 лет. Но обычно это 50 лет и более. Наверное, закисление почвы происходит сезонно в средней. . .
В чем ценность человеческого опыта в глобальном смысле?
kumehtar 03.07.2026
Возможно, ценность человека не в том, что он однажды достигает мудрости, а в том, что он становится носителем карты пути. Он знает не только истину, но и последовательность внутренних изменений,. . .
интеграция AnyLogic с самописным REST API и переход на Odoo
anaschu 03.07.2026
Успешная интеграция AnyLogic с самописным REST API и переход на промышленную Odoo WMS Сегодня проделал огромный путь от простой симуляции физических процессов до построения полноценной. . .
Поиск всех путей на ориентированном графе. Linux
dcc0 02.07.2026
Переработка старого кода из моей статьи. Через несколько переработок от PHP кода к C89 (надеюсь, 89). Но довольно запутанно получилось. Код для Linux. Но если убрать time и то, что с ним. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru