Russian Qt Forum
Ноябрь 22, 2024, 22:33 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Накладные расходы слот-сигнал  (Прочитано 10961 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Октябрь 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 уже невелика, но проседание на последнем тесте все еще вдвое. Хотя кто знает, может это я где-то ошибся

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

Ну вот, я кажется начал писать блоги  Плачущий
« Последнее редактирование: Октябрь 25, 2014, 17:44 от Igors » Записан
kuzulis
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2812


Просмотр профиля
« Ответ #1 : Октябрь 27, 2014, 11:30 »

А ты в development (или interest) рассылку кинь это все. Мож там что-то конкретное ответят про проседание и прочее. А то тут много всяких "комментаторов" сейчас понабежит. Улыбающийся
« Последнее редактирование: Октябрь 27, 2014, 11:38 от kuzulis » Записан

ArchLinux x86_64 / Win10 64 bit
qate
Супер
******
Offline Offline

Сообщений: 1177


Просмотр профиля
« Ответ #2 : Октябрь 27, 2014, 12:37 »

если гдето ответят - отпишись тут )

а если завести 4 qeventloop-a и в каждом бросать сигналы и ловить слоты - может ядра загрузятся ?
Записан
vulko
Гость
« Ответ #3 : Октябрь 27, 2014, 13:08 »

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

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


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

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

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

Сообщений: 976



Просмотр профиля
« Ответ #4 : Октябрь 27, 2014, 13:14 »

Да и вообще непонятно что тут замеряется и в чем вопрос?
Что замеряется понятно, а вот в чем вопрос, действительно, не понятно.  Улыбающийся
Записан
vulko
Гость
« Ответ #5 : Октябрь 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 тут вообще полный писец.


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

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #6 : Октябрь 27, 2014, 15:19 »

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

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

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

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
vulko
Гость
« Ответ #7 : Октябрь 27, 2014, 15:30 »

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

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

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


Это не совсем корректно.
Лучше делать замеры между вызовом emit signal и непосредственным вызовом slot'а.
Записан
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #8 : Октябрь 27, 2014, 15:32 »

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

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

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


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

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
Пантер
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 5876


Жаждущий знаний


Просмотр профиля WWW
« Ответ #9 : Октябрь 27, 2014, 15:46 »

Вопщем, я к тому, что у DirectConnection будет незначительная просадка, по отношению к прямому вызову. QueueConnection будет значительно им уступать, но тут  все логично.
Записан

1. Qt - Qt Development Frameworks; QT - QuickTime
2. Не используйте в исходниках символы кириллицы!!!
3. Пользуйтесь тегом code при оформлении сообщений.
xokc
Птица говорун
*****
Offline Offline

Сообщений: 976



Просмотр профиля
« Ответ #10 : Октябрь 27, 2014, 19:35 »

Если речь идет об одном потоке писателе и одном читателе - тут всё понятно. Интереснее вопрос насколько успешно система сигнал/слотов разрулит ситуацию с несколькими (многими) писателями и несколькими (многими) читателями. А также то, насколько она в этом смысле эффективнее (или не эффективнее), например, очереди на QAtomic или неблокирующей очереди из liblfds.org. Или очереди на ZeroMQ. И так далее.
« Последнее редактирование: Октябрь 27, 2014, 22:13 от xokc » Записан
qate
Супер
******
Offline Offline

Сообщений: 1177


Просмотр профиля
« Ответ #11 : Октябрь 28, 2014, 08:24 »

А также то, насколько она в этом смысле эффективнее (или не эффективнее), например, очереди на QAtomic или неблокирующей очереди из liblfds.org. Или очереди на ZeroMQ. И так далее.

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

Записан
vulko
Гость
« Ответ #12 : Октябрь 28, 2014, 09:22 »

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

Сигнал-слоты это не производительное решение, т.к. queuedconnection не подразумевает быстрого отклика, а direct connection вообще не подходит для многопоточного использования.
В этом контексте мне непонятно о какой эффективности ты говоришь.
Записан
vulko
Гость
« Ответ #13 : Октябрь 28, 2014, 09:25 »

Вопщем, я к тому, что у DirectConnection будет незначительная просадка, по отношению к прямому вызову. QueueConnection будет значительно им уступать, но тут  все логично.

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

Сообщений: 11445


Просмотр профиля
« Ответ #14 : Октябрь 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, поэтому не вижу как создать ситуацию "много читателей" (из того же ведра). "Много писателей" - см последний тест, да, пагубно влияет.

если гдето ответят - отпишись тут )
Да я, собственно, ничего и не спрашивал  Улыбающийся
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.078 секунд. Запросов: 22.