Процедура asm fpu intersectRaySphere x86 - как оптимизировать

Здравствуйте, у меня есть процедура c:

    inline float intersectRaySphere(float3* rayO, float3* rayV, float3* sO, float sR)
    {
    static float3 Q;

    Q = sub(sO,rayO);

    float cc = dot(&Q,&Q);
    float v = dot(&Q,rayV);
    float d = sR*sR - (cc - v*v);

    // If there was no intersection, return -1
    if (d < 0.0) return (-1.0f);
    // Return the distance to the [first] intersecting point
    return (v - sqrt(d));
    }

Я пытался переписать его на x86 fpu asm и создать такой

    _asm_intersectRaySphere:; Function begin
    push    ebp                                     ; 0000 _ 55
    mov     ebp, esp                                ; 0001 _ 89. E5
    add     esp, -20                                ; 0003 _ 83. C4, EC
    mov     eax, dword [ebp+8H]                     ; 0006 _ 8B. 45, 08
    mov     ecx, dword [ebp+0CH]                    ; 0009 _ 8B. 4D, 0C
    mov     edx, dword [ebp+10H]                    ; 000C _ 8B. 55, 10
    fld     dword [edx]                             ; 000F _ D9. 02
    fsub    dword [eax]                             ; 0011 _ D8. 20
    fld     dword [edx+4H]                          ; 0013 _ D9. 42, 04
    fsub    dword [eax+4H]                          ; 0016 _ D8. 60, 04
    fld     dword [edx+8H]                          ; 0019 _ D9. 42, 08
    fsub    dword [eax+8H]                          ; 001C _ D8. 60, 08
    fld     st2                                     ; 001F _ D9. C2
    fmul    st0, st(0)                              ; 0021 _ DC. C8
    fld     st2                                     ; 0023 _ D9. C2
    fmul    st0, st(0)                              ; 0025 _ DC. C8
    fld     st2                                     ; 0027 _ D9. C2
    fmul    st0, st(0)                              ; 0029 _ DC. C8
    faddp   st1, st(0)                              ; 002B _ DE. C1
    faddp   st1, st(0)                              ; 002D _ DE. C1
    fld     dword [ecx]                             ; 002F _ D9. 01
    fmul    st(0), st4                              ; 0031 _ D8. CC
    fld     dword [ecx+4H]                          ; 0033 _ D9. 41, 04
    fmul    st(0), st4                              ; 0036 _ D8. CC
    fld     dword [ecx+8H]                          ; 0038 _ D9. 41, 08
    fmul    st(0), st4                              ; 003B _ D8. CC
    faddp   st1, st(0)                              ; 003D _ DE. C1
    faddp   st1, st(0)                              ; 003F _ DE. C1
    fst     dword [ebp-4H]                          ; 0041 _ D9. 55, FC
    fmul    st0, st(0)                              ; 0044 _ DC. C8
    fld     dword [ebp+14H]                         ; 0046 _ D9. 45, 14
    fmul    st0, st(0)                              ; 0049 _ DC. C8
    faddp   st1, st(0)                              ; 004B _ DE. C1
    fsubrp  st1, st(0)                              ; 004D _ DE. E1
    fxch    st3                                     ; 004F _ D9. CB
    fstp    st0                                     ; 0051 _ DD. D8
    fstp    st0                                     ; 0053 _ DD. D8
    fstp    st0                                     ; 0055 _ DD. D8
    ftst                                            ; 0057 _ D9. E4
    fwait                                           ; 0059 _ 9B
    fnstsw  ax                                      ; 005A _ DF. E0
    fwait                                           ; 005C _ 9B
    sahf                                            ; 005D _ 9E
    jc      ?_001                                   ; 005E _ 72, 07
    fsqrt                                           ; 0060 _ D9. FA
    fsubr   dword [ebp-4H]                          ; 0062 _ D8. 6D, FC
    jmp     ?_002                                   ; 0065 _ EB, 06

     ?_001:  
    fstp    st0                                     ; 0067 _ DD. D8
    fld1                                            ; 0069 _ D9. E8
    fchs                                            ; 006B _ D9. E0
     ?_002:  
    mov     esp, ebp                                ; 006D _ 89. EC
    pop     ebp                                     ; 006F _ 5D
    ret                                             ; 0070 _ C3
    ; _asm_intersectRaySphere End of function

проверено, и он работает нормально, процедура c занимает около 150 циклов (на моем 6 или 7-летнем Pentium 4), моя процедура asm занимает около 66 циклов (*) - так что это хорошее улучшение, но, возможно, оно также может быть еще немного поправилась?

спасибо

(*) я тестировал без особой осторожности на случайных входных данных, поэтому, возможно, это была причина «не пересечения» - без участия sqrt


person grunge fightr    schedule 20.08.2012    source источник


Ответы (1)


Я бы заменил это:

fstp st0
fstp st0
fstp st0
ftst
fwait
fnstsw  ax
fwait
sahf
jc ?__001

Этим:

fcompp
fstp st0
fldz
fcomip st0, st1
ja ?__001

fnstsw не быстрый, и sahf тоже не очень, особенно на P4. Если вы не можете использовать fcomi (т. е. если он должен работать на P1 или PMMX), вы все равно можете пропустить sahf, протестировав немного непосредственно в ax.

person harold    schedule 20.08.2012
comment
кажется, небольшое улучшение примерно на 1-2 циклах, иногда трудно сказать, потому что у меня был какой-то другой результат в разных прогонах, иногда 68, например, иногда 65 - то же самое было с «классической» нормализацией на fpu - иногда 90 иногда 80 :/ (например, моя первоначальная версия с хранилищем fld xyz fld xyz была 90, улучшенная с одним fld xyz и хранением в стеке также было 90, но когда я измерил начальное значение, оно стало 80 - несколько странно) - person grunge fightr; 20.08.2012
comment
@grungefightr хорошо, это, конечно, мало поможет, но я ожидал немного большего (может быть, от 4 до 6 циклов). - person harold; 20.08.2012
comment
хорошо, все в порядке - мои измерения не очень точны, я хочу просто получить общее представление о fpu - все же я верю, что могут существовать дополнительные правила для оптимизации такого кода fpu - но это не имеет значения - когда-нибудь l8ter будет купи новый процессор с avx и попробуй переписать самые важные куски под avx, теперь хочу потренироваться, чтобы подготовить l8er ;-) - person grunge fightr; 20.08.2012
comment
65 хорошо, (очень хорошо), кроме того, когда «нормализация», которая является только обычным добавлением, и не выполняет реальных геометрических расчетов, занимает 80 (пока не пробовал с хитрым invsqry (29) - может быть, будет быстрее - не еще пробовал версию sse) [хотя 65, вероятно, потому что я тестирую ее с такими данными, где пересечение не происходит и sqrt не вызывается] - person grunge fightr; 20.08.2012
comment
Кстати, вы не должны проверять это на случайных данных. Я совершенно уверен, что если бы вы все время тестировали это на одних и тех же реальных данных, цифры имели бы гораздо больше смысла. И они, вероятно, также были бы выше - 65 действительно слишком мало для того, чтобы этот квадратный корень происходил в значительном проценте случаев. - person harold; 20.08.2012
comment
да, я так думаю. Что касается случайных данных, я имею в виду, что я даю им некоторые случайно записанные данные вручную, в частности ` static float3 avv = {100,100,100}; статический float3 bvv = {1,2,1}; статический float3 cvv = {10,20,13}; ` Все время одно и то же, но, вероятно, пересечения не происходит ;-) - person grunge fightr; 20.08.2012
comment
Может быть полезнее взять реальную сцену в качестве эталона — тогда вы оптимизируете реальный случай, который действительно произойдет. В противном случае легко случайно сделать трассировку пустой сцены очень быстрой (за счет заполненных сцен), но это не очень полезно. - person harold; 20.08.2012
comment
да, сейчас я буду тестировать настоящие пиксели, но процедура маршрутизации всего пикселя длинная, около 300 строк, но я измерю ее, мне любопытно, сколько циклов на пиксель это - person grunge fightr; 20.08.2012
comment
что касается правил opty, misation - я слышал о некоторых методах «цепочек с меньшим количеством зависимостей» (чтобы позволить moachine распараллеливать некоторые строки) - должно ли это работать также с fpu здесь ?? - person grunge fightr; 21.08.2012
comment
@grungefightr правило цепочек зависимостей применяется и к fpu, но в этом случае вы мало что можете сделать, не так ли? - person harold; 21.08.2012
comment
не знаю, опыта не было - а может чудаки чередовать с фмуллами? Только что читал, что fadds и fmulls можно распараллелить (просматривая отличные руководства по туманам agner :/) - person grunge fightr; 21.08.2012