Принудительное вÑтраивание методов в Burst
(Russian translation from English by Maxim Voloshin)
Burst 1.0.1 по-Ñути ÑвлÑетÑÑ Ð¿Ð°Ñ‚Ñ‡ÐµÐ¼ к верÑии 1.0.0, но на удивление он добавлÑет новую полезную функцию: теперь мы можем вÑтраивать(inline) методы принудительно. Читайте чтобы узнать как!
Ð”Ð»Ñ Ð½Ð°Ñ‡Ð°Ð»Ð°, Ñоздадим задачу Burst-компилÑтора, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ñодержит здоровенный метод:
[BurstCompile] struct BigMethodJob : IJob { [ReadOnly] public int Val1; [ReadOnly] public int Val2; [WriteOnly] public NativeArray<float> Result; public void Execute() { float f = PointlessAddition(Val1); f += PointlessAddition(Val2); Result[0] = f; } float PointlessAddition(int val) { float f = 0; f += val+1; f += val+2; f += val+3; f += val+4; f += val+5; f += val+6; f += val+7; f += val+8; f += val+9; f += val+10; f += val+11; f += val+12; f += val+13; f += val+14; f += val+15; f += val+16; f += val+17; f += val+18; f += val+19; f += val+20; f += val+21; f += val+22; f += val+23; f += val+24; f += val+25; f += val+26; f += val+27; f += val+28; f += val+29; f += val+30; f += val+31; f += val+32; f += val+33; f += val+34; f += val+35; f += val+36; f += val+37; f += val+38; f += val+39; f += val+40; return f; } }
Задача абÑолютно беÑÑмыÑленна, но Ñодержит доÑтаточно кода чтобы Burst не вÑтраивал тело PointlessAddition
вмеÑто двух вызовов, раÑположенных в Execute
. УбедитьÑÑ Ð² Ñтом можно поÑмотрев в Burst инÑпектор:
; Execute push r14 push rbx push rax mov rbx, rdi mov edi, dword ptr [rbx] movabs r14, offset ".LBigMethodJob.PointlessAddition(BigMethodJob* this, int val)_4CCC87A9ADCAE58C" call r14 movss dword ptr [rsp + 4], xmm0 mov edi, dword ptr [rbx + 4] call r14 addss xmm0, dword ptr [rsp + 4] mov rax, qword ptr [rbx + 8] movss dword ptr [rax], xmm0 add rsp, 8 pop rbx pop r14 ret ; PointlessAddition movd xmm0, edi pshufd xmm0, xmm0, 0 movabs rax, offset .LCPI1_0 movdqa xmm8, xmmword ptr [rax] paddd xmm8, xmm0 movabs rax, offset .LCPI1_1 movdqa xmm2, xmmword ptr [rax] paddd xmm2, xmm0 movabs rax, offset .LCPI1_2 movdqa xmm3, xmmword ptr [rax] paddd xmm3, xmm0 movabs rax, offset .LCPI1_3 movdqa xmm4, xmmword ptr [rax] paddd xmm4, xmm0 movabs rax, offset .LCPI1_4 movdqa xmm5, xmmword ptr [rax] paddd xmm5, xmm0 movabs rax, offset .LCPI1_5 movdqa xmm6, xmmword ptr [rax] paddd xmm6, xmm0 movabs rax, offset .LCPI1_6 movdqa xmm7, xmmword ptr [rax] paddd xmm7, xmm0 movabs rax, offset .LCPI1_7 movdqa xmm1, xmmword ptr [rax] paddd xmm1, xmm0 cvtdq2ps xmm1, xmm1 cvtdq2ps xmm7, xmm7 cvtdq2ps xmm6, xmm6 cvtdq2ps xmm5, xmm5 addps xmm5, xmm6 addps xmm5, xmm1 addps xmm5, xmm7 cvtdq2ps xmm1, xmm4 cvtdq2ps xmm3, xmm3 cvtdq2ps xmm2, xmm2 cvtdq2ps xmm4, xmm8 addps xmm4, xmm2 addps xmm4, xmm1 addps xmm4, xmm5 addps xmm4, xmm3 movabs rax, offset .LCPI1_8 movdqa xmm1, xmmword ptr [rax] paddd xmm1, xmm0 movabs rax, offset .LCPI1_9 paddd xmm0, xmmword ptr [rax] cvtdq2ps xmm0, xmm0 cvtdq2ps xmm1, xmm1 addps xmm1, xmm0 movaps xmm2, xmm4 movhlps xmm2, xmm2 addps xmm2, xmm4 haddps xmm2, xmm2 movaps xmm0, xmm1 movhlps xmm0, xmm0 addps xmm0, xmm1 haddps xmm0, xmm0 addss xmm0, xmm2 ret
СмыÑл большей чаÑти Ñтого кода, на Ñамом деле, не важен. Ð’Ð°Ð¶Ð½Ð°Ñ Ñ‡Ð°ÑÑ‚ÑŒ находитÑÑ Ð½Ð° Ñамом верху в Execute
, где мы видим две инÑтрукции call
. Они дважды вызывают метод PointlessAddition
. Далее мы видим оÑтальные инÑтрукции, ÑвлÑющиеÑÑ Ñодержанием PointlessAddition
. Ðто показывает, что компилÑтор вызывает метод, вмеÑто того чтобы помеÑтить его инÑтрукции в Execute
напрÑмую.
Теперь попробуем новую оÑобенноÑÑ‚ÑŒ Burst 1.0.1 и включим вÑтраивание метода Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ [MethodImpl]
:
[MethodImpl(MethodImplOptions.AggressiveInlining)] float PointlessAddition(int val)
Теперь, еÑли поÑмотреть в Burst инÑпектор мы не увидим никаких call
, зато инÑтрукций Ñтало намного больше:
mov ecx, dword ptr [rdi] mov eax, dword ptr [rdi + 4] lea edx, [rcx + 1] cvtsi2ss xmm0, edx lea edx, [rcx + 2] cvtsi2ss xmm1, edx lea edx, [rcx + 3] cvtsi2ss xmm2, edx addss xmm2, xmm1 lea edx, [rcx + 4] xorps xmm1, xmm1 cvtsi2ss xmm1, edx addss xmm1, xmm2 lea edx, [rcx + 5] xorps xmm2, xmm2 cvtsi2ss xmm2, edx addss xmm2, xmm1 lea edx, [rcx + 6] xorps xmm1, xmm1 cvtsi2ss xmm1, edx addss xmm1, xmm2 lea edx, [rcx + 7] xorps xmm2, xmm2 cvtsi2ss xmm2, edx addss xmm2, xmm1 lea edx, [rcx + 8] xorps xmm1, xmm1 cvtsi2ss xmm1, edx addss xmm1, xmm2 lea edx, [rcx + 9] xorps xmm2, xmm2 cvtsi2ss xmm2, edx addss xmm2, xmm1 lea edx, [rcx + 10] xorps xmm1, xmm1 cvtsi2ss xmm1, edx addss xmm1, xmm2 lea edx, [rcx + 11] xorps xmm2, xmm2 cvtsi2ss xmm2, edx addss xmm2, xmm1 lea edx, [rcx + 12] xorps xmm1, xmm1 cvtsi2ss xmm1, edx addss xmm1, xmm2 lea edx, [rcx + 13] xorps xmm2, xmm2 cvtsi2ss xmm2, edx addss xmm2, xmm1 lea edx, [rcx + 14] xorps xmm1, xmm1 cvtsi2ss xmm1, edx addss xmm1, xmm2 lea edx, [rcx + 15] xorps xmm2, xmm2 cvtsi2ss xmm2, edx addss xmm2, xmm1 lea edx, [rcx + 16] xorps xmm1, xmm1 cvtsi2ss xmm1, edx addss xmm1, xmm2 lea edx, [rcx + 17] xorps xmm2, xmm2 cvtsi2ss xmm2, edx addss xmm2, xmm1 lea edx, [rcx + 18] xorps xmm1, xmm1 cvtsi2ss xmm1, edx addss xmm1, xmm2 lea edx, [rcx + 19] xorps xmm2, xmm2 cvtsi2ss xmm2, edx addss xmm2, xmm1 lea edx, [rcx + 20] xorps xmm1, xmm1 cvtsi2ss xmm1, edx addss xmm1, xmm2 lea edx, [rcx + 21] xorps xmm2, xmm2 cvtsi2ss xmm2, edx addss xmm2, xmm1 lea edx, [rcx + 22] xorps xmm1, xmm1 cvtsi2ss xmm1, edx addss xmm1, xmm2 lea edx, [rcx + 23] xorps xmm2, xmm2 cvtsi2ss xmm2, edx addss xmm2, xmm1 lea edx, [rcx + 24] xorps xmm1, xmm1 cvtsi2ss xmm1, edx addss xmm1, xmm2 lea edx, [rcx + 25] xorps xmm2, xmm2 cvtsi2ss xmm2, edx addss xmm2, xmm1 lea edx, [rcx + 26] xorps xmm1, xmm1 cvtsi2ss xmm1, edx addss xmm1, xmm2 lea edx, [rcx + 27] xorps xmm2, xmm2 cvtsi2ss xmm2, edx addss xmm2, xmm1 lea edx, [rcx + 28] xorps xmm1, xmm1 cvtsi2ss xmm1, edx addss xmm1, xmm2 lea edx, [rcx + 29] xorps xmm2, xmm2 cvtsi2ss xmm2, edx addss xmm2, xmm1 lea edx, [rcx + 30] xorps xmm1, xmm1 cvtsi2ss xmm1, edx addss xmm1, xmm2 lea edx, [rcx + 31] xorps xmm2, xmm2 cvtsi2ss xmm2, edx addss xmm2, xmm1 lea edx, [rcx + 32] xorps xmm1, xmm1 cvtsi2ss xmm1, edx addss xmm1, xmm2 lea edx, [rcx + 33] xorps xmm2, xmm2 cvtsi2ss xmm2, edx addss xmm2, xmm1 lea edx, [rcx + 34] xorps xmm1, xmm1 cvtsi2ss xmm1, edx addss xmm1, xmm2 lea edx, [rcx + 35] xorps xmm2, xmm2 cvtsi2ss xmm2, edx addss xmm2, xmm1 lea edx, [rcx + 36] xorps xmm1, xmm1 cvtsi2ss xmm1, edx addss xmm1, xmm2 lea edx, [rcx + 37] xorps xmm2, xmm2 cvtsi2ss xmm2, edx addss xmm2, xmm1 lea edx, [rcx + 38] xorps xmm1, xmm1 cvtsi2ss xmm1, edx addss xmm1, xmm2 lea edx, [rcx + 39] xorps xmm2, xmm2 cvtsi2ss xmm2, edx addss xmm2, xmm1 add ecx, 40 xorps xmm1, xmm1 cvtsi2ss xmm1, ecx addss xmm1, xmm2 lea ecx, [rax + 1] xorps xmm2, xmm2 cvtsi2ss xmm2, ecx lea ecx, [rax + 2] cvtsi2ss xmm3, ecx addss xmm3, xmm1 addss xmm3, xmm2 lea ecx, [rax + 3] xorps xmm1, xmm1 cvtsi2ss xmm1, ecx addss xmm1, xmm3 lea ecx, [rax + 4] xorps xmm2, xmm2 cvtsi2ss xmm2, ecx addss xmm2, xmm1 lea ecx, [rax + 5] xorps xmm1, xmm1 cvtsi2ss xmm1, ecx addss xmm1, xmm2 lea ecx, [rax + 6] xorps xmm2, xmm2 cvtsi2ss xmm2, ecx addss xmm2, xmm1 lea ecx, [rax + 7] xorps xmm1, xmm1 cvtsi2ss xmm1, ecx addss xmm1, xmm2 lea ecx, [rax + 8] xorps xmm2, xmm2 cvtsi2ss xmm2, ecx addss xmm2, xmm1 lea ecx, [rax + 9] xorps xmm1, xmm1 cvtsi2ss xmm1, ecx addss xmm1, xmm2 lea ecx, [rax + 10] xorps xmm2, xmm2 cvtsi2ss xmm2, ecx addss xmm2, xmm1 lea ecx, [rax + 11] xorps xmm1, xmm1 cvtsi2ss xmm1, ecx addss xmm1, xmm2 lea ecx, [rax + 12] xorps xmm2, xmm2 cvtsi2ss xmm2, ecx addss xmm2, xmm1 lea ecx, [rax + 13] xorps xmm1, xmm1 cvtsi2ss xmm1, ecx addss xmm1, xmm2 lea ecx, [rax + 14] xorps xmm2, xmm2 cvtsi2ss xmm2, ecx addss xmm2, xmm1 lea ecx, [rax + 15] xorps xmm1, xmm1 cvtsi2ss xmm1, ecx addss xmm1, xmm2 lea ecx, [rax + 16] xorps xmm2, xmm2 cvtsi2ss xmm2, ecx addss xmm2, xmm1 lea ecx, [rax + 17] xorps xmm1, xmm1 cvtsi2ss xmm1, ecx addss xmm1, xmm2 lea ecx, [rax + 18] xorps xmm2, xmm2 cvtsi2ss xmm2, ecx addss xmm2, xmm1 lea ecx, [rax + 19] xorps xmm1, xmm1 cvtsi2ss xmm1, ecx addss xmm1, xmm2 lea ecx, [rax + 20] xorps xmm2, xmm2 cvtsi2ss xmm2, ecx addss xmm2, xmm1 lea ecx, [rax + 21] xorps xmm1, xmm1 cvtsi2ss xmm1, ecx addss xmm1, xmm2 lea ecx, [rax + 22] xorps xmm2, xmm2 cvtsi2ss xmm2, ecx addss xmm2, xmm1 lea ecx, [rax + 23] xorps xmm1, xmm1 cvtsi2ss xmm1, ecx addss xmm1, xmm2 lea ecx, [rax + 24] xorps xmm2, xmm2 cvtsi2ss xmm2, ecx addss xmm2, xmm1 lea ecx, [rax + 25] xorps xmm1, xmm1 cvtsi2ss xmm1, ecx addss xmm1, xmm2 lea ecx, [rax + 26] xorps xmm2, xmm2 cvtsi2ss xmm2, ecx addss xmm2, xmm1 lea ecx, [rax + 27] xorps xmm1, xmm1 cvtsi2ss xmm1, ecx addss xmm1, xmm2 lea ecx, [rax + 28] xorps xmm2, xmm2 cvtsi2ss xmm2, ecx addss xmm2, xmm1 lea ecx, [rax + 29] xorps xmm1, xmm1 cvtsi2ss xmm1, ecx addss xmm1, xmm2 lea ecx, [rax + 30] xorps xmm2, xmm2 cvtsi2ss xmm2, ecx addss xmm2, xmm1 lea ecx, [rax + 31] xorps xmm1, xmm1 cvtsi2ss xmm1, ecx addss xmm1, xmm2 lea ecx, [rax + 32] xorps xmm2, xmm2 cvtsi2ss xmm2, ecx addss xmm2, xmm1 lea ecx, [rax + 33] xorps xmm1, xmm1 cvtsi2ss xmm1, ecx addss xmm1, xmm2 lea ecx, [rax + 34] xorps xmm2, xmm2 cvtsi2ss xmm2, ecx addss xmm2, xmm1 lea ecx, [rax + 35] xorps xmm1, xmm1 cvtsi2ss xmm1, ecx addss xmm1, xmm2 lea ecx, [rax + 36] xorps xmm2, xmm2 cvtsi2ss xmm2, ecx addss xmm2, xmm1 lea ecx, [rax + 37] xorps xmm1, xmm1 cvtsi2ss xmm1, ecx addss xmm1, xmm2 lea ecx, [rax + 38] xorps xmm2, xmm2 cvtsi2ss xmm2, ecx addss xmm2, xmm1 lea ecx, [rax + 39] xorps xmm1, xmm1 cvtsi2ss xmm1, ecx addss xmm1, xmm2 add eax, 40 xorps xmm2, xmm2 cvtsi2ss xmm2, eax addss xmm2, xmm1 addss xmm2, xmm0 mov rax, qword ptr [rdi + 8] movss dword ptr [rax], xmm2 ret
Таким образом мы легко удалили вызовы и продублировали тело функции в Execute
.
Теперь мы видим, что вÑтраивание методов работает, но оÑталоÑÑŒ понÑÑ‚ÑŒ когда мы должны иÑпользовать Ñто и при каких обÑтоÑтельÑтвах. Забавно, что мне надо было добавить кучу кода в метод чтобы Burst не вÑтраивал его автоматичеÑки. Ðто означает, что методы уже агреÑÑивно вÑтраиваютÑÑ, даже без атрибута. ПолучаетÑÑ, что [MethodImpl]
должен быть там, где Burst не вÑтраивает методы Ñам, но метод обÑзательно должен быть вÑтроен. Большие методы, в общем Ñлучае, не должны вÑтраиватьÑÑ, потому что затраты на его вызов отноÑительно низки в Ñравнение Ñ Ð·Ð°Ñ‚Ñ€Ð°Ñ‚Ð°Ð¼Ð¸ на его выполнение. ОтÑюда Ñледует правило – иÑпользуйте ручное вÑтраивание без фанатизма.