[Ann] Net Allocation internals
От: Sinix  
Дата: 01.10.14 13:36
Оценка: 72 (10)
На codeproject появилась небольшая статья от Ben Watson (это который Writing High-Performance .NET Code).

Из интересного:
* Аллокация объектов: в лучшем случае new() вместе с выделением памяти укладывается в 9 asm-инструкций
* Минимальный размер объекта — 12 байт (для x86). Как бы известный факт, но в куче блогов почему-то пишут только про 8 байт заголовка.
* Создание объекта с финалайзером заметно дороже. Тоже известно, но напомнить не помешает.

Кое-что было у других авторов и у самого Ben Watson в его блоге, но в виде одной короткой статьи не попадалось. По уровню напоминает классику типа %subj% UNDOCUMENTED от Wesner Moise или .NET Type Internals от Adityanand.
Re: [Ann] Net Allocation internals
От: Evgeny.Panasyuk Россия  
Дата: 02.10.14 17:00
Оценка:
Здравствуйте, Sinix, Вы писали:

S>* Аллокация объектов: в лучшем случае new() вместе с выделением памяти укладывается в 9 asm-инструкций


Непонятно с чем связанно удивление — это много или мало?
У Compacting GC выделение памяти на Happy-Path это, фактически, просто увеличение указателя на требуемый размер
Re[2]: [Ann] Net Allocation internals
От: Sinix  
Дата: 03.10.14 05:10
Оценка: +1
Здравствуйте, Evgeny.Panasyuk, Вы писали:

S>>* Аллокация объектов: в лучшем случае new() вместе с выделением памяти укладывается в 9 asm-инструкций

EP>Непонятно с чем связанно удивление — это много или мало?
Скорее, "если сильно постараться, то можно впихнуть, но всё равно круто"

EP>У Compacting GC выделение памяти на Happy-Path это, фактически, просто увеличение указателя на требуемый размер

Угу. Только
1. Надо ещё загрести размер типа (несложно, сборка гарантированно загружена в момент jit-компиляции).
2. Выбрать текущий буфер для аллокации (тут есть нюансы).
3. Заполнить заголовок объекта (снова несложно).

Cам код принципиально прост. Все "динамические" значения достаются по захардкоженным адресам. Нет никаких проверок на потокобезопасность, т.к. каждый поток работает со своей областью в gen0.
Но объём архитектурных решений, необходимых чтобы это "да там всё просто" работало, внушает уважение
Re[3]: [Ann] Net Allocation internals
От: Evgeny.Panasyuk Россия  
Дата: 03.10.14 13:17
Оценка:
Здравствуйте, Sinix, Вы писали:

S>1. Надо ещё загрести размер типа (несложно, сборка гарантированно загружена в момент jit-компиляции).


А разве размер типа не известен во время компиляции? Или хотя бы во время JIT? Там по хорошему не должно быть хождения в память за размером типа.
Или размер типа может поменяться во время работы программы?

S>2. Выбрать текущий буфер для аллокации (тут есть нюансы).


Всего лишь обращение к TLS — mov edx, dword ptr fs:[0E30h], то есть tls.current_allocator.

S>Cам код принципиально прост. Все "динамические" значения достаются по захардкоженным адресам. Нет никаких проверок на потокобезопасность, т.к. каждый поток работает со своей областью в gen0.

S>Но объём архитектурных решений, необходимых чтобы это "да там всё просто" работало, внушает уважение

Нужен всего лишь precise garbage collection, и только — всё остальное вытекает из этого. Нет там "объёма архитектурных решений".
Re[4]: [Ann] Net Allocation internals
От: Sinix  
Дата: 03.10.14 13:58
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

S>>1. Надо ещё загрести размер типа (несложно, сборка гарантированно загружена в момент jit-компиляции).

EP>А разве размер типа не известен во время компиляции?
Нет, в следующей версии сборки в класс может добавиться/удалиться поле.

EP>Или хотя бы во время JIT? Там по хорошему не должно быть хождения в память за размером типа.

Угу, в этот момент и хардкодится. Писал выше: "несложно, сборка гарантированно загружена в момент jit-компиляции".


EP>Или размер типа может поменяться во время работы программы?

Если забыть про строки, массивы и объекты DLR — не может. По крайней мере, в текущей версии CLR точно. И в будущих — очень сомневаюсь, что появится.

S>>2. Выбрать текущий буфер для аллокации (тут есть нюансы).

EP>Всего лишь обращение к TLS — mov edx, dword ptr fs:[0E30h], то есть tls.current_allocator.
Угу.

EP>Нужен всего лишь precise garbage collection, и только — всё остальное вытекает из этого. Нет там "объёма архитектурных решений".

Это до момента, когда идею из академической статьи надо превратить в стандарт, который проживёт без особых изменений 15 лет. Вот это и внушает.
Re[5]: [Ann] Net Allocation internals
От: Evgeny.Panasyuk Россия  
Дата: 03.10.14 15:20
Оценка: 14 (1) +1
Здравствуйте, Sinix, Вы писали:

EP>>Или размер типа может поменяться во время работы программы?

S>Если забыть про строки, массивы и объекты DLR — не может. По крайней мере, в текущей версии CLR точно. И в будущих — очень сомневаюсь, что появится.

То есть размер типа можно передавать напрямую в new, без лишних обращений к памяти. Если же всё заинлайнить, то получается (C++ с подобным аллокатором):
    // get top of free space from TLS allocator
    mov    rbx, QWORD PTR fs:free_space_top@tpoff

    // increase by sizeof(Abstract)=8
    lea    rax, [rbx+8] 

    // check for bounds
    cmp    rax, QWORD PTR fs:total@tpoff
    jae    .SLOW_PATH
.L9:

    // update top
    mov    QWORD PTR fs:free_space_top@tpoff, rax

    // put virtual table pointer
    mov    QWORD PTR [rbx], OFFSET FLAT:_ZTV8Abstract+16
    // result pointer is in rbx

6 инструкций vs 9+3, но это мелочь по сравнению с тем, что тут ещё и на одно обращение к памяти меньше.
Re: [Ann] Net Allocation internals
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 09.10.14 09:43
Оценка: +1 -1
Здравствуйте, Sinix, Вы писали:

S>На codeproject появилась небольшая статья от Ben Watson (это который Writing High-Performance .NET Code).


S>Из интересного:

S>* Аллокация объектов: в лучшем случае new() вместе с выделением памяти укладывается в 9 asm-инструкций

Выделение принципиально неправильно рассматривать отдельно от издержек на использование и в частности на освобождение. Скажем, после аллокации всегда есть использование. В зависимости от того, кто будет ссылаться на новый объект, издержки на ту же аллокацию резко меняются. Если добавить минимальную инициализацию, то получается что даже эти 9 инструкций роли не играют. Получить профит можно, но массовой пользы такие знания не несут.

S>* Минимальный размер объекта — 12 байт (для x86). Как бы известный факт, но в куче блогов почему-то пишут только про 8 байт заголовка.


Пишут в основном про оверхед, а не про минимальный размер объекта. Просто никому не приходило в голову замерять размер пустого объекта. Случай вобщем вырожденый.
Re[3]: [Ann] Net Allocation internals
От: BulatZiganshin  
Дата: 12.10.14 18:54
Оценка: 14 (1)
Здравствуйте, Sinix, Вы писали:

S>Но объём архитектурных решений, необходимых чтобы это "да там всё просто" работало, внушает уважение


да это старндартное решение. в хаскеле сделано точно так же
Люди, я люблю вас! Будьте бдительны!!!
Re[2]: [Ann] Net Allocation internals
От: Философ Ад http://vk.com/id10256428
Дата: 13.10.14 08:30
Оценка:
Здравствуйте, Ikemefula, Вы писали:

S>>* Минимальный размер объекта — 12 байт (для x86). Как бы известный факт, но в куче блогов почему-то пишут только про 8 байт заголовка.


I>Пишут в основном про оверхед, а не про минимальный размер объекта. Просто никому не приходило в голову замерять размер пустого объекта. Случай вобщем вырожденый.


boxing же, блин
Всё сказанное выше — личное мнение, если не указано обратное.
Re[4]: [Ann] Net Allocation internals
От: Sinix  
Дата: 13.10.14 09:37
Оценка: 18 (1)
Здравствуйте, BulatZiganshin, Вы писали:

S>>Но объём архитектурных решений, необходимых чтобы это "да там всё просто" работало, внушает уважение

BZ>да это старндартное решение. в хаскеле сделано точно так же



Когда я копался в GHC мне так не показалось, но копался очень поверхностно, могу и ошибаться. Емнип, там свои особенности и для CLR они ооочень слабо подходят. Сам allocate явно на 9 инструкций не тянет. Аллокация блоков тоже своеобразная, гранулярность внутри mblock по умолчанию — блоками по 4кб (см allocBlock). Если не вру (вот тут совсем не уверен) для старших поколений и LOB аллокации ещё и обёрнуты в локи ACQUIRE_SM_LOCK. Сравниваем с gc segments по 64кб в CLR

Disclaimer: я ни в коем случае не собираюсь оценивать GHC с точки зрения потребностей хаскеля, речь именно про "стандартное решение, всё как в CLR".

Из того, что ещё сходу вспомнил: т.к. структуры в основном immutable, обратных ссылок между поколениями практически нет, для редких исключений можно вообще не напрягаться. Для дотнета решение с линейно падающей производительностью не пройдёт, приходится извращаться. Вот описание (см "Making Generations Work with Write Barriers"), вот подробности текущей реализации.
Re[3]: [Ann] Net Allocation internals
От: Sinix  
Дата: 13.10.14 09:47
Оценка:
Здравствуйте, Философ, Вы писали:

Ф>boxing же, блин

Тут ни при чём.

Речь про
class A {}

class B { int x; }

class C { int x; int y; }
// ...
var a = new A(); // takes 12 (24) bytes.
var b = new B(); // takes 12 (24) bytes.
var c = new C(); // takes 16 (24) bytes.

Подробности:
http://geekswithblogs.net/akraus1/archive/2012/07/25/150301.aspx
http://www.codeproject.com/Articles/812678/Performance-Considerations-of-Class-Design-and-Gen
Re[3]: [Ann] Net Allocation internals
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 13.10.14 12:26
Оценка:
Здравствуйте, Философ, Вы писали:

S>>>* Минимальный размер объекта — 12 байт (для x86). Как бы известный факт, но в куче блогов почему-то пишут только про 8 байт заголовка.


I>>Пишут в основном про оверхед, а не про минимальный размер объекта. Просто никому не приходило в голову замерять размер пустого объекта. Случай вобщем вырожденый.


Ф>boxing же, блин


Боксинг здесь ни при чем.
Re[5]: [Ann] Net Allocation internals
От: BulatZiganshin  
Дата: 14.10.14 16:44
Оценка: 28 (1) +1
Здравствуйте, Sinix, Вы писали:

S>Сам allocate явно на 9 инструкций не тянет.


почему не тянет? я там насчитал 9 мопов (12 инструкций) в основном пути. разумеется при условии что этот код будут инлайнить как в CLR. из них 2 мопа (3 инструкции) можно безболезненно выкинуть, храня

bd->end = bd->start + min(BLOCK_SIZE_W, LARGE_OBJECT_THRESHOLD)
Люди, я люблю вас! Будьте бдительны!!!
Re[6]: [Ann] Net Allocation internals
От: Sinix  
Дата: 14.10.14 17:19
Оценка:
Здравствуйте, BulatZiganshin, Вы писали:

BZ>почему не тянет? я там насчитал 9 мопов (12 инструкций) в основном пути. разумеется при условии что этот код будут инлайнить как в CLR.


Угу, перечитал код внимательней — всё ок там, с "на 9 не тянет" я явно поторопился
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.