LINUX.ORG.RU

QString и неявный шаринг данных

 ,


0

4

Задался совершенно детским вопросом. Как правильно быстро передавать QString в функцию, которая этот QString изменять не будет: по константной ссылке или по значению? Строго говоря, сам объект QString это прокси для неявно пошаренных данных, содержащий исключительно указатель на эти данные. То есть размер у прокси-объекта абсолютно аналогичен размеру ссылки. Недостатком ссылки является необходимость разыменовывать два указателя вместо одного (и не исключено что многократно). Недостатком объекта — отработка конструктора и деструктора с передёргиванием счётчика ссылок туда-сюда. При этом сам Qt поголовно использует для этих целей константные ссылки. Есть ещё какие-то аргументы? Или это исключительно читабельности ради?

★★★★★

Ответ на: комментарий от sjinks

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

Ты видишь там надпись gnu Си. -std=gnu99, gnu11.

А вот фиг. Так, как определил её ты, она в объектнике будет — ибо man visibility. Проверяется выхлопом gcc -S. Если ты хочешь, чтобы её не было в объектнике — делай её статической, либо задавай дефолтную видимость hidden.

Инлайн, который появился в c99 и инлайн из гнуси разные вещи.

procoder99
()
Ответ на: комментарий от sjinks

Я знаю, что ты имеешь в виду, но так случается далеко не всегда. Вряд ли весь код функции сразу будет в L1i. Такое возможно только в однозадачной системе. На практике же случаются переключения контекста и за те 5 секунд выполнения кода может выполниться не одна функция. Если бы кеш полностью очищался при каждом переключении контекста, были бы огромные тормоза.

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

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

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

В нелинейных функциях l1i миссы тебя будут волновать в последнюю очередь.

Да почти всегда.

procoder99
()
Ответ на: комментарий от procoder99

Ты видишь там надпись gnu Си. -std=gnu99, gnu11.

Держи. Твой код с -std=gnu11: http://x3me.me/l

Компилятор не развернул функцию, не смотря на inline.

Инлайн, который появился в c99 и инлайн из гнуси разные вещи.

Матчасть читай, скучно с тобой: http://gcc.gnu.org/onlinedocs/gcc/Inline.html

When an inline function is not static, then the compiler must assume that there may be calls from other source files; since a global symbol can be defined only once in any program, the function must not be defined in the other source files, so the calls therein cannot be integrated. Therefore, a non-static inline function is always compiled on its own in the usual fashion.

sjinks ★★★
()
Ответ на: комментарий от procoder99

Пример валый, слишком абстрактный мне лениво глядеть кишки х264.

Тебе не лениво только воздух сотрясать? :-) Пример не абстрактный, а очень даже практический.

sjinks ★★★
()
Ответ на: комментарий от sjinks

Т.е. примеров я не увижу - так и запишем. Я верю только в бенчмарк, проверять выхлоп, который написан в статье мне лень, ибо это кишки x264.

По поводу твоей статьи - она ничего не несёт. Естественно, если я получу в своём коде фейл по l1i( что маловероятно даже для х264, ибо я обычно не разварачиваю функции на ссешечке больше, чем на кешлайн) - я подумаю над переписанием кода. Заметь не над кастылями, аля отменям инлайн - а на уменьшении кода и оптимизации его вызывателей.

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

Напрягающий код, гоняемый в цикле( это не характерно для кути и иже с ним) должен вмещатся в l1i, а код, которыйн е гоняют в цикле - ему пофиг.

Поэтому, если ты развернёшь полностью весь цикл, то работать он будет так же. Т.е. выпилишь из моего кода вообще нахрен циклы.

Тогда он будет фрефетчить добесконечности и не будет фейлить прфечи на переходах.

procoder99
()
Ответ на: комментарий от x0r

при копировании QString у тебя скопируется весь массив с текстом. разыменование, по сравнению с этим, вообще ничто.

QString умеет copy-on-write. Your argument is invalid.

2TS:

const QString &something

Ибо семантика. И понятнее при коллективной разработке.

KennyMinigun ★★★★★
()
Ответ на: комментарий от procoder99

о чем говорил я, а именно

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

это не характерно для кути и иже с ним

Ты просто не писал высокопроизводительных приложений на Qt и иже с ними :-)

ибо я обычно не разварачиваю функции на ссешечке больше, чем на кешлайн

Тебе напомнить, какой размер у cache line, или сам вспомнишь?

Поэтому, если ты развернёшь полностью весь цикл, то работать он будет так же. Т.е. выпилишь из моего кода вообще нахрен циклы.

Не будет. Догадайся, почему.

sjinks ★★★
()
Ответ на: комментарий от procoder99

Да, по ссылке то, что я собрал из своего кода.

Круто ты собрал, если у тебя в твоём коде компилятор ругается на неопределенную функцию.

sjinks ★★★
()
Ответ на: комментарий от sjinks

Unroll применимо только к циклам. А функция именно встраивается.

Смотря какая функция — gcc и clang умеют TCO + unrolling для соответствующих функций.

quasimoto ★★★★
()
Последнее исправление: quasimoto (всего исправлений: 1)
Ответ на: комментарий от sjinks

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

Что ты показал? Это правдиво только для одного случая из 100. Я жажду примеров.

А так ты берёшь десяток килобайт кода и сравниваешь пхождение по 10килобайтами и сотне, когда у тебя в первом случае кеш вообще не трогается( чего не бывает в реальном коде с функциями 10кб), а сотня - это бред.

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

Ты просто не писал высокопроизводительных приложений на Qt и иже с ними :-)

Удиви - я жажду примеров.

Тебе напомнить, какой размер у cache line, или сам вспомнишь?

Меня не интересует l1i в моём коде, ибо в любом случае мой код ВСЕГДА будет в нём. Меня интересует d, а не i.

Не будет. Догадайся, почему.

Ну ок будет чуть медленней. И далеко не из-за l1i.

Суть в том, что если код не гоняется по миллиардам раз в цикле - влезает он в l1i или нет - покласть.

Мы выяснили, что надо слидить на циклами, чтобы они влезали в l1i - это банальность, за которой следит любой студент.

Когда функция взаимоинлайнится в множество иных, разных функций, при этом функция достаточно длинная и в процессе работы кода ОН МОГ БЫ ВЛЕЗТЬ В l1i, но он не влезает.

Во всех остальных случаях инлайн будет всегда быстрее каллов.

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

Мой код - Это нахрен десятки гигафлопс на ведро. Ты понимаешь, чем это отличается от кутишечки? Твоя кутишечка больше будет ждать на lcc, тлб мисах и ветлениях, чем на l1i.

Поэтому в 95% случаев инлайн профитней, кроме тех, о которых я сказал выше.

procoder99
()
Ответ на: комментарий от procoder99

Ты хоть понимаешь, что 99.(9) в точности равно 100?

anonymous
()
Ответ на: комментарий от procoder99

Портянка без каллов быстрее портянки с каллами

Знаком ли вам такой термин как CPU instruction cache?

anonymous
()
Ответ на: комментарий от procoder99

Потамучто она инлайн.

Выражаясь твоим языком, «потамучто ты анскиллед».

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

static inline int test(void)
{
        srand(time(NULL));
        return rand();
}

int main(int argc, char** argv)
{
        printf("%d\n", test());
        return 0;
}
$ ls test*
test.c
$ gcc -std=gnu11 -O2 -fno-inline test.c -o test
$ ls test*
test  test.c
sjinks ★★★
()
Ответ на: комментарий от procoder99

АХ, т.е. ты слился и понял, а потом впилил статик - молодец. Теперь убери статик.

Нет. Просто в отличие от тебя, я знаю разницу между встраиванием, определённым в gnu89 и встраиванием, определённым в C99 и позже.

Если ты объявляешь встраиваемую функцию в C99 и не определяешь её как static, компилятор предполагает, что она может быть вызвана из других модулей трансляции; соответственно, он генерирует внешний символ. Кури секцию 6.7.4 стандарта.

Если ты указываешь компилятору -fno-inline, то ты ССЗБ, ибо компилятор не будет генерировать код для inline-функций. В таком случае у тебя должно быть определение extern inline, а реализация функции должна присутствовать в одном из модулей трансляции. Либо функция должна быть объявлена как static. Опять же, кури стандарт до просветления.

Т.е. фактически ты демонстрируешь незнание или непонимание матчасти и почему-то пытаешься этим кичиться, что со стороны выглядит довольно-таки глупо.

sjinks ★★★
()
Ответ на: комментарий от KblCb

не странно ли вообще передавать указатель по ссылке?

конечно странно

но это, похоже, проблема с++

т.е. в рамках «не выпендривайся, ешь такой с++, как дают!» скорее всего надо передавать по константной ссылке

но предположу, что если бы с++ был сделан правильно, то тогда по значению

т.е. если у нас есть «листовая» функция f (или почти листовая), которая хочет содержимое объекта QString (т.е. строку), то можно было бы кидать туда пойнтер (назовем его QNonIncrementedPointerToStringData), который бы *не инкрементировался* на входе в f и не декрементировался на выходе из f

интересно бы это забенчить — но думаю будут случаи, когда профит всего 0.5 такта, но будут, видимо, и гораздо большие профиты — может ты забенчишь?

вообще основное возражение против gc на refcount — это именно такие случаи

(остается вопрос: а что если кто-то сделает reference_count=0 в параллельном потоке? но тогда и константная ссылка не спасет)

www_linux_org_ru ★★★★★
()
Последнее исправление: www_linux_org_ru (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.