Здравствуйте, Ikemefula, Вы писали: I>Тоже можно Издержки разные, на порядок по времени например только из за медленной компиляции.
Это решается установкой разработчику нормального компа На современных четырехядерниках даже большие проекты компилятся довольно быстро.
Здравствуйте, Nik_1, Вы писали:
I>>Тоже можно Издержки разные, на порядок по времени например только из за медленной компиляции. N_>Это решается установкой разработчику нормального компа На современных четырехядерниках даже большие проекты компилятся довольно быстро.
5 минут — это чудовищно много.
Кроме того, для джавы и дотнета очень много самых различных тулов в силу синтаксиса.
Здравствуйте, Cyberax, Вы писали:
C>>>Intelocked-операции всю скорость съедят. В моём тесте с С++ один только interlocked exchange на refcounter'е в std::string уже тормозит больше, чем код на Java. CC>>Интерлокед там 1 на деаллокацию и только в случае деаллокации из не родного потока. Это довольно редкий сценарий. C>Там их больше будет. Например, для возврата объекта в "родной" пул и т.п.
Нет, ибо возвращает их в родные пенаты родной поток. Ну или если родной поток уже помер то вместо добавления в deferred освобождающий поток ограничивается декрементом счётчика выделенных блоков и если достигли нуля — убивает abandoned пул.
C>Получается очень и очень непростой дизайн аллокатора.
C'mon! Нет там ничего сверхсложного. Подумать надо, но никаких сверхнапрягов.
ThreadPoolAlloc у меня занял когда-то около часу ковыряшек из принципа на спор с кем то из шарпников по поводу скорости их GC.
C>>>С -XX:+UseParallelGC. CC>>Тогда я имею полное право использовать ThreadPoolAlloc. Так что всё равно нету 10х. C>Так я ведь задизайню тест, где у тебя всё будет сливать моему
Если будет эквивалентный код на Java и С++ — можем попробовать, если тебе ещё не надоело.
Я ведь тоже могу задизайнить тест, где учту слабые стороны GC.
C>Неа. Ты ну никак не можешь сделать многопоточный аллокатор без блокировок (sleeping mutexes) и/или атомарных операций.
Мутексы можно выкинуть вообще, а атомарники нужны только в случае если выделенный объект надо убивать в другом потоке. Если потоки памятью не обмениваются то вообще ничего не надо.
Ну, у ОС память для пулов запрашивать придётся через её API, который сам по себе всегда на блокировке.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, Ikemefula, Вы писали:
I>>>Тоже можно Издержки разные, на порядок по времени например только из за медленной компиляции. N_>>Это решается установкой разработчику нормального компа На современных четырехядерниках даже большие проекты компилятся довольно быстро. I>5 минут — это чудовищно много.
I>Кроме того, для джавы и дотнета очень много самых различных тулов в силу синтаксиса.
Эту старую песню мы уже слышали.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, CreatorCray, Вы писали:
C>>Там их больше будет. Например, для возврата объекта в "родной" пул и т.п. CC>Нет, ибо возвращает их в родные пенаты родной поток. Ну или если родной поток уже помер то вместо добавления в deferred освобождающий поток ограничивается декрементом счётчика выделенных блоков и если достигли нуля — убивает abandoned пул.
Память на висящий пул теряем, кстати.
C>>Получается очень и очень непростой дизайн аллокатора. CC>C'mon! Нет там ничего сверхсложного. Подумать надо, но никаких сверхнапрягов. CC>ThreadPoolAlloc у меня занял когда-то около часу ковыряшек из принципа на спор с кем то из шарпников по поводу скорости их GC.
Это он у тебя ещё маленький.
C>>Так я ведь задизайню тест, где у тебя всё будет сливать моему CC>Если будет эквивалентный код на Java и С++ — можем попробовать, если тебе ещё не надоело. CC>Я ведь тоже могу задизайнить тест, где учту слабые стороны GC.
Давай
C>>Неа. Ты ну никак не можешь сделать многопоточный аллокатор без блокировок (sleeping mutexes) и/или атомарных операций. CC>Мутексы можно выкинуть вообще, а атомарники нужны только в случае если выделенный объект надо убивать в другом потоке. Если потоки памятью не обмениваются то вообще ничего не надо.
Неа. Получается наааамного сложнее. Если ты из другого потока освобождаешь объект, то тебе его надо положить обратно в пул предидущего треда. Начинаются разборки: а как это делать? Тебе надо как-то менять структуры другого потока, причём они при этом могут рейсить с самими операциями потока. Так что надо городить сложный RCU, как минимум.
Либо объекты из других потоков помещать в lookaside-списки, который интегрировать периодически обратно в пул. Но если эти списки растут слишком быстро, то упс.
Ещё можно помещать объект в cleanup-список в текущем потоке (оставляя пометку в заголовке аллокации), откуда его потом читает родительский поток.
Ни один из вариантов не оптимален на 100%. В Hoard'е используется дикая смесь всего этого, но всё равно у них тоже узкие места есть.
Здравствуйте, Cyberax, Вы писали:
C>>>Там их больше будет. Например, для возврата объекта в "родной" пул и т.п. CC>>Нет, ибо возвращает их в родные пенаты родной поток. Ну или если родной поток уже помер то вместо добавления в deferred освобождающий поток ограничивается декрементом счётчика выделенных блоков и если достигли нуля — убивает abandoned пул. C>Память на висящий пул теряем, кстати.
Не теряем, она висит занятая, да. И если очень хочется, то можно сделать так, что первый освобождающий в этом пуле забирает его и объединяет со своим пулом.
Я себе такой задачи на момент написания аллокатора не ставил.
C>>>Получается очень и очень непростой дизайн аллокатора. CC>>C'mon! Нет там ничего сверхсложного. Подумать надо, но никаких сверхнапрягов. CC>>ThreadPoolAlloc у меня занял когда-то около часу ковыряшек из принципа на спор с кем то из шарпников по поводу скорости их GC. C>Это он у тебя ещё маленький.
Зато уже шустрый.
C>>>Так я ведь задизайню тест, где у тебя всё будет сливать моему CC>>Если будет эквивалентный код на Java и С++ — можем попробовать, если тебе ещё не надоело. CC>>Я ведь тоже могу задизайнить тест, где учту слабые стороны GC. C>Давай
Так лениво ж. Я ж не ставил себе задачу обгадить жабный GC. Моя задача была показать что С++ может иметь столь же быстрый аллокатор.
C>>>Неа. Ты ну никак не можешь сделать многопоточный аллокатор без блокировок (sleeping mutexes) и/или атомарных операций. CC>>Мутексы можно выкинуть вообще, а атомарники нужны только в случае если выделенный объект надо убивать в другом потоке. Если потоки памятью не обмениваются то вообще ничего не надо. C>Неа. Получается наааамного сложнее. Если ты из другого потока освобождаешь объект, то тебе его надо положить обратно в пул предидущего треда. Начинаются разборки: а как это делать? Тебе надо как-то менять структуры другого потока, причём они при этом могут рейсить с самими операциями потока. Так что надо городить сложный RCU, как минимум.
Не намного.
C>Либо объекты из других потоков помещать в lookaside-списки, который интегрировать периодически обратно в пул. Но если эти списки растут слишком быстро, то упс. C>Ещё можно помещать объект в cleanup-список в текущем потоке (оставляя пометку в заголовке аллокации), откуда его потом читает родительский поток.
Без всяких пометок, просто добавляем освобождаемый в top ISLL, который находится в контексте родительского потока.
Пока из того пула не делаются аллокации нет никакой разницы в free blocks list эти блоки или же в deferred blocks list. А первая же аллокация, которой понадобятся свободные блоки заберёт deferred список и добавит его содержимое в список свободных блоков.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, CreatorCray, Вы писали:
I>>Кроме того, для джавы и дотнета очень много самых различных тулов в силу синтаксиса. CC>Эту старую песню мы уже слышали.
Про то и речь — никаких изменений в лучшую сторону нет, остаётся надеяться на железо.
Здравствуйте, CreatorCray, Вы писали:
C>>Память на висящий пул теряем, кстати. CC>Не теряем, она висит занятая, да. И если очень хочется, то можно сделать так, что первый освобождающий в этом пуле забирает его и объединяет со своим пулом.
А дальше начнутся проблемы с cache locality
C>>>>Так я ведь задизайню тест, где у тебя всё будет сливать моему CC>>>Если будет эквивалентный код на Java и С++ — можем попробовать, если тебе ещё не надоело. CC>>>Я ведь тоже могу задизайнить тест, где учту слабые стороны GC. C>>Давай CC>Так лениво ж. Я ж не ставил себе задачу обгадить жабный GC. Моя задача была показать что С++ может иметь столь же быстрый аллокатор.
Попробую сделать красивый многопоточный тест, с тестированием локальности, lock elision и прочих вкусностей в Java.
C>>Неа. Получается наааамного сложнее. Если ты из другого потока освобождаешь объект, то тебе его надо положить обратно в пул предидущего треда. Начинаются разборки: а как это делать? Тебе надо как-то менять структуры другого потока, причём они при этом могут рейсить с самими операциями потока. Так что надо городить сложный RCU, как минимум. CC>Не намного.
Ооо....
C>>Либо объекты из других потоков помещать в lookaside-списки, который интегрировать периодически обратно в пул. Но если эти списки растут слишком быстро, то упс. C>>Ещё можно помещать объект в cleanup-список в текущем потоке (оставляя пометку в заголовке аллокации), откуда его потом читает родительский поток. CC>Без всяких пометок, просто добавляем освобождаемый в top ISLL, который находится в контексте родительского потока. CC>Пока из того пула не делаются аллокации нет никакой разницы в free blocks list эти блоки или же в deferred blocks list. А первая же аллокация, которой понадобятся свободные блоки заберёт deferred список и добавит его содержимое в список свободных блоков.
Плохо. Кэш-локальность будет ни к чёрту (в Java она идеальная — выделение из непрерывного блока памяти). Тебе нужно будет объекты раскладывать по bin'ам, кореллирующим с физическим расположением данных.
Я же говорю — много открытий чудных будет. По своему личному опыту говорю
Здравствуйте, Cyberax, Вы писали:
C>>>Память на висящий пул теряем, кстати. CC>>Не теряем, она висит занятая, да. И если очень хочется, то можно сделать так, что первый освобождающий в этом пуле забирает его и объединяет со своим пулом. C>А дальше начнутся проблемы с cache locality
С чего бы вдруг. Кончится место в родных chunks будем выделять в забранных.
Page fault count у ThreadPoolAlloc кстати ниже чем у Java с UseParallelGC (11'532 супротив 64'755)
CC>>Так лениво ж. Я ж не ставил себе задачу обгадить жабный GC. Моя задача была показать что С++ может иметь столь же быстрый аллокатор. C>Попробую сделать красивый многопоточный тест, с тестированием локальности, lock elision и прочих вкусностей в Java.
А потом точно такое же на С++ не забудь. Чтоб можно было сравнить.
У меня есть VTune, который умеет профайлить как Java так и C++. Cache miss показывать умеет.
C>>>Либо объекты из других потоков помещать в lookaside-списки, который интегрировать периодически обратно в пул. Но если эти списки растут слишком быстро, то упс. C>>>Ещё можно помещать объект в cleanup-список в текущем потоке (оставляя пометку в заголовке аллокации), откуда его потом читает родительский поток. CC>>Без всяких пометок, просто добавляем освобождаемый в top ISLL, который находится в контексте родительского потока. CC>>Пока из того пула не делаются аллокации нет никакой разницы в free blocks list эти блоки или же в deferred blocks list. А первая же аллокация, которой понадобятся свободные блоки заберёт deferred список и добавит его содержимое в список свободных блоков. C>Плохо. Кэш-локальность будет ни к чёрту (в Java она идеальная — выделение из непрерывного блока памяти). Тебе нужно будет объекты раскладывать по bin'ам, кореллирующим с физическим расположением данных.
Java выделяет блоки подряд. Поэтому locality там будет только если одновременно с заполнением контейнера не происходит ещё каких либо долговременных аллокаций. Или жабий GC научился определять какие данные следует положить рядом?
Если дозарезу надо обеспечить locality то мне например проще прицепить к контейнеру специализированный аллокатор, который выделит fixed size objects pool и будет им рулить.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, CreatorCray, Вы писали:
C>>А дальше начнутся проблемы с cache locality CC>С чего бы вдруг. Кончится место в родных chunks будем выделять в забранных.
Вот именно из-за этого. Разные потоки изначально будут иметь разные арены (thread-local пулы), и в кэше каждого потока будут лежать данные по большей части именно из локальной арены.
CC>Page fault count у ThreadPoolAlloc кстати ниже чем у Java с UseParallelGC (11'532 супротив 64'755)
Page fault'ы там возникают в треде с GC, когда он ставит ловушки.
CC>>>Так лениво ж. Я ж не ставил себе задачу обгадить жабный GC. Моя задача была показать что С++ может иметь столь же быстрый аллокатор. C>>Попробую сделать красивый многопоточный тест, с тестированием локальности, lock elision и прочих вкусностей в Java. CC>А потом точно такое же на С++ не забудь. Чтоб можно было сравнить.
Это понятно.
CC>У меня есть VTune, который умеет профайлить как Java так и C++. Cache miss показывать умеет.
В Java надо аккуратно только это делать.
C>>Плохо. Кэш-локальность будет ни к чёрту (в Java она идеальная — выделение из непрерывного блока памяти). Тебе нужно будет объекты раскладывать по bin'ам, кореллирующим с физическим расположением данных. CC>Java выделяет блоки подряд. Поэтому locality там будет только если одновременно с заполнением контейнера не происходит ещё каких либо долговременных аллокаций.
И что? Данные в одном потоке всё равно будут обычно лежать близко.
CC>Если дозарезу надо обеспечить locality то мне например проще прицепить к контейнеру специализированный аллокатор, который выделит fixed size objects pool и будет им рулить.
И попадание на синхронизацию.
Здравствуйте, Cyberax, Вы писали:
C>>>А дальше начнутся проблемы с cache locality CC>>С чего бы вдруг. Кончится место в родных chunks будем выделять в забранных. C>Вот именно из-за этого. Разные потоки изначально будут иметь разные арены (thread-local пулы), и в кэше каждого потока будут лежать данные по большей части именно из локальной арены.
1) У потока нет кэша У х86 кэш он или на ядро проца или общий на проц. Потоков же может крутиться сколько угодно.
2) Присоединять чужой пул к своему можно только в случае если поток-владелец другого пула уже помер.
CC>>Page fault count у ThreadPoolAlloc кстати ниже чем у Java с UseParallelGC (11'532 супротив 64'755) C>Page fault'ы там возникают в треде с GC, когда он ставит ловушки.
Ловушки он ставит для COMMIT следующей страницы, когда памяти отъето больше чем закоммичено.
CC>>У меня есть VTune, который умеет профайлить как Java так и C++. Cache miss показывать умеет. C>В Java надо аккуратно только это делать.
Читай: в идеальном environment
C>>>Плохо. Кэш-локальность будет ни к чёрту (в Java она идеальная — выделение из непрерывного блока памяти). Тебе нужно будет объекты раскладывать по bin'ам, кореллирующим с физическим расположением данных. CC>>Java выделяет блоки подряд. Поэтому locality там будет только если одновременно с заполнением контейнера не происходит ещё каких либо долговременных аллокаций. C>И что? Данные в одном потоке всё равно будут обычно лежать близко.
Зависит. Если расстояние больше чем размер одной линии кэша то locality в жопе.
CC>>Если дозарезу надо обеспечить locality то мне например проще прицепить к контейнеру специализированный аллокатор, который выделит fixed size objects pool и будет им рулить. C>И попадание на синхронизацию.
Я так понимаю ты себе совсем не представляешь возможность существования аллокатора без обязательной синхронизации?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока
Здравствуйте, CreatorCray, Вы писали:
C>>Вот именно из-за этого. Разные потоки изначально будут иметь разные арены (thread-local пулы), и в кэше каждого потока будут лежать данные по большей части именно из локальной арены. CC>1) У потока нет кэша У х86 кэш он или на ядро проца или общий на проц. Потоков же может крутиться сколько угодно.
Есть Общий кэш процессора.
CC>2) Присоединять чужой пул к своему можно только в случае если поток-владелец другого пула уже помер.
А освобождённые объекты куда попадут?
CC>>>Page fault count у ThreadPoolAlloc кстати ниже чем у Java с UseParallelGC (11'532 супротив 64'755) C>>Page fault'ы там возникают в треде с GC, когда он ставит ловушки. CC>Ловушки он ставит для COMMIT следующей страницы, когда памяти отъето больше чем закоммичено.
Не совсем. Он их использует для того, чтобы глушить потоки.
CC>>>У меня есть VTune, который умеет профайлить как Java так и C++. Cache miss показывать умеет. C>>В Java надо аккуратно только это делать. CC>Читай: в идеальном environment
Нет, просто много шума.
C>>И что? Данные в одном потоке всё равно будут обычно лежать близко. CC>Зависит. Если расстояние больше чем размер одной линии кэша то locality в жопе.
Ну так всё равно вероятность попадание в одну линию намного больше.
CC>>>Если дозарезу надо обеспечить locality то мне например проще прицепить к контейнеру специализированный аллокатор, который выделит fixed size objects pool и будет им рулить. C>>И попадание на синхронизацию. CC>Я так понимаю ты себе совсем не представляешь возможность существования аллокатора без обязательной синхронизации?
Неа. Под синхронизацией понимаются interlocked-операци и/или мьтексы/события/семафоры.
Здравствуйте, Cyberax, Вы писали:
C>Здравствуйте, CreatorCray, Вы писали:
C>>>Вот именно из-за этого. Разные потоки изначально будут иметь разные арены (thread-local пулы), и в кэше каждого потока будут лежать данные по большей части именно из локальной арены. CC>>1) У потока нет кэша У х86 кэш он или на ядро проца или общий на проц. Потоков же может крутиться сколько угодно. C>Есть Общий кэш процессора.
Он никак не связан с потоками ОС.
CC>>2) Присоединять чужой пул к своему можно только в случае если поток-владелец другого пула уже помер. C>А освобождённые объекты куда попадут?
Что значит освобождённые объекты. На уровне аллокатора нет объектов, есть блоки памяти.
Свободные блоки из присоединяемого пула сидят в списке свободных для этого пула. При объединении их следует присоединить в конец списка свободных блоков основного пула.
CC>>>>Page fault count у ThreadPoolAlloc кстати ниже чем у Java с UseParallelGC (11'532 супротив 64'755) C>>>Page fault'ы там возникают в треде с GC, когда он ставит ловушки. CC>>Ловушки он ставит для COMMIT следующей страницы, когда памяти отъето больше чем закоммичено. C>Не совсем. Он их использует для того, чтобы глушить потоки.
Глушить в смысле останавливать? Неужто все остальные способы не подходят? Этож managed код всё таки.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Забанили по IP, значит пора закрыть эту страницу.
Всем пока