string_view по ссылке или по значению
От: _NN_ www.nemerleweb.com
Дата: 27.05.19 17:36
Оценка:
В теории по ссылке эффективнее т.к. передача всего одного указателя вместо двух.
В интернетах пишут, что незачем заморачиваться класс и так маленький и по значению сойдёт.
Что думаете ?
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: string_view по ссылке или по значению
От: Nuzhny Россия https://github.com/Nuzhny007
Дата: 27.05.19 18:01
Оценка: 1 (1) +3
Здравствуйте, _NN_, Вы писали:

_NN>Что думаете ?


По значению
Re: string_view по ссылке или по значению
От: watchmaker  
Дата: 27.05.19 18:11
Оценка: +1
Здравствуйте, _NN_, Вы писали:

_NN>В теории по ссылке эффективнее

Определи, что значит "эффективнее".
Например, код не будет быстрее. И даже можно утверждать, что часто будет медленнее. Ведь передача по ссылке запрещает много полезных оптимизаций, например из-за правил алиасинга в C++: https://godbolt.org/z/nso76I .

_NN>т.к. передача всего одного указателя вместо двух.

Ну да. А заодно потребует от вызываемой функции материализовать экземпляр, ссылку на который нужно будет передать в вызываемую функцию.
Разменяли запись в регистр на аллокацию объекта в памяти. Аллокация, конечно, в стеке, но всё равно такой курс размена обычно невыгодный.

_NN>Что думаете ?

Если нет веских причин передавать по ссылке, то передавать string_view всегда нужно по значению. Веские причины встречаются редко.
Re[2]: string_view по ссылке или по значению
От: _NN_ www.nemerleweb.com
Дата: 27.05.19 18:17
Оценка:
Здравствуйте, watchmaker, Вы писали:

Ну вот я передавал всегда по значению, а тут кто-то посоветовал по ссылке.
По значению действительно эффективнее.
https://gcc.godbolt.org/z/L3ObMK
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: string_view по ссылке или по значению
От: _NN_ www.nemerleweb.com
Дата: 27.05.19 18:28
Оценка:
Здравствуйте, watchmaker, Вы писали:

_NN>>В теории по ссылке эффективнее

W>Определи, что значит "эффективнее".
W>Например, код не будет быстрее. И даже можно утверждать, что часто будет медленнее. Ведь передача по ссылке запрещает много полезных оптимизаций, например из-за правил алиасинга в C++: https://godbolt.org/z/nso76I .
В этом примере как раз sum_chars_ref гораздо короче
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[3]: string_view по ссылке или по значению
От: watchmaker  
Дата: 27.05.19 18:39
Оценка:
Здравствуйте, _NN_, Вы писали:

W>>Например, код не будет быстрее. И даже можно утверждать, что часто будет медленнее. Ведь передача по ссылке запрещает много полезных оптимизаций, например из-за правил алиасинга в C++: https://godbolt.org/z/nso76I .

_NN>В этом примере как раз sum_chars_ref гораздо короче :))
Удивительно, но длина машинного кода не является единственным определяющим фактором времени его работы :)
Важно, что чтений из памяти sum_chars_ref делает вдвое больше. И плюс всякие оптимизации, завязанные на знание числа итераций цикла (unroll, vectorize), отпадают.
То что он короче — это следствие того, что компилятор сдался и просто признал, что его знаний не хватит чтобы понять как такую фигню заставить быстро работать.
Re: string_view по ссылке или по значению
От: Zhendos  
Дата: 27.05.19 23:56
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>В теории по ссылке эффективнее т.к. передача всего одного указателя вместо двух.

_NN>В интернетах пишут, что незачем заморачиваться класс и так маленький и по значению сойдёт.
_NN>Что думаете ?

1. Есть CppCoreGuidelines описывающий что передавать по ссылке, а что по значению
и string_view как раз попадает под категорию "cheap", так как два машинных слова.

http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#f16-for-in-parameters-pass-cheaply-copied-types-by-value-and-others-by-reference-to-const

2. Вообще передача по ссылке выглядит безумием на x86-64,
вот мы вычислили string_view и у нас есть два значения (указатель и длина),
в двух регистрах, вместо того, чтобы сразу вызывать (перейти по адресу)
вызываемой функции, мы кладем эти регистры в стек, записываем адрес
(куда положили) в регистр, вызываем функцию, та чтобы работать с string_view
достает данные из стека, загружая их в два регистра.
Безумие какое-то получается.

3. Ну aliasing как ту уже заметили (и он даже работает если всего один аргумент типа const string_view &),
например в середине функции, которой передали "const string_view &" вызывается какая-то функцию,
постэфеккты которой компилятор не может предсказать, компилятор тогда сгенерирует код,
который перечитает string_view из памяти, после вызова этой функции, а то вдруг она поменяла значение.
Re[4]: string_view по ссылке или по значению
От: kaa.python Ниоткуда РСДН профессионально мёртв и завален ватой.
Дата: 28.05.19 01:55
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>Удивительно, но длина машинного кода не является единственным определяющим фактором времени его работы

W>Важно, что чтений из памяти sum_chars_ref делает вдвое больше. И плюс всякие оптимизации, завязанные на знание числа итераций цикла (unroll, vectorize), отпадают.

Очень заинтриговал! А не можешь немного рассказать почему это:

        movsbq  (%rsi,%r9), %rax
        addq    %rcx, %rax
        movq    %rax, (%rdx)
        movsbq  1(%rsi,%r9), %rcx
        addq    %rax, %rcx
        movq    %rcx, (%rdx)
        movsbq  2(%rsi,%r9), %rax
        addq    %rcx, %rax
        movq    %rax, (%rdx)
        movsbq  3(%rsi,%r9), %rcx
        addq    %rax, %rcx
        movq    %rcx, (%rdx)
        addq    $4, %r9
        cmpq    %r9, %rdi
        jne     .LBB0_8
        testq   %r8, %r8
        je      .LBB0_6
.LBB0_4:
        addq    %r9, %rsi
        xorl    %eax, %eax
.LBB0_5:                                # =>This Inner Loop Header: Depth=1
        movsbq  (%rsi,%rax), %rdi
        addq    %rdi, %rcx
        movq    %rcx, (%rdx)


быстрее этого:
        movq    (%rsi), %rcx
        xorl    %edx, %edx
.LBB1_2:                                # =>This Inner Loop Header: Depth=1
        movsbq  (%r8,%rdx), %rax
        addq    %rax, %rcx
        movq    %rcx, (%rsi)


По мне так мы имеем довольно схожий набор из movsbq и movq в обоих случаях и в первом варианте делаем куда больше обращений к памяти.
Re[5]: string_view по ссылке или по значению
От: reversecode google
Дата: 28.05.19 02:56
Оценка: 10 (1)
потому что в конвеер грузится сразу доступ к 4 елементам в случае если длинна кратна 4
а в цикле ниже только по одному
и это медленее для цпу

вообще странно слышать такой вопрос от вас
кем вы в лк работали ?
Re[6]: string_view по ссылке или по значению
От: kaa.python Ниоткуда РСДН профессионально мёртв и завален ватой.
Дата: 28.05.19 03:20
Оценка:
Здравствуйте, reversecode, Вы писали:

R>потому что в конвеер грузится сразу доступ к 4 елементам в случае если длинна кратна 4

R>а в цикле ниже только по одному
R>и это медленее для цпу

Спасибо, да, разумно.

R>вообще странно слышать такой вопрос от вас

R>кем вы в лк работали ?

Странно? Да ни сколько, работа в ЛК совсем не значит что ты занимаешься оптимизациями В ЛК я был "Mac Applications Development Group Manager".
Re[2]: string_view по ссылке или по значению
От: _NN_ www.nemerleweb.com
Дата: 28.05.19 06:16
Оценка:
Здравствуйте, watchmaker, Вы писали:

А что насчёт возврата ?
Применимы ли тут аналогичные выводы ?
Судя по дисассемблеру как раз возврат ссылки эффективнее будет:

//         mov     rax, rdi
string_view const& as_view(string_view const& view) noexcept { return view; }

//         mov     rdx, rsi
//         mov     rax, rdi
string_view as_view2(string_view view) noexcept { return view; }
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: string_view по ссылке или по значению
От: T4r4sB Россия  
Дата: 28.05.19 06:52
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>Если нет веских причин передавать по ссылке, то передавать string_view всегда нужно по значению. Веские причины встречаются редко.


Убогое АБИ — веская причина? Виндуза не позволяет передавать такие вещи по значению.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[3]: string_view по ссылке или по значению
От: _NN_ www.nemerleweb.com
Дата: 28.05.19 06:57
Оценка:
Здравствуйте, T4r4sB, Вы писали:

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


W>>Если нет веских причин передавать по ссылке, то передавать string_view всегда нужно по значению. Веские причины встречаются редко.


TB>Убогое АБИ — веская причина? Виндуза не позволяет передавать такие вещи по значению.


Можете пояснить при чём тут Виндоуз и где например Линукс лучше в данном случае ?
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[4]: string_view по ссылке или по значению
От: T4r4sB Россия  
Дата: 28.05.19 07:01
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Можете пояснить при чём тут Виндоуз и где например Линукс лучше в данном случае ?


Попробуй передать структурку по значению, собери ллвм под винду-64 для наглядности, посмотри в код и огорчись)))
Это мусрософт такую хренатень придумал.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[3]: string_view по ссылке или по значению
От: Zhendos  
Дата: 28.05.19 07:27
Оценка:
Здравствуйте, _NN_, Вы писали:

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


_NN>А что насчёт возврата ?

_NN>Применимы ли тут аналогичные выводы ?
_NN>Судя по дисассемблеру как раз возврат ссылки эффективнее будет:

_NN>
_NN>//         mov     rax, rdi
_NN>string_view const& as_view(string_view const& view) noexcept { return view; }

_NN>//         mov     rdx, rsi
_NN>//         mov     rax, rdi
_NN>string_view as_view2(string_view view) noexcept { return view; }
_NN>


Так ведь метод же вызвали не просто так, а с string_view
будут работать, а для этого в первом случае загрузят данные из памяти
в два регистра, а во втором просто начнут использовать эти два регистра.
Разве не очевидно какой вариант быстрее?
Re[5]: string_view по ссылке или по значению
От: _NN_ www.nemerleweb.com
Дата: 28.05.19 07:28
Оценка:
Здравствуйте, T4r4sB, Вы писали:

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


_NN>>Можете пояснить при чём тут Виндоуз и где например Линукс лучше в данном случае ?


TB>Попробуй передать структурку по значению, собери ллвм под винду-64 для наглядности, посмотри в код и огорчись)))

TB>Это мусрософт такую хренатень придумал.

Вы про ABI x64 винды ?
Aggregates (other) By pointer. First 4 parameters passed as pointers in RCX, RDX, R8, and R9

https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2019
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[6]: string_view по ссылке или по значению
От: T4r4sB Россия  
Дата: 28.05.19 07:34
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Вы про ABI x64 винды ?

_NN>Aggregates (other) By pointer. First 4 parameters passed as pointers in RCX, RDX, R8, and R9

Да-да-да. У вас не получится передать стрингвью по значению, в ШИНДОШЫ за вас всё решили и избавили вас от моральных страданий.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[6]: string_view по ссылке или по значению
От: T4r4sB Россия  
Дата: 28.05.19 07:40
Оценка:
Здравствуйте, _NN_, Вы писали:

Вот пример:
#include <cstdio>

struct string_view {
  const char* chars;
  size_t length;
};

extern"C" void print(struct string_view sv) {
  for (size_t i=0; i<sv.length; ++i) {
    printf("%c", sv.chars[i]);
  }
};


clang hello.cpp -o hello.ll -S -emit-llvm -O3

define dso_local void @print(%struct.string_view* nocapture readonly) local_unnamed_addr #0 {
  %2 = getelementptr inbounds %struct.string_view, %struct.string_view* %0, i64 0, i32 1
  %3 = load i64, i64* %2, align 8, !tbaa !8
  %4 = icmp eq i64 %3, 0
  br i1 %4, label %7, label %5

; <label>:5:                                      ; preds = %1
  %6 = getelementptr inbounds %struct.string_view, %struct.string_view* %0, i64 0, i32 0
  br label %8

; <label>:7:                                      ; preds = %8, %1
  ret void

; <label>:8:                                      ; preds = %5, %8
  %9 = phi i64 [ 0, %5 ], [ %15, %8 ]
  %10 = load i8*, i8** %6, align 8, !tbaa !14
  %11 = getelementptr inbounds i8, i8* %10, i64 %9
  %12 = load i8, i8* %11, align 1, !tbaa !15
  %13 = sext i8 %12 to i32
  %14 = tail call i32 @putchar(i32 %13)
  %15 = add nuw i64 %9, 1
  %16 = load i64, i64* %2, align 8, !tbaa !8
  %17 = icmp ult i64 %15, %16
  br i1 %17, label %8, label %7
}
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[5]: string_view по ссылке или по значению
От: watchmaker  
Дата: 28.05.19 07:46
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB> Убогое АБИ — веская причина? Виндуза не позволяет передавать такие вещи по значению.

Возможность передавать структуры по значению — это свойство языка, а не ABI.
Наверное в вышепроцитированном утверждении какое-то слово пропущено (например, "через регистры" или что-то ещё)

TB>Попробуй передать структурку по значению, собери ллвм под винду-64 для наглядности, посмотри в код и огорчись)))

Если сравнивать win c win, то вроде получается не хуже: https://godbolt.org/z/af28Dy
Сходу видна только проблема с тем, что если объект не модифицируется, а передаётся дальше как есть (как в последней паре функций с рекурсией), то получается плохо с копированием его на стек на каждой итерации. Но и для systemV abi аналогичный пример можно придумать (да на самом деле даже этот подойдёт).

А ты про какой сценарий говоришь?
Re[6]: string_view по ссылке или по значению
От: T4r4sB Россия  
Дата: 28.05.19 07:58
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>Возможность передавать структуры по значению — это свойство языка, а не ABI.


Проблема всех компиляторов С/С++ под винду-64, так лучше?

W>Наверное в вышепроцитированном утверждении какое-то слово пропущено (например, "через регистры" или что-то ещё)


TB>>Попробуй передать структурку по значению, собери ллвм под винду-64 для наглядности, посмотри в код и огорчись)))

W>Если сравнивать win c win, то вроде получается не хуже: https://godbolt.org/z/af28Dy
W>А ты про какой сценарий говоришь?
Ой, там асм. Я уже разучился его понимать. В ЛЛВМ лучше видно. Что передача по значению превращается в передачу по структуре.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[7]: string_view по ссылке или по значению
От: watchmaker  
Дата: 28.05.19 08:29
Оценка:
Здравствуйте, T4r4sB, Вы писали:

TB>Вот пример:

TB>
TB>#include <cstdio>

TB>struct string_view {
TB>  const char* chars;
TB>  size_t length;
TB>};

TB>extern"C" void print(struct string_view sv) {
TB>  for (size_t i=0; i<sv.length; ++i) {
TB>    printf("%c", sv.chars[i]);
TB>  }
TB>};


TB>clang hello.cpp -o hello.ll -S -emit-llvm -O3


И? Заменяем теперь сигнатуру функции на void print(const string_view& sv) и видим, что в IR лучше не стало.
То есть с точки зрения IR кода тут нет выгоды, если мы будет передавать по ссылке const string_view& sv.

А вообще на IR тут смотреть плохо. Он не показывает важные машинно-специфичные оптимизации. Например, передача по ссылке или по значению влияет на register pressure, но в IR это никак не отображено — в нём же бесконечное количество регистров
Re[8]: string_view по ссылке или по значению
От: T4r4sB Россия  
Дата: 28.05.19 08:42
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>И? Заменяем теперь сигнатуру функции на void print(const string_view& sv) и видим, что в IR лучше не стало.


Вот именно! IR никак не меняется от замены указателя на значение!

W>А вообще на IR тут смотреть плохо. Он не показывает важные машинно-специфичные оптимизации. Например, передача по ссылке или по значению влияет на register pressure, но в IR это никак не отображено — в нём же бесконечное количество регистров


Неважно, он показывает, что в функцию передаётся именно указатель. По-моему, этого достаточно.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[9]: string_view по ссылке или по значению
От: watchmaker  
Дата: 28.05.19 08:48
Оценка:
Здравствуйте, T4r4sB, Вы писали:

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


W>>И? Заменяем теперь сигнатуру функции на void print(const string_view& sv) и видим, что в IR лучше не стало. :))


TB>Вот именно! IR никак не меняется от замены указателя на значение!


Хорошо что мы в этом согласны :)

Значит эта ветка всё же показывает, что тут нет веских причин передавать string_view по ссылке даже под win. Так?
Напомню, с чего всё началось: http://rsdn.org/forum/cpp/7455853.1
Автор: T4r4sB
Дата: 28.05.19
:)

W>>Если нет веских причин передавать по ссылке, то передавать string_view всегда нужно по значению.
TB>Убогое АБИ — веская причина?

Re[9]: string_view по ссылке или по значению
От: reversecode google
Дата: 28.05.19 08:55
Оценка:
TB>Неважно, он показывает, что в функцию передаётся именно указатель. По-моему, этого достаточно.

в результирующем асм коде никакого указателя нет даже в вашем случае
компилятор оптимизирует и передает в двух регистрах вашу пару хранящуюся в структуре
Re[10]: string_view по ссылке или по значению
От: T4r4sB Россия  
Дата: 28.05.19 09:34
Оценка:
Здравствуйте, watchmaker, Вы писали:


W>Значит эта ветка всё же показывает, что тут нет веских причин передавать string_view по ссылке даже под win. Так?

W>Напомню, с чего всё началось: http://rsdn.org/forum/cpp/7455853.1
Автор: T4r4sB
Дата: 28.05.19

W>

W>>>Если нет веских причин передавать по ссылке, то передавать string_view всегда нужно по значению.
TB>>Убогое АБИ — веская причина?


Ну как сказать. Убогое АБИ — это веская причина того, что ты в принципе не сможешь передать св по значению. Согласен?
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[10]: string_view по ссылке или по значению
От: T4r4sB Россия  
Дата: 28.05.19 09:36
Оценка:
Здравствуйте, reversecode, Вы писали:

R>в результирующем асм коде никакого указателя нет даже в вашем случае

R>компилятор оптимизирует и передает в двух регистрах вашу пару хранящуюся в структуре

Компилятор передаёт указатель на структуру снаружи и разыменовывает её внутри. Не, я понимаю, есть оптимизации между границами функций (тогда вообще пофиг как передавать, компилятор разберётся), но если функция сидит в другом бинарнике, например, то эта оптимизация не сработает.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[11]: string_view по ссылке или по значению
От: reversecode google
Дата: 28.05.19 09:41
Оценка:
TB>Компилятор передаёт указатель на структуру снаружи и разыменовывает её внутри. Не, я понимаю, есть оптимизации между границами функций (тогда вообще пофиг как передавать, компилятор разберётся), но если функция сидит в другом бинарнике, например, то эта оптимизация не сработает.

вам надо посмотреть видео доклада антона полухина про С++ строки, и вывод именно такой — не надо быть умнее компилятора

не важно где функция, компилятор увидит передающийся тип и как он используется в теле
и с оптимизирует
Re: string_view по ссылке или по значению
От: fk0 Россия https://fk0.name
Дата: 28.05.19 10:34
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>В теории по ссылке эффективнее т.к. передача всего одного указателя вместо двух.

_NN>В интернетах пишут, что незачем заморачиваться класс и так маленький и по значению сойдёт.
_NN>Что думаете ?

При передаче по значению его можно модифицировать внутри функции, а не копировать (если по константной ссылке).
Re[10]: string_view по ссылке или по значению
От: watchmaker  
Дата: 28.05.19 10:55
Оценка:
Здравствуйте, reversecode, Вы писали:


TB>>Неважно, он показывает, что в функцию передаётся именно указатель. По-моему, этого достаточно.


R>в результирующем асм коде никакого указателя нет даже в вашем случае

R>компилятор оптимизирует и передает в двух регистрах вашу пару хранящуюся в структуре
Под какую платформу? В этой ветке T4r4sB рассказывает про windows.
А windows ABI это явно запрещает:

A single argument is never spread across multiple register

https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=vs-2019
Re[2]: string_view по ссылке или по значению
От: _NN_ www.nemerleweb.com
Дата: 28.05.19 11:02
Оценка:
А что насчёт constexpr ?

#include <string_view>

constexpr bool a(std::string_view const& l, std::string_view const& r) {
    return true;
}

// OK
void f() {
    std::string_view q("A");
    std::string_view w("A");
    constexpr bool xx = a(q, w);
}

constexpr bool b(std::string_view  l, std::string_view  r) {
    return true;
}

// А тут не собирается
void g() {
    std::string_view q("A");
    std::string_view w("A");
    constexpr bool xx = b(q, w);
}
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[11]: string_view по ссылке или по значению
От: watchmaker  
Дата: 28.05.19 11:07
Оценка: +1
Здравствуйте, T4r4sB, Вы писали:

TB>Ну как сказать. Убогое АБИ — это веская причина того, что ты в принципе не сможешь передать св по значению. Согласен?


Вот прямо с такой формулировкой? Совсем не согласен!
Возможность передать по значению — это свойство языка C++. От используемого ABI оно не зависит. Даже если используется абстрактная машина C++ и никакого ABI нет вообще.

Вот я передал long double по значению:
extern void foo(long double);
foo(4);


А вот я передал по значению std::string_view:
extern void bar(std::string_view);
bar("hello"sv);


Этот код будет передавать аргументы вне зависимости от ABI.

ABI будет задавать лишь куда аргументы будет помещены: например, будут ли они переданы через регистры или переданы через стек, или каким-то ещё невообразимым образом. Но во всех случаях они будут переданы по значению. "Через регистры по значению", "через стек по значению", "невообразимым образом, но по значению", и так далее.
Re[12]: string_view по ссылке или по значению
От: T4r4sB Россия  
Дата: 28.05.19 11:14
Оценка: +2
Здравствуйте, watchmaker, Вы писали:

W>Вот прямо с такой формулировкой? Совсем не согласен!

W>Возможность передать по значению — это свойство языка C++. От используемого ABI оно не зависит. Даже если используется абстрактная машина C++ и никакого ABI нет вообще.

В контексте низкоуровневых оптимизаций говорить об абстракциях неуместно.
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[12]: string_view по ссылке или по значению
От: _NN_ www.nemerleweb.com
Дата: 28.05.19 11:32
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>ABI будет задавать лишь куда аргументы будет помещены: например, будут ли они переданы через регистры или переданы через стек, или каким-то ещё невообразимым образом. Но во всех случаях они будут переданы по значению. "Через регистры по значению", "через стек по значению", "невообразимым образом, но по значению", и так далее.

Мы тут обсуждаем именно подкапотную работу, а не абстракции языка.
То, что всё передается по значению по умолчанию это свойства языка и никто с этим не спорит, вопрос будет ли это достаточно эффективным в случае string_view или нет.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[13]: string_view по ссылке или по значению
От: watchmaker  
Дата: 28.05.19 11:35
Оценка:
Здравствуйте, T4r4sB, Вы писали:

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


W>>Вот прямо с такой формулировкой? Совсем не согласен!

W>>Возможность передать по значению — это свойство языка C++. От используемого ABI оно не зависит. Даже если используется абстрактная машина C++ и никакого ABI нет вообще.

TB>В контексте низкоуровневых оптимизаций говорить об абстракциях неуместно.


И это говорит человек, который не спускается ниже IR при разговорах об оптимизации!

Ладно, если серьёзно, то вопрос в первом сообщении темы был про передачу аргументов std::string_view: по ссылке это делать или по значению.

Понятно, что есть кривые ABI, где не будет разницы в сгенированном машинном коде при вызове функции. Спасибо, что напомнил об этом (я вот под windows давно не пишу и честно об этом забыл). Но это лишь означает, что их наличие не сдвигает чашу весов в сторону одного из вариантов. То есть их наличие — не причина предпочитать const std::string_view против const std::string_view& или наоборот.
А вот то, что при const std::string_view компилятору разрешено сделать больше оптимизаций, чем при const std::string_view& (даже на архитектурах, где передача идёт через память, а код вызова одинаков с точностью до интструкции), — уже причина.
И то, что на systemV ABI передача через значение чаще эффективнее — тоже причина (хотя не такая хорошая, как предыдущая).
Re[4]: string_view по ссылке или по значению
От: _NN_ www.nemerleweb.com
Дата: 28.05.19 11:37
Оценка:
Здравствуйте, Zhendos, Вы писали:

Z>Разве не очевидно какой вариант быстрее?


Вот выхлоп MSVC.
Как видно передача по значению занимается копированием, а по ссылке нет.
Неужели вариант с копированием будет быстрее ?

struct view { char const*p; int size; }

view f(view) PROC                         ; f
        movups  xmm0, XMMWORD PTR [rdx]
        mov     rax, rcx
        movups  XMMWORD PTR [rcx], xmm0
        ret     0
view f(view) ENDP                         ; f

v$ = 8
view const & g(view const &) PROC                     ; g
        mov     rax, rcx
        ret     0
view const & g(view const &) ENDP                     ; g
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[3]: string_view по ссылке или по значению
От: watchmaker  
Дата: 28.05.19 11:39
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>А что насчёт constexpr ?

А что?
C constexpr всё хорошо. Это с приведённым кодом не очень.


_NN>// А тут не собирается


Да. А ещё интересно, что даже если заменить std::string_view, скажем, на int или на void*, то всё равно не собирается:
constexpr bool b(void*  l, void*  r) {
    return true;
}

void g() {
    void* q = nullptr;
    void* w = nullptr;
    constexpr bool xx = b(q, w);
}


Наверное, дело тут ошибка всё же не в std::string_view
Re[11]: string_view по ссылке или по значению
От: reversecode google
Дата: 28.05.19 11:57
Оценка:
https://godbolt.org/z/uEKEED
под виндовс какой именно компиль ?
кстати по линку выше видно что если передавать по ссылке
то происходит два дополнительных чтения с памяти в цикле
так то всяко разно передача по значению будет быстрей
Re[4]: string_view по ссылке или по значению
От: _NN_ www.nemerleweb.com
Дата: 28.05.19 12:09
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>Да. А ещё интересно, что даже если заменить std::string_view, скажем, на int или на void*, то всё равно не собирается:

W>Наверное, дело тут ошибка всё же не в std::string_view

Что значит ошибка в коде ?
Код компилируется с ссылкой успешно, значит в нём нет ошибки.

Добавляем ссылку и код собирается без проблем:
constexpr bool b(void*&  l, void*&  r) {
    return true;
}

void g() {
    void* q = nullptr;
    void* w = nullptr;
    constexpr bool xx = b(q, w);
}

https://gcc.godbolt.org/z/IBhF8A
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[12]: string_view по ссылке или по значению
От: watchmaker  
Дата: 28.05.19 12:39
Оценка:
Здравствуйте, reversecode, Вы писали:

R>https://godbolt.org/z/uEKEED

R>под виндовс какой именно компиль ?
Ну msvc вроде не умеет там под что-то отличное копмилировать, так что он подойдёт. А clang и gcc там собирают под unix, но для экспериментов их можно попросить использовать чужеродное abi.

R>кстати по линку выше видно что если передавать по ссылке

R>то происходит два дополнительных чтения с памяти в цикле
R>так то всяко разно передача по значению будет быстрей
Всё так.
И это платформонезависимая оптимизация. То есть для её не важно какое abi используется, и вообще linux ли там или windows. Сама её возможность следует из описания абстрактной машины C++.
Ведь если std::string_view передаётся по ссылке, то компилятор будет обязан на каждой итерации перечитывать значение sv.size() из памяти. Например, из-за того, что передача по ссылке не запрещает ссылаться для обоих аргументов функции на одну и ту же память (а значит модификация sum может поменять значение str.size(), а следовательно нужно перечитать str).
Строго говоря, конечно, компилятор может сгенерировать две ветки в функции: в одной делать честно и тупо, а в другой проверять, что все аргументы не пересекаются по памяти и сводить его к случаю как будто аргумент передан по значению. Но для мало-мальски сложных функций это очень сложно сделать на практике (например, сложно доказать, что какой-нибудь callback не поменяет память в string_view, ссылка на которую была передана в функцию).
То есть тут передача по значению играет роль модификатора restrict из C: она гарантирует, что аргументы ссылаются на разную память, и из-за этого её можно эффективно кешировать и отслеживать изменения в ней.
Re[5]: string_view по ссылке или по значению
От: Zhendos  
Дата: 28.05.19 13:20
Оценка:
Здравствуйте, _NN_, Вы писали:

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


Z>>Разве не очевидно какой вариант быстрее?


_NN>Вот выхлоп MSVC.

_NN>Как видно передача по значению занимается копированием, а по ссылке нет.
_NN>Неужели вариант с копированием будет быстрее ?

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

И я вижу два варианта:

string_view_ref_or_value get_string_view();

string_view_ref_or_value x = get_string_view();


либо мы сразу используем x, тогда мы лезем в память и достаем
и data и size (1), или передаем полученный x куда-то, но как мы выяснили
передачу лучше делать по значению, значит мы снова лезем в память и опять же достаем
data и size (2) (можно конечно дальше передавать ссылку, что кстати очень опасно,
но в конце концов мы придем к 1 или 2).

В обоих случаях получается что либо одинаково быстро будет
работать вся программа или чуть медленнее, если string_view вычисляется,
потому кладется в поле класса, а потом на поле класса возвращается ссылка.
Re[6]: string_view по ссылке или по значению
От: _NN_ www.nemerleweb.com
Дата: 28.05.19 13:34
Оценка:
Z>Вы куда-то контекст обсуждения потеряли.
Z>Естественно функция которую не вызывают вообще самая быстрая,
Z>можно считать что она вызывается за 0 тактов.
Z>Но мы же хотим чтобы в вся программа при использовании того или иного
Z>способа возврата string_view работала быстрее.
Z>Поэтому нужно рассматривать функцию возвращающую string_view вместе
Z>с кодом который ее вызывает.

Z>И я вижу два варианта:


Z>
Z>string_view_ref_or_value get_string_view();

Z>string_view_ref_or_value x = get_string_view();
Z>


Z>либо мы сразу используем x, тогда мы лезем в память и достаем

Z>и data и size (1), или передаем полученный x куда-то, но как мы выяснили
Z>передачу лучше делать по значению, значит мы снова лезем в память и опять же достаем
Z>data и size (2) (можно конечно дальше передавать ссылку, что кстати очень опасно,
Z>но в конце концов мы придем к 1 или 2).
А если мы передаём одни ссылки то нам не нужно доставать data и size до функции, где реально они будут нужны.
Скажем, в цепочке f->g->h->i мы можем создать объект в f и передавать ссылку до i, и только там достать data и size;
Если передавать по значению получается нужно их доставать и передавать каждый раз.
Или есть подвох ?

Z>В обоих случаях получается что либо одинаково быстро будет

Z>работать вся программа или чуть медленнее, если string_view вычисляется,
Z>потому кладется в поле класса, а потом на поле класса возвращается ссылка.

Т.е. если возвращать заранее созданный string_view как в случае поле класса то ссылка будет эффективней чем возвращать по значению ? Так ?
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[13]: string_view по ссылке или по значению
От: reversecode google
Дата: 28.05.19 13:35
Оценка:
кстати под виндой, 70 шланг релиз выдал два одинаковых результата на x64
по значению как по ссылке
с двумя под чтениями

хз кто там в бекенде кланга генерил обжект
у меня он под студию стоит настроенный
Re[7]: string_view по ссылке или по значению
От: Zhendos  
Дата: 28.05.19 16:09
Оценка:
Здравствуйте, _NN_, Вы писали:


Z>>И я вижу два варианта:


Z>>
Z>>string_view_ref_or_value get_string_view();

Z>>string_view_ref_or_value x = get_string_view();
Z>>


Z>>либо мы сразу используем x, тогда мы лезем в память и достаем

Z>>и data и size (1), или передаем полученный x куда-то, но как мы выяснили
Z>>передачу лучше делать по значению, значит мы снова лезем в память и опять же достаем
Z>>data и size (2) (можно конечно дальше передавать ссылку, что кстати очень опасно,
Z>>но в конце концов мы придем к 1 или 2).
_NN>А если мы передаём одни ссылки то нам не нужно доставать data и size до функции, где реально они будут нужны.
_NN>Скажем, в цепочке f->g->h->i мы можем создать объект в f и передавать ссылку до i, и только там достать data и size;
_NN>Если передавать по значению получается нужно их доставать и передавать каждый раз.
_NN>Или есть подвох ?

Ничего не понял,
если есть цепочка возврата, то какая разница заняты два регистра или один?
каждый раз это просто "ret", зачем кого-то доставать?

"f" заполняет два регистра и вызвает "ret", "g" уже имеет правильно заполненные регистры,
поэтому она просто вызывает ret, как и "h" и "i" сразу их использует.

Z>>В обоих случаях получается что либо одинаково быстро будет

Z>>работать вся программа или чуть медленнее, если string_view вычисляется,
Z>>потому кладется в поле класса, а потом на поле класса возвращается ссылка.

_NN>Т.е. если возвращать заранее созданный string_view как в случае поле класса то ссылка будет эффективней чем возвращать по значению ? Так ?


Нет, будет так же или хуже при возврате по ссылке. Хуже потому что если мы где-то будет иметь код
вида:

const string_view &another_get_string_view()
{
  const string_view& s = get_string_view();
  work_with_s_1(s);
  global_function();
  work_with_s_2(s);
  return s;
}


то так как мы получили "s" по ссылке, то мы два раза перечитаем "data" и "size"
из памяти, так как может global_function поменяла данные по ссылке.

То есть если мы предаем не используя, то есть у нас прямая цепочка
h() { return g(); } g() { return f(); }


то будет также, потому что хотя мы используем два регистра,
а не один, но это ведь "конец" всех этих функций,
и регистры не нужно на стек сохранять,
а если мы между делом, что-то делаем с этим 'const string_view&' то будет хуже.

И как бы нужно не забывать, что string_view это по сути ссылка,
и она может быть получена от std::string,
и чем дальше мы отдаем string_view, тем сложнее следить за временем жизни,
передавать на несколько уровней вверх без использования string_view это
по-моему очень странный сценарий.
Отредактировано 28.05.2019 16:12 Zhendos . Предыдущая версия .
Re[8]: string_view по ссылке или по значению
От: _NN_ www.nemerleweb.com
Дата: 28.05.19 22:05
Оценка:
Здравствуйте, Zhendos, Вы писали:

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

Z>а не один, но это ведь "конец" всех этих функций,
Z>и регистры не нужно на стек сохранять,
Z>а если мы между делом, что-то делаем с этим 'const string_view&' то будет хуже.

MSVC судя по всему не очень доволен передачей по значению.
Получаем копирование из памяти вместо использование регистров:
        mov     rdi, QWORD PTR __$ReturnUdt$[rsp]
        mov     rsi, rax
        mov     ecx, 16
        rep movsb


https://gcc.godbolt.org/z/bEiWGU
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[9]: string_view по ссылке или по значению
От: Zhendos  
Дата: 28.05.19 23:57
Оценка:
Здравствуйте, _NN_, Вы писали:

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


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

Z>>а не один, но это ведь "конец" всех этих функций,
Z>>и регистры не нужно на стек сохранять,
Z>>а если мы между делом, что-то делаем с этим 'const string_view&' то будет хуже.

_NN>MSVC судя по всему не очень доволен передачей по значению.


_NN>https://gcc.godbolt.org/z/bEiWGU


1. Не inline бесмысленна в этом коде, функция должна быть extern,
то есть ее тело должно быть невидимым для компилятор в этой единице трансляции
2. Нужно конечно в godbolt поменять компилятор на любой другой: icc, clang, gcc
Ведь в том ABI в x86-64 который реализовала MS весь спор о передаче по ссылке 16 байт
или по значению, а также возврат по ссылке 16 байт или по значению полностью бессмыслен,
разве это не очевидно?
Re[13]: string_view по ссылке или по значению
От: N. I.  
Дата: 29.05.19 08:58
Оценка:
_NN_:

_NN>Мы тут обсуждаем именно подкапотную работу, а не абстракции языка.

_NN>То, что всё передается по значению по умолчанию это свойства языка и никто с этим не спорит, вопрос будет ли это достаточно эффективным в случае string_view или нет.

В случае, когда функция инлайнится, calling conventions ничего не решают.

В случае, когда вызов функции не инлайнится, следует учитывать не только то, каким способом на низком уровне будут переданы аргументы, но ещё и насколько удобно компилятору будет оптимизировать код после такого вызова. Передача аргумента по const reference никак не защищает его от изменения внутри вызываемой функции, т.к. она легально может применить const_cast (если объект изначально не const) и дальше делать с ним что угодно. Когда же локальный объект куда-то передаётся по значению, отследить, что его не модифицируют, заметно проще.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.