Russian Qt Forum

Qt => Общие вопросы => Тема начата: Igors от Октябрь 25, 2014, 14:42



Название: Накладные расходы слот-сигнал
Отправлено: Igors от Октябрь 25, 2014, 14:42
Добрый день

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

При каком конкретно времени исполнения слота (вкупе с частотой сигналов) эти расходы становятся ощутимыми? Конечно результат зависит от машины, платформы и версии Qt. Для данных ниже; скромный Хeon 2.66, 4 ядра, Qt 4.7.4, OSX 10.7.5 и даже Debug build.

Что и как меряем
Сначала вызываем тело слота (нагрузку) напрямую и засекаем сколько раз оно выполнилось в секунду. Затем испускаем такое же кол-во сигналов (неск способами) в секунду и смотрим сколько раз сработал слот в секунду. Отношение этих 2 замеров и даст оверхед. Понятно что если нагрузка достаточно велика - никакого оверхеда вообще не увидим. Поэтому тестировались 2 задачи

а) "min Job"  (холостой ход) тело слота почти пустое. Ну ++ к паре счетчиков, if (раз в 10К) и печать раз в секунду. Ну плюс деструктор аргумента QStringList (сводится к имплисит шаре)

b) "1K Job" то же что "a" но добавлено изменения QStringList (100 строк по 10 символов), теперь он уже будет реально скопирован и удален.  

Результаты холостого хода
Цитировать
--------- Test min Job ------------

Test 1 direct call:
received/sec 13424576.0
received/sec 13580420.0
received/sec 13573427.0
received/sec 13577423.0
total received = 54210000

Test 2 direct signal:
received/sec 1644355.6
received/sec 1664335.6
received/sec 1664335.6
received/sec 1664335.6
total received = 6644000

Test 3 queued signal:
received/sec 90367.4
received/sec 95378.6
received/sec 104685.9
received/sec 110889.1
total received = 404000
Тут ничего особенного, Понятно что DirectConnection чего-то весит, QueuedConnection еще больше

Цитировать
Test 4 queued signal multi-sender:
received/sec 9442.9
received/sec 9624.6
received/sec 9182.7
received/sec 10018.2
total received = 41000
А вот тут уже интереснее. То же число сигналов посылается не одной. а 3-мя нитками. Ядер хватает, но скорость резко упала, ведь за мутекс дерутся уже не 2 а 4 нитки. Что будет дальше (при большем числе "испускающих") - не проверял

Результаты небольшой нагрузки
Цитировать
--------- Test 1K Job ------------

Test 1 direct call:
received/sec 21526.4
received/sec 21442.5
received/sec 21442.5
received/sec 21421.6
total received = 88000

Test 2 direct signal:
received/sec 21317.8
received/sec 21153.8
received/sec 21174.2
received/sec 21153.8
total received = 88000

Test 3 queued signal:
received/sec 19802.0
received/sec 19665.7
received/sec 19120.5
received/sec 19743.3
total received = 80000

Test 4 queued signal multi-sender:
received/sec 9132.4
received/sec 9242.1
received/sec 9311.0
received/sec 9389.7
total received = 40000
Вполне ожидаемо - чем больше нагрузка, тем стабильнее. Разница Direct/Queued уже невелика, но проседание на последнем тесте все еще вдвое. Хотя кто знает, может это я где-то ошибся

Остальное см в прилагаемых исходниках.

Ну вот, я кажется начал писать блоги  :'(


Название: Re: Накладные расходы слот-сигнал
Отправлено: kuzulis от Октябрь 27, 2014, 11:30
А ты в development (или interest) рассылку кинь это все. Мож там что-то конкретное ответят про проседание и прочее. А то тут много всяких "комментаторов" сейчас понабежит. :)


Название: Re: Накладные расходы слот-сигнал
Отправлено: qate от Октябрь 27, 2014, 12:37
если гдето ответят - отпишись тут )

а если завести 4 qeventloop-a и в каждом бросать сигналы и ловить слоты - может ядра загрузятся ?


Название: Re: Накладные расходы слот-сигнал
Отправлено: vulko от Октябрь 27, 2014, 13:08
А вот тут уже интереснее. То же число сигналов посылается не одной. а 3-мя нитками. Ядер хватает, но скорость резко упала, ведь за мутекс дерутся уже не 2 а 4 нитки. Что будет дальше (при большем числе "испускающих") - не проверял

Это вот эта глобальная (ахтунг!) переменная - мьютекс, то?)))
Код:
QSemaphore theSemaphore;


Да и вообще непонятно что тут замеряется и в чем вопрос?

Разница между DirectConnection и QueuedConnection ровно в том что, первое выполнит слот в потоке в котором был сигнал, а второе выполнит слот в потоке где живет объект, у которого он вызывается. Вызов через event loop и соотв. отсюда и разница во времени выполнения.

А "проседания", которые вовсе не проседания, а разные типы выполнения слотов, сильно зависят от кода. В данном случае он такой, в другом случае другие цифры будут.


Название: Re: Накладные расходы слот-сигнал
Отправлено: xokc от Октябрь 27, 2014, 13:14
Да и вообще непонятно что тут замеряется и в чем вопрос?
Что замеряется понятно, а вот в чем вопрос, действительно, не понятно.  :)


Название: Re: Накладные расходы слот-сигнал
Отправлено: vulko от Октябрь 27, 2014, 14:22
Да и вообще непонятно что тут замеряется и в чем вопрос?
Что замеряется понятно, а вот в чем вопрос, действительно, не понятно.  :)

Понятно?) Точно?)

Цитировать
А вот тут уже интереснее. То же число сигналов посылается не одной. а 3-мя нитками. Ядер хватает, но скорость резко упала, ведь за мутекс дерутся уже не 2 а 4 нитки. Что будет дальше (при большем числе "испускающих") - не проверял

Откуда 2-а?
NUM_SENDER = 1 в исходниках.


Небольшой тизер...
Код:
void CReceiver::SlotGet( QStringList lst )
{
if (mNumPrint >= NUM_PRINT) return;

if (mJobID == JOB_1K)
for (int i = 0; i < lst.size(); ++i)
lst[i][0] = 'B';

++mCount;
++mTotal;
if (mCount % 1000 * 10) return;
int delta = mTime.elapsed();                                            // <------------------------------- конец замера
if (delta > 1000) {
printf("received/sec %.1f\n", mCount * 1000.0f / delta);
mCount = 0;
mTime.restart();                                                     // <------------------------------- начало замера
++mNumPrint;
if (mNumPrint >= NUM_PRINT)
theSemaphore.release();
}
}


Тут весь проект сделан через не то место.
Нормальные замеры делают так - 1 000 000 вызовов directcall, 1 000 000 queuedconnection.
Замеряется время затраченное в первом и во втором случае. Далее 1 000 000 вызовов делится на количество секунд, и получается количество вызовов в секунду.
А тут что? А когда потоков сендеров >1 тут вообще полный писец.


И что же в итоге замеряется? Как полное отсутсвие хоть сколь-нибудь продуманной архитектуры сказывается на производительности?


Название: Re: Накладные расходы слот-сигнал
Отправлено: Пантер от Октябрь 27, 2014, 15:19
Может, я что-то не понял, но директ коннекшн транслируется в прямой вызов. Накидал очень быструю тестовую прогу, все норм:

31742 - прямой вызов
32637 - direct
34128 - queue

Это затраченное время в мс на 1000000 итераций.


Название: Re: Накладные расходы слот-сигнал
Отправлено: vulko от Октябрь 27, 2014, 15:30
Может, я что-то не понял, но директ коннекшн транслируется в прямой вызов. Накидал очень быструю тестовую прогу, все норм:

31742 - прямой вызов
32637 - direct
34128 - queue

Это затраченное время в мс на 1000000 итераций.


Это не совсем корректно.
Лучше делать замеры между вызовом emit signal и непосредственным вызовом slot'а.


Название: Re: Накладные расходы слот-сигнал
Отправлено: Пантер от Октябрь 27, 2014, 15:32
Может, я что-то не понял, но директ коннекшн транслируется в прямой вызов. Накидал очень быструю тестовую прогу, все норм:

31742 - прямой вызов
32637 - direct
34128 - queue

Это затраченное время в мс на 1000000 итераций.


Это не совсем корректно.
Лучше делать замеры между вызовом emit signal и непосредственным вызовом slot'а.
Да, понял ошибку. Но лень сейчас накидывать тест.


Название: Re: Накладные расходы слот-сигнал
Отправлено: Пантер от Октябрь 27, 2014, 15:46
Вопщем, я к тому, что у DirectConnection будет незначительная просадка, по отношению к прямому вызову. QueueConnection будет значительно им уступать, но тут  все логично.


Название: Re: Накладные расходы слот-сигнал
Отправлено: xokc от Октябрь 27, 2014, 19:35
Если речь идет об одном потоке писателе и одном читателе - тут всё понятно. Интереснее вопрос насколько успешно система сигнал/слотов разрулит ситуацию с несколькими (многими) писателями и несколькими (многими) читателями. А также то, насколько она в этом смысле эффективнее (или не эффективнее), например, очереди на QAtomic или неблокирующей очереди из liblfds.org. Или очереди на ZeroMQ. И так далее.


Название: Re: Накладные расходы слот-сигнал
Отправлено: qate от Октябрь 28, 2014, 08:24
А также то, насколько она в этом смысле эффективнее (или не эффективнее), например, очереди на QAtomic или неблокирующей очереди из liblfds.org. Или очереди на ZeroMQ. И так далее.

чтобы внедрять "другие" очереди в проект на qt - это надо действительно иметь причину (не баг) для этого
о таких случаях я нигде не читал (не говорю что читал многое)



Название: Re: Накладные расходы слот-сигнал
Отправлено: vulko от Октябрь 28, 2014, 09:22
Если речь идет об одном потоке писателе и одном читателе - тут всё понятно. Интереснее вопрос насколько успешно система сигнал/слотов разрулит ситуацию с несколькими (многими) писателями и несколькими (многими) читателями. А также то, насколько она в этом смысле эффективнее (или не эффективнее), например, очереди на QAtomic или неблокирующей очереди из liblfds.org. Или очереди на ZeroMQ. И так далее.

Сигнал-слоты это не производительное решение, т.к. queuedconnection не подразумевает быстрого отклика, а direct connection вообще не подходит для многопоточного использования.
В этом контексте мне непонятно о какой эффективности ты говоришь.


Название: Re: Накладные расходы слот-сигнал
Отправлено: vulko от Октябрь 28, 2014, 09:25
Вопщем, я к тому, что у DirectConnection будет незначительная просадка, по отношению к прямому вызову. QueueConnection будет значительно им уступать, но тут  все логично.

Именно. При этом direct и queued connection'ы - это абсолютно разные вещи. Один для однопотока, второй для многопотока.


Название: Re: Накладные расходы слот-сигнал
Отправлено: Igors от Октябрь 28, 2014, 10:45
По поводу измерений. "Давайте вызовем мульен напрямую а потом мульен слот-сигнал, вот и все". Это не годится для queued. Непрерывно помещая сигнал (фактически событие) в очередь, мы постоянно/часто блокируем мутекс очереди, и обработчику трудно извлечь событие. В результате увидим гораздо больший оверхед, который сами же и создали. Поэтому посылается то число сигналов которое обработчик может переварить (получено прямым вызовом), и не все сразу а равномерно (порциями).

Тут одна неточность - для queued меряем только время приема, но ведь есть еще и посылка (которая сейчас в др нитке/ядре)

Как этим пользоваться. Запустить и посмотреть оверхед queued c небольшой нагрузкой. Напр вижу он не больше 10%, меня устраивает. Если нет - подкрутить константу NUM_STR (нагрузка больше/меньше). Имеем число обработок в секунду, напр 20K. Это можно считать пропускной способностью очереди, (немного завышенной). Т.е. если мы будем шмалять такие сигналы с частотой 20К/sec, то очередь будет расти и, возможно, переполнится. А вот если  10K (или даже 15K) то нам ничего не грозит, и затраты на слот/сигнал не превышают 10% от полезной работы.

Теперь осталось засечь число срабатываний слота в проекте. Пример (с которого все началось). Человек спросил какие проблемы могут быть если на частоте сотни в секунду в теле слота выполняется помещение а контейнер. Эту операцию нет смысла даже мерять - "холостой ход". Да, 90% оверхед, или даже больше. Но при такой ничтожной частоте и потери-то с гулькин нос. Т.е. затратили напр 1 секунду (за неск часов работы приложения). Мы могли сделать то же за 0.1 секунды (в 10 раз быстрее), но зачем?

Если речь идет об одном потоке писателе и одном читателе - тут всё понятно. Интереснее вопрос насколько успешно система сигнал/слотов разрулит ситуацию с несколькими (многими) писателями и несколькими (многими) читателями. А также то, насколько она в этом смысле эффективнее (или не эффективнее), например, очереди на QAtomic или неблокирующей очереди из liblfds.org. Или очереди на ZeroMQ. И так далее.
С удовольствием приму участие в обсуждении. Но начинать надо "от печки", т.е. с выяснения той частоты где появляется нужда в чем-то более интеллектуальном чем вязка слот-сигнал веников  :)

а если завести 4 qeventloop-a и в каждом бросать сигналы и ловить слоты - может ядра загрузятся ?
У каждой нитки свой (и только один) qeventloop, поэтому не вижу как создать ситуацию "много читателей" (из того же ведра). "Много писателей" - см последний тест, да, пагубно влияет.

если гдето ответят - отпишись тут )
Да я, собственно, ничего и не спрашивал  :)


Название: Re: Накладные расходы слот-сигнал
Отправлено: vulko от Октябрь 28, 2014, 11:34
Человек спросил какие проблемы могут быть если на частоте сотни в секунду в теле слота выполняется помещение а контейнер.

Наговнокодил кривой пример и продолжает из себя эксперта строить...  ;D

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


Название: Re: Накладные расходы слот-сигнал
Отправлено: xokc от Октябрь 28, 2014, 16:23
Но начинать надо "от печки", т.е. с выяснения той частоты где появляется нужда в чем-то более интеллектуальном чем вязка слот-сигнал веников  :)
Полностью согласен. Кто готов выяснить значение частоты? :)


Название: Re: Накладные расходы слот-сигнал
Отправлено: Igors от Октябрь 29, 2014, 09:20
Полностью согласен. Кто готов выяснить значение частоты? :)
Так его уже выяснили. Напр если тело слота исполняется 20K/сек, то при работе с частотой 15K все хорошо, оверхед невелик. При меньшем времени исполнения слота оверхед будет расти и наоборот.

Понятно что если мы помещаем в очередь больше событий чем обработчик успевает прожевать, то очередь будет неуклонно расти, это неизбежно, оверхед слот/сигнала здесь ни при чем. Да, и Qt очередь использует стандартную схему (Q)WaitCondition.

По поводу "столкновения на мутексе" - неоднократно замечал что чем больше ниток конкурируют за него, тем хуже скорость, причем значительно. Поэтому и добавил этот тест.

Предлагаю такой вывод: основанием для отказа от (удобного) обмена с помощью слот/сигнал могут служить:

 - высокие требования к пропускной способности очереди (типа 30-40К/сек)
 - перекосы в планировании типа 10 пишут - 1 читает, также при приличной частоте   

И то и другое не так уж просто получить :) Напр для первого напрашивается вопрос: а чего такую мелкоту гнать через очередь в таком количестве?


Название: Re: Накладные расходы слот-сигнал
Отправлено: xokc от Октябрь 29, 2014, 22:32
Переформулирую и конкретизирую вопрос. Частота наполнения очереди - 10 раз в секунду, размер каждого элемента от 128 до 256 кБайт, частота чтения из неё - от 10 до 80 раз в секунду, потоков-писателей 8 шт., читатели (X шт.) объединены в пулы, пусть их количество (пулов в смысле) равно 16. Продолжительность обработки каждого элемента очереди каждым читателем - 1 мс, процессор 24-х ядерный. Чему равно Xmax при требуемой общей загруженности CPU в среднем не более 50%? Без реального моделирования это можно оценить?


Название: Re: Накладные расходы слот-сигнал
Отправлено: Igors от Октябрь 30, 2014, 09:23
Переформулирую и конкретизирую вопрос. Частота наполнения очереди - 10 раз в секунду, размер каждого элемента от 128 до 256 кБайт, частота чтения из неё - от 10 до 80 раз в секунду, потоков-писателей 8 шт., читатели (X шт.) объединены в пулы, пусть их количество (пулов в смысле) равно 16. Продолжительность обработки каждого элемента очереди каждым читателем - 1 мс, процессор 24-х ядерный. Чему равно Xmax при требуемой общей загруженности CPU в среднем не более 50%? Без реального моделирования это можно оценить?
При конкретно 16 читателях - полагаю ровным счетом ничего не грозит, частота слишком мала. Наверное Вы говорите об обычной/стандартной очереди на (Q)WaitCondition - в случае слот/сигнал не вижу как сделать "много читателей". Если не так понял - поправьте.

Сколько ниток-читателей выдержит? Здесь не скажу, надо проверять. Но в любом случае плодить нитки "на каждого" плохо. Не совсем ясно что здесь "пул".