Re[11]: SObjectizer: I Love This Game!
От: remark Россия http://www.1024cores.net/
Дата: 07.05.07 15:40
Оценка:
Здравствуйте, eao197, Вы писали:

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


R>>А тебя в SObjectizer мьютексы тоже локальные используются или один глобальный? Если один глобальный, то в тесте надо тоже сделать один на все объекты, а не на каждый объект по мьютексу...


E>Глобальные мьютексы используются (если вспоминать навскидку) для:

E>* защиты ядра SObjectizer и его системного словаря при выполнении таких операций, как send_msg, register_coop, deregister_coop и пр.;

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

E>* при выделении памяти в стандратной библиотеке C++.


Тут можно так сделать — для объектов, которые выделяются в больших количествах (сообщения/события), можно сделать эффективные кэширующие неблокирующие схемы, которые тоже не будут затрагивать мьютексов и атомарных операций.
Трейдофф: большее потребление памяти. Ну, если надо быстро, то кэшировать придётся в любом случае — тут стандартный размен памяти на скорость.



1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[11]: SObjectizer: I Love This Game!
От: remark Россия http://www.1024cores.net/
Дата: 07.05.07 15:51
Оценка:
Здравствуйте, eao197, Вы писали:

E>Я бы добавил сюда еще и потенциальные проблемы с переносимостью atomic-операций. На x86 есть инструкции для их поддержке. А вот на каких-нибудь Sun-ах или MIPS-ах с этим дело как обстоит?


Это как раз принципиальной проблемы точно не составляет.
Так или иначе аналоги этих операций есть на всех SMP системах — иначе бы там и мьютекса не сделать.
На большинстве машин примитивы достаточно похожи на x86, на каких-то примитивы немного другие, но базовые вещи, такие как референс каунтинг или мьютекс, точно сделать можно.
Да, портировать, конечно, будет сложнее. Но в идеале можно тоже взять готовую библиотеку портированных примитивов и использовать её. Вот ты сам приводил в примере атомарные операции в ACE...
Ну и в любом случае эти все вещи можно достаточно чётко локализовать в классах типа atomic_ref_counter, thread_shared_ptr, fifo_queue и т.д. И уже портровать исключительно их, на крайний случай для какой-то платформы можно сделать и на мьютексе.


1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[11]: SObjectizer: I Love This Game!
От: remark Россия http://www.1024cores.net/
Дата: 07.05.07 16:36
Оценка:
Здравствуйте, eao197, Вы писали:

E>Принцип такой:

E>* при отсылке сообщения создается объект so_4::rt::msg_data_t. Он создает объект so_4::rt::impl::msg_data_impl_t;
E>* когда создается объект so_4::rt::impl::msg_data_impl_t (т.е. описатель экземпляра сообщения внутри SObjectizer), то увеличивается счетчик ссылок на сам msg_data_impl_t, а так же на соответствующего агента (объект so_4::rt::impl::agent_wrapper_base_t);
E>* при копировании so_4::rt::msg_data_t инкрементируются и декрементируются счетчики на so_4::rt::impl::msg_data_impl_t;
E>* при диспетчеризации заявок, полученных при отсылке сообщения, создаются объекты so_4::rt::event_data_t. Которые содержат в себе объекты, производные от so_4::rt::impl::event_data_impl_t;
E>* когда создается объект so_4::rt::impl::evt_data_impl_t (т.е. описатель одной заявки для события), то увеличивается счетчик ссылок на сам evt_data_impl_t и на соответствующего агента;
E>* так же so_4::rt::impl::evt_data_impl_t содежат ссылку на msg_data_impl_t и для сохранения ее корректности увеличивают количество ссылок на msg_data_impl_t (с соответствующим увеличением количества ссылок на агента).

E>Схема запутанная, но пять лет назад я не смог придумать ничего лучше, поскольку объекты msg_data_t, event_data_t всю эту кухню скрывают внутри себя, что позволяет легко манипулировать объектами msg_data_t, event_data_t -- а это было очень важно чтобы получить корректно работающую версию SObjectizer.


Ну схема не особо запутанная — видно, что ты отталкивался от корректности работы, поэтому всё получается достаточно логично.

Сходу:

Вот это избыточно:
E>* когда создается объект so_4::rt::impl::evt_data_impl_t (т.е. описатель одной заявки для события), то увеличивается счетчик ссылок на сам evt_data_impl_t и на соответствующего агента;
Т.к. событие держит сообщение, а сообщение держит агента — следовательно событию держать агента уже не обязательно.

Вот это тоже вроде как избыточно, т.к. агента мы уже держим с помощью самого сообщения:
* так же so_4::rt::impl::evt_data_impl_t содежат ссылку на msg_data_impl_t и для сохранения ее корректности увеличивают количество ссылок на msg_data_impl_t (с соответствующим увеличением количества ссылок на агента).

Потом я так понимаю, что ты используешь хендлы разделяемых объектов, которые при создании/копировании увеличивают счётчик для объекта, а в деструкторе уменьшают его. Неинтрузивное владение и неинтрузивные контейнеры, конечно, очень удобно и просто, но приводит к лишним изменениям счётчика.

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

— при этом каждый раз трогать счётчик агента нет смысла — можно положить в tls агрегированный счётчик использования этого агента всеми сообщениями и событиями этого треда, т.о. сам разделяемый счётчик агента будет декрементироваться только один раз, когда в данном треде никто больше его не использует (с агрегированным счётчиком в tls можно работать простыми декрементами/инкрементами — ничего защищать не надо)

— плюс можно аналогично агрегировать работу со счётчиком события по потокам, т.е. только последняя обработка события в потоке будет уменьшать его счётчик

Это, конечно, очень схематично. Наверняка в реальнсти всё будет сложнее. Да и тут вопросов много — например, как эффективно хранить в tls агрегированные счётчики для всех агентов. Но тем не менее, я думаю, что что-то похожее можно сделать.

Зато в итоге получаем следующее — из всей работы со счётчиками остаётся только декремент одного счётчика события после обработки, да и то не каждый раз. Вот это уже близко к желаемому результату.

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


Стоп. Я наверное тут что-то напутал. Ну ладно уже написал — удалять жалко
При отсылке сообщения надо инкрементировать счётчик не только для агента, которому принадлежит сообщение, но и тем, кому сообщение отправляется. Правильно? Ну всё равно временем жизни агентов можно управлять агрегированно на уровне потоков — только когда никто в потоке не интересуется агентом, декрементируем у него счётчик.
С событиями я похоже тоже что-то напутал — т.к. для одного сообщения создаётся не одно событие, а множество. Правильно? Тоже всё равно можно что-нибудь агрегировать по потокам и убрать избыточные инкремены/декременты.



1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[11]: SObjectizer: I Love This Game!
От: remark Россия http://www.1024cores.net/
Дата: 07.05.07 16:44
Оценка:
Здравствуйте, eao197, Вы писали:

Вот это я что-то не очень понял:

E>* когда создается объект so_4::rt::impl::evt_data_impl_t (т.е. описатель одной заявки для события), то увеличивается счетчик ссылок на сам evt_data_impl_t и на соответствующего агента;


evt_data_impl_t сам на себя счётчик увеличивает?

И про агентов я запутался — тут же несколько агентов принимает участие — один, которому принадлежит сообщение, и остальные, которые обрабатывают события. Правильно?




E>* при отсылке сообщения создается объект so_4::rt::msg_data_t. Он создает объект so_4::rt::impl::msg_data_impl_t;


Вот тут вот мы увеличиваем счётчик агента, которому принадлежит сообщение:

E>* когда создается объект so_4::rt::impl::msg_data_impl_t (т.е. описатель экземпляра сообщения внутри SObjectizer), то увеличивается счетчик ссылок на сам msg_data_impl_t, а так же на соответствующего агента (объект so_4::rt::impl::agent_wrapper_base_t);


E>* при копировании so_4::rt::msg_data_t инкрементируются и декрементируются счетчики на so_4::rt::impl::msg_data_impl_t;

E>* при диспетчеризации заявок, полученных при отсылке сообщения, создаются объекты so_4::rt::event_data_t. Которые содержат в себе объекты, производные от so_4::rt::impl::event_data_impl_t;

А вот тут вот уже на того агента, который будет обрабатывать событие:

E>* когда создается объект so_4::rt::impl::evt_data_impl_t (т.е. описатель одной заявки для события), то увеличивается счетчик ссылок на сам evt_data_impl_t и на соответствующего агента;


А вот тут опять на первого:

E>* так же so_4::rt::impl::evt_data_impl_t содежат ссылку на msg_data_impl_t и для сохранения ее корректности увеличивают количество ссылок на msg_data_impl_t (с соответствующим увеличением количества ссылок на агента).


Правильно?



1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[12]: SObjectizer: I Love This Game!
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 07.05.07 17:02
Оценка:
Здравствуйте, remark, Вы писали:

E>>* защиты ядра SObjectizer и его системного словаря при выполнении таких операций, как send_msg, register_coop, deregister_coop и пр.;


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

R>Трейдофф: при изменении системного словаря придётся его копировать. По крайне мере частично.

Это будет довольно накладно, когда агентов будет тысячи, а создаваться и удаляться они будут на каждый чих (как процессы в Erlang). В ряде проектов у нас так и делается -- агенты создаются на каждую транзацию, иногда сотни в секунду.

E>>* при выделении памяти в стандратной библиотеке C++.


R>Тут можно так сделать — для объектов, которые выделяются в больших количествах (сообщения/события), можно сделать эффективные кэширующие неблокирующие схемы, которые тоже не будут затрагивать мьютексов и атомарных операций.

R>Трейдофф: большее потребление памяти. Ну, если надо быстро, то кэшировать придётся в любом случае — тут стандартный размен памяти на скорость.

Это можно решать не задействуя внутренности SObjectizer -- пользователь может сам реализовывать new/delete для своих сообщений.

А память в самом SObjectizer нужно будет оптимизировать когда именно она станет узким местом.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[12]: SObjectizer: I Love This Game!
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 07.05.07 17:19
Оценка:
Здравствуйте, remark, Вы писали:

E>>* когда создается объект so_4::rt::impl::evt_data_impl_t (т.е. описатель одной заявки для события), то увеличивается счетчик ссылок на сам evt_data_impl_t и на соответствующего агента;


R>evt_data_impl_t сам на себя счётчик увеличивает?


Очепятался -- когда создается so_4::rt::event_data_t.

R>И про агентов я запутался — тут же несколько агентов принимает участие — один, которому принадлежит сообщение, и остальные, которые обрабатывают события. Правильно?


Да.


E>>* при отсылке сообщения создается объект so_4::rt::msg_data_t. Он создает объект so_4::rt::impl::msg_data_impl_t;


R>Вот тут вот мы увеличиваем счётчик агента, которому принадлежит сообщение:


E>>* когда создается объект so_4::rt::impl::msg_data_impl_t (т.е. описатель экземпляра сообщения внутри SObjectizer), то увеличивается счетчик ссылок на сам msg_data_impl_t, а так же на соответствующего агента (объект so_4::rt::impl::agent_wrapper_base_t);


E>>* при копировании so_4::rt::msg_data_t инкрементируются и декрементируются счетчики на so_4::rt::impl::msg_data_impl_t;

E>>* при диспетчеризации заявок, полученных при отсылке сообщения, создаются объекты so_4::rt::event_data_t. Которые содержат в себе объекты, производные от so_4::rt::impl::event_data_impl_t;

R>А вот тут вот уже на того агента, который будет обрабатывать событие:


E>>* когда создается объект so_4::rt::impl::evt_data_impl_t (т.е. описатель одной заявки для события), то увеличивается счетчик ссылок на сам evt_data_impl_t и на соответствующего агента;


R>А вот тут опять на первого:


E>>* так же so_4::rt::impl::evt_data_impl_t содежат ссылку на msg_data_impl_t и для сохранения ее корректности увеличивают количество ссылок на msg_data_impl_t (с соответствующим увеличением количества ссылок на агента).


R>Правильно?


Да.

Еще дополнение для полноты картины: сообщение может быть отложенным и/или переодическим. В этом случае еще msg_data_t уходит диспетчеру в нить таймера.

По поводу tls -- тогда усложняется подсчет количества ссылок на агента при дерегистрации.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[13]: SObjectizer: I Love This Game!
От: remark Россия http://www.1024cores.net/
Дата: 07.05.07 17:22
Оценка:
Здравствуйте, eao197, Вы писали:

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


E>>>* защиты ядра SObjectizer и его системного словаря при выполнении таких операций, как send_msg, register_coop, deregister_coop и пр.;


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

R>>Трейдофф: при изменении системного словаря придётся его копировать. По крайне мере частично.

E>Это будет довольно накладно, когда агентов будет тысячи, а создаваться и удаляться они будут на каждый чих (как процессы в Erlang). В ряде проектов у нас так и делается -- агенты создаются на каждую транзацию, иногда сотни в секунду.


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


E>>>* при выделении памяти в стандратной библиотеке C++.


R>>Тут можно так сделать — для объектов, которые выделяются в больших количествах (сообщения/события), можно сделать эффективные кэширующие неблокирующие схемы, которые тоже не будут затрагивать мьютексов и атомарных операций.

R>>Трейдофф: большее потребление памяти. Ну, если надо быстро, то кэшировать придётся в любом случае — тут стандартный размен памяти на скорость.

E>Это можно решать не задействуя внутренности SObjectizer -- пользователь может сам реализовывать new/delete для своих сообщений.


Внутри тоже, наверное, что-то должно часто создаваться/удаляться — события, например...

E>А память в самом SObjectizer нужно будет оптимизировать когда именно она станет узким местом.


Ну это без вопросов...


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[13]: SObjectizer: I Love This Game!
От: remark Россия http://www.1024cores.net/
Дата: 07.05.07 17:29
Оценка:
Здравствуйте, eao197, Вы писали:

E>По поводу tls -- тогда усложняется подсчет количества ссылок на агента при дерегистрации.


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

А чем tls усложняет? Это же просто кэширование. Т.е. можно 100 раз вызвать инкремент, потом 100 раз декремент. А можно с тем же успехом 1 раз вызвать инкремент, потом 99 раз посчитать в tls, а потом 1 раз вызвать декремент.
Т.е. с т.з. агента ничего не меняется — просто как будто его только один объект использует из потока...


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[14]: SObjectizer: I Love This Game!
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 07.05.07 18:39
Оценка:
Здравствуйте, remark, Вы писали:

E>>По поводу tls -- тогда усложняется подсчет количества ссылок на агента при дерегистрации.


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


R>А чем tls усложняет? Это же просто кэширование. Т.е. можно 100 раз вызвать инкремент, потом 100 раз декремент. А можно с тем же успехом 1 раз вызвать инкремент, потом 99 раз посчитать в tls, а потом 1 раз вызвать декремент.

R>Т.е. с т.з. агента ничего не меняется — просто как будто его только один объект использует из потока...

С точки зрения агента не меняется, меняется с точки зрения системного словаря и логики инкрементирования количества ссылок.

Тут с событиями для tls другой минус -- если не ошибаюсь, то event_data_t распихивается по очередям диспетчера совсем на другой нити, чем затем будет выполняться (на нити, на которой вызывался send_msg).

Хотя идея интересная. С ходу, правда, красивое и простое решение пока не вырисовывается, но можно покурить



SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[9]: SObjectizer: I Love This Game!
От: remark Россия http://www.1024cores.net/
Дата: 07.05.07 22:23
Оценка:
Здравствуйте, eao197, Вы писали:

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


R>>>>Хм... а почему нельзя использовать Interlocked-операции?


E>>>Потому что изменение счетчика ссылок на сообщение должно выполняться в одной же транзакции с изменением счетчика ссылок на агента-владельца. А иногда и еще какой-то счетчик задействуется (если не забыл ничего). Т.е. за раз нужно изменять сразу несколько ссылок.


R>>А почему это должно быть именно в одной транзакции? Почему никто не должен видеть эти счётчики в рассогласованных состояниях? Ведь с reference counting'ом обычно так — или в счётчике не ноль и тогда собственно пофигу что, т.к. объект не удаляется, или в счётчике 0, и тогда вобщем-то тоже пофигу, т.к. объект удаляется...


E>Я тут сваял тестик с некоторой имитацией подсчета ссылок в SObjectizer. Он делает подсчет ссылок на основе блокировке на mutex-е (фактически, critical section в Windows) и на основе atomic-операций. Дело в том, что в SObjectizer нужно увеличивать не один счетчик, а четыре. Поэтому интересно было сравнить, насколько четыре atomic-op выгоднее, чем один mutex. Оказались, что не выгоднее.


E>Вот замеры на Pentium-M 1.5GHz (512Mb, WinXP-SP2):

E>
E>objects: 1, thread_per_object: 4, cycles: 1000000
E>refcount_by_mutex: 0.578
E>refcount_by_atomic_op: 0.89
E>objects: 10, thread_per_object: 4, cycles: 1000000
E>refcount_by_mutex: 6.062
E>refcount_by_atomic_op: 8.842
E>objects: 100, thread_per_object: 4, cycles: 1000000
E>refcount_by_mutex: 59.633
E>refcount_by_atomic_op: 88.537
E>


E>Вот замеры на двух-процессорной 2 х Xeon 3.2 (2G RAM, Win2003):

E>
E>objects: 1, thread_per_object: 4, cycles: 1000000
E>refcount_by_mutex: 1.5
E>refcount_by_atomic_op: 1.969
E>objects: 10, thread_per_object: 4, cycles: 1000000
E>refcount_by_mutex: 4.313
E>refcount_by_atomic_op: 9.484
E>objects: 100, thread_per_object: 4, cycles: 1000000
E>refcount_by_mutex: 25.548
E>refcount_by_atomic_op: 47.469
E>


E>На двух-процессорной машине при увеличении количества нитей вариант на atomic-op проигрывает гораздо больше варианту с mutex-ом, чем на однопроцессорной (разрыв больше).


E>У тебя есть возможность прогнать этот тест на 4-х процессорной машине? (А то в моем распоряжении только 2-х процессорные). Требуется ACE, я использовал ACE 5.5.6.

1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[10]: SObjectizer: I Love This Game!
От: remark Россия http://www.1024cores.net/
Дата: 08.05.07 07:08
Оценка:
Здравствуйте, eao197, Вы писали:

E>>Я тут сваял тестик с некоторой имитацией подсчета ссылок в SObjectizer. Он делает подсчет ссылок на основе блокировке на mutex-е (фактически, critical section в Windows) и на основе atomic-операций. Дело в том, что в SObjectizer нужно увеличивать не один счетчик, а четыре. Поэтому интересно было сравнить, насколько четыре atomic-op выгоднее, чем один mutex. Оказались, что не выгоднее.


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


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[11]: SObjectizer: I Love This Game!
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 08.05.07 07:24
Оценка:
Здравствуйте, remark, Вы писали:

R>Ты тут немного смухлевал

R>У тебя там не 4 счётчика под одним мьютексом меняются, а два под одним, и потом ещё два под другим. Т.ч. я думаю, тут производительность должна быть практически одинаковой, что так 4 счётчика менять, что все 4 interlocked операциями. Даже должно быть под сильной нагрузкой interlocked чуть быстрее.

Ты имеешь в виду SObjectizer?
Так если interlocked не дают ощутимого преимущества, то не видно причин менять существующий и отлаженный код на новый, который еще предстоит написать и отладить. И при наличии вероятности, что для какой-нибудь платформы в ACE не будет эффективной реализации atomic-операций.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[12]: SObjectizer: I Love This Game!
От: remark Россия http://www.1024cores.net/
Дата: 08.05.07 09:21
Оценка:
Здравствуйте, eao197, Вы писали:

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


R>>Ты тут немного смухлевал

R>>У тебя там не 4 счётчика под одним мьютексом меняются, а два под одним, и потом ещё два под другим. Т.ч. я думаю, тут производительность должна быть практически одинаковой, что так 4 счётчика менять, что все 4 interlocked операциями. Даже должно быть под сильной нагрузкой interlocked чуть быстрее.

E>Ты имеешь в виду SObjectizer?


Да. Методы agent_wrapper_base_t::inc_ref_count()/agent_wrapper_base_t::dec_ref_count()

E>Так если interlocked не дают ощутимого преимущества, то не видно причин менять существующий и отлаженный код на новый, который еще предстоит написать и отладить. И при наличии вероятности, что для какой-нибудь платформы в ACE не будет эффективной реализации atomic-операций.


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


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[13]: SObjectizer: I Love This Game!
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 08.05.07 09:28
Оценка:
Здравствуйте, remark, Вы писали:

R>Да. Методы agent_wrapper_base_t::inc_ref_count()/agent_wrapper_base_t::dec_ref_count()


Ok.

E>>Так если interlocked не дают ощутимого преимущества, то не видно причин менять существующий и отлаженный код на новый, который еще предстоит написать и отладить. И при наличии вероятности, что для какой-нибудь платформы в ACE не будет эффективной реализации atomic-операций.


R>Как говорится "моё дело предложить — твоё дело отказаться"


Именно. Поэтому огромное спасибо за участие.
Будет возможность -- черкни мне письмецо с твоими координатами для включения в THANKS.

R>Ну вообще задача не просто заменить мьютексы на atomic-операции, задача — сделать 0 (прописью: ноль ) atomic-операций на основном пути отправки сообщений. Этот тест это ты написал, а не я


Я пока не вижу, как вообще отказаться от синхронизации. Кстати, подозреваю, что по сравнению с mutex-ами или atomic-операциями TLS так же будет не самым дешовым вариантом.

У меня сейчас есть какие-то смутные идеи по организации чего-то вроде сборки мусора для таких сущностей как msg_data_impl_t и event_data_impl_t. Т.е. при их создании инкрементируется счетчик ссылок у агента, но не в таком количестве раз, как сейчас. А затем они убиваются не сразу после своей обработки, а при неких подходящих условиях.

Возможно, количество обращений к мутексу получится серьезно сократить.

В любом случае


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[9]: SObjectizer: I Love This Game!
От: remark Россия http://www.1024cores.net/
Дата: 08.05.07 09:30
Оценка:
Здравствуйте, eao197, Вы писали:

E>Я тут сваял тестик с некоторой имитацией подсчета ссылок в SObjectizer. Он делает подсчет ссылок на основе блокировке на mutex-е (фактически, critical section в Windows) и на основе atomic-операций. Дело в том, что в SObjectizer нужно увеличивать не один счетчик, а четыре. Поэтому интересно было сравнить, насколько четыре atomic-op выгоднее, чем один mutex. Оказались, что не выгоднее.



Я тут такой провёл эксперимент.
Запустил бенчмарк customer_ring (ring size: 10000; token count: 100; dispatcher: one thread) — получил пропускную способность 162000.
Потом убрал в функции send_msg() rw_mutex so_4::rt::impl::kernel_t::shutdown_preventer_t shutdown_preventer
получил пропускную способность 163000
Потом убрал мьютексы в функциях agent_wrapper_base_t::inc_ref_count()/agent_wrapper_base_t::dec_ref_count() (те самые, которые считают референс каунтеры для сообщений/событий/агентов)
получил пропускную способность 167000

... прирост не то чтобы особо существенный... даже если убрать все эти мьютексы...
Вообще-то я же тестировал на одноядерном AMD (а AMD похоже грамотно обрабатывают атомарные операции в одноядерном режиме — не вносят никакого оверхеда)...

А ты не пробовал такой тест проводить — если убрать всю синхронизацию на основном пути?
Ну типа, что б вообще понять предел, к чему можно стремится. И что б понять, что узкое место именно здесь. Особенно было бо интересно поглядеть для двухядерной машины.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[14]: SObjectizer: I Love This Game!
От: remark Россия http://www.1024cores.net/
Дата: 08.05.07 09:42
Оценка:
Здравствуйте, eao197, Вы писали:

R>>Как говорится "моё дело предложить — твоё дело отказаться"


E>Именно. Поэтому огромное спасибо за участие.

E>Будет возможность -- черкни мне письмецо с твоими координатами для включения в THANKS.



R>>Ну вообще задача не просто заменить мьютексы на atomic-операции, задача — сделать 0 (прописью: ноль ) atomic-операций на основном пути отправки сообщений. Этот тест это ты написал, а не я


E>Я пока не вижу, как вообще отказаться от синхронизации. Кстати, подозреваю, что по сравнению с mutex-ами или atomic-операциями TLS так же будет не самым дешовым вариантом.


Если взять TLS как его предоставляет Win API, то это очень-очень быстро — это затрагивает не более чем пара машинных инструкций — косвенное обращение и инкремент — естественно, что никакой синхронизации и никаких обращений к глобальным данным.
Что поверх этого наворачивает pthread или ACE — это уже другой вопрос — но надо надеятся, что тоже не очень много.
TLS — это _очень_ мощный инструмент для оптимизации многопоточных приложений.


E>У меня сейчас есть какие-то смутные идеи по организации чего-то вроде сборки мусора для таких сущностей как msg_data_impl_t и event_data_impl_t. Т.е. при их создании инкрементируется счетчик ссылок у агента, но не в таком количестве раз, как сейчас. А затем они убиваются не сразу после своей обработки, а при неких подходящих условиях.


E>Возможно, количество обращений к мутексу получится серьезно сократить.


Вот это уже в правильном направлении мысли
Если будет время может попробую сделать патч к SObjectizer как я себе это вижу...


E>В любом случае


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[10]: SObjectizer: I Love This Game!
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 08.05.07 09:48
Оценка:
Здравствуйте, remark, Вы писали:

R>Я тут такой провёл эксперимент.

R>Запустил бенчмарк customer_ring (ring size: 10000; token count: 100; dispatcher: one thread) — получил пропускную способность 162000.
R>Потом убрал в функции send_msg() rw_mutex so_4::rt::impl::kernel_t::shutdown_preventer_t shutdown_preventer
R>получил пропускную способность 163000
R>Потом убрал мьютексы в функциях agent_wrapper_base_t::inc_ref_count()/agent_wrapper_base_t::dec_ref_count() (те самые, которые считают референс каунтеры для сообщений/событий/агентов)
R>получил пропускную способность 167000

R>... прирост не то чтобы особо существенный... даже если убрать все эти мьютексы...

R>Вообще-то я же тестировал на одноядерном AMD (а AMD похоже грамотно обрабатывают атомарные операции в одноядерном режиме — не вносят никакого оверхеда)...

R>А ты не пробовал такой тест проводить — если убрать всю синхронизацию на основном пути?

R>Ну типа, что б вообще понять предел, к чему можно стремится. И что б понять, что узкое место именно здесь. Особенно было бо интересно поглядеть для двухядерной машины.

Я пока возьму тайм-аут чтобы разобраться с текущими делами.
Когда готовил третью бету SObjectizer, то проводил какие-то такие эксперименты. Что именно я убирал не помню, но без использования мутексов прирост составлял что-то порядка +20K сообщений в секунду на моем Centrino 1.5GHz.

PS. Координаты твои получил. В следуюей версии SObjectizer будут в THANKS


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[11]: SObjectizer: I Love This Game!
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 08.05.07 14:33
Оценка:
Здравствуйте, remark, Вы писали:

R>Ты тут немного смухлевал

R>У тебя там не 4 счётчика под одним мьютексом меняются, а два под одним, и потом ещё два под другим. Т.ч. я думаю, тут производительность должна быть практически одинаковой, что так 4 счётчика менять, что все 4 interlocked операциями. Даже должно быть под сильной нагрузкой interlocked чуть быстрее.

Как оказалось, смухлевал не немного, а много
Вот версия, которая использует два мутекса (по два счетчика под каждым). А так же содержит тест TLS (в терминологии ACE -- TSS).

Под WinXP для параметров 10 (объектов), 4 нити на каждый объект, 1000000 итераций:
mutex:  10.463
atomic:  6.558
tss:     7.229

То же параметры под Linux (Slackware 10.2, ядро 2.6.13):
mutex:  19.382
atomic:  5.539
tss:     8.193

Имеет смысл заниматься Atomic-ом.

Под Windows с использованием ACE 5.5.8 очень быстро вылазят ограничение на количество TLS переменных в программе. Уже при 15 объектах и 4 нитях на объект вылазят ошибки при обращении к TLS-счетчикам (видимо, TlsAlloc для них завершается неудачно).


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[12]: SObjectizer: I Love This Game!
От: remark Россия http://www.1024cores.net/
Дата: 08.05.07 16:43
Оценка:
Здравствуйте, eao197, Вы писали:

E>Под WinXP для параметров 10 (объектов), 4 нити на каждый объект, 1000000 итераций:

E>
E>mutex:  10.463
E>atomic:  6.558
E>tss:     7.229
E>

E>То же параметры под Linux (Slackware 10.2, ядро 2.6.13):
E>
E>mutex:  19.382
E>atomic:  5.539
E>tss:     8.193
E>




E>Имеет смысл заниматься Atomic-ом.





E>Под Windows с использованием ACE 5.5.8 очень быстро вылазят ограничение на количество TLS переменных в программе. Уже при 15 объектах и 4 нитях на объект вылазят ошибки при обращении к TLS-счетчикам (видимо, TlsAlloc для них завершается неудачно).


Странно... это под Win98 было порядка 20 слотов, а начиная с Win2k там вроде должно быть порядка 1000...
В любом случае выделять слот на каждый пук не стоит, т.к. выделение может быть _очень_ медленным, к тому же всё равно слоты рано или поздно кончатся.
В таких ситуациях обычно выделяют один слот, например, на библиотеку или на какую-либо подсистему и далее хранят в этом слоте некое множество объектов. Правда тут встаёт вопрос о быстром поиске в этом множестве...
Странно вообще, что у тебя TLS получился такой медленный... А ты случаем в цикле не выделяешь слоты? Может это оверхед ACE... Он же как раз по ходу должен в одном слоте хранить что-то типа map...

Кстати, это ты на какой тачке мерил? На одноядерной или на двуядерной? Если на одноядерной, то на двуядерной должно быть ещё круче


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[13]: SObjectizer: I Love This Game!
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 08.05.07 16:57
Оценка:
Здравствуйте, remark, Вы писали:

E>>Под Windows с использованием ACE 5.5.8 очень быстро вылазят ограничение на количество TLS переменных в программе. Уже при 15 объектах и 4 нитях на объект вылазят ошибки при обращении к TLS-счетчикам (видимо, TlsAlloc для них завершается неудачно).


R>Странно... это под Win98 было порядка 20 слотов, а начиная с Win2k там вроде должно быть порядка 1000...

R>В любом случае выделять слот на каждый пук не стоит, т.к. выделение может быть _очень_ медленным, к тому же всё равно слоты рано или поздно кончатся.

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

R>В таких ситуациях обычно выделяют один слот, например, на библиотеку или на какую-либо подсистему и далее хранят в этом слоте некое множество объектов. Правда тут встаёт вопрос о быстром поиске в этом множестве...


Вряд ли обычный std::map даст существенный оверхед по сравнению с mutex-ом

R>Кстати, это ты на какой тачке мерил? На одноядерной или на двуядерной? Если на одноядерной, то на двуядерной должно быть ещё круче


На одноядерной. Не всегда есть возможность на двухпроцессорной машине гонять тесты.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.