Школоло / Говнокод #7977 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55
  56. 56
  57. 57
  58. 58
  59. 59
  60. 60
  61. 61
  62. 62
  63. 63
  64. 64
  65. 65
  66. 66
  67. 67
  68. 68
  69. 69
  70. 70
  71. 71
  72. 72
  73. 73
  74. 74
  75. 75
  76. 76
  77. 77
  78. 78
  79. 79
  80. 80
  81. 81
  82. 82
  83. 83
  84. 84
  85. 85
  86. 86
  87. 87
  88. 88
  89. 89
  90. 90
  91. 91
  92. 92
const n = 50;
type vec = array [1..n*4] of system.word;
function vprod(const a, b: vec): Cardinal;
  var i: longInt;
  begin
    result := 0;
    for i := 1 to high(vec) do inc(result, a[i] * b[i]);
  end;
function vprod_asm1(const a, b: vec): Cardinal; assembler;
  asm
     push ebx
     push ecx
     push edx
     push esi
     push edi
     xor ebx, ebx
     mov ecx, n*4
     mov esi, a
     mov edi, b
     xor eax, eax
     cld
  @@l:
     mov   ax, word ptr [esi]
     lea   esi, [esi+2]
     mul   word ptr [edi]
     lea   edi, [edi+2]
     shl   edx, 16
     mov   dx, ax
     add   ebx, edx
     dec   ecx
     jne   @@l
     mov   eax, ebx
     pop edi
     pop esi
     pop edx
     pop ecx
     pop ebx
  end;
function vprod_asm2(const a, b: vec): Cardinal; assembler;
  asm
    push ebx
    push ecx
    push edx
    push esi
    push edi
    xor ebx, ebx
    mov ecx, n*4
    mov esi, a
    mov edi, b
    xor eax, eax
    cld
  @@l:
    lodsw
    movzx   edx, WORD PTR [edi]
    imul    edx
    lea     edi, [edi+2]
    add     ebx, eax
    loop  @@l
    mov   eax, ebx
    pop edi
    pop esi
    pop edx
    pop ecx
    pop ebx
  end;
function vprod_mmx (const a, b: vec): Cardinal; assembler;
  var muls: record l, h: Cardinal end;
  asm
    push ebx
    push ecx
    push esi
    push edi
    mov ecx, n
    mov esi, a
    mov edi, b
    xor eax, eax
    lea     ebx, muls
  @@l:
    db $0F,$6F,$06  // movq    mm0, [esi]
    db $0F,$F5,$07  // pmaddwd mm0, [edi]
    lea     esi, [esi+8]
    db $0F,$7F,$03  // movq    [ebx], mm0
    lea     edi, [edi+8]
    add     eax, [ebx]
    add     eax, [ebx+4]
    loop    @@l
    db $0F,$77 // emms
    pop edi
    pop esi
    pop ecx
    pop ebx
  end;

По просьбам трудящихся публикую модифицированную версию примера MMXTEST.PAS из комплекта компилятора TMT Pascal. Программа находит скалярное произведение двух векторов. Далее должен быть основной блок с фрагментами типа for i := 1 to 100000 do vprod(a, b); , которые я не стал публиковать ввиду ограничений. Функция vprod_asm1 — почти оригинальный код TMT, функция vprod_asm2 — мой оптимизированный вариант. Результаты запуска на двух машинах (таймер получал по RDTSC):
AMD K6-2-333 МГц, FSB 66 МГц.

Delphi7:
Pascal = 0.550 sec.
Asm x86 (original) = 1.034 sec.
Asm x86 (optimized) = 0.490 sec.
Asm MMX = 0.130 sec.
С директивой $O- первый результат 0.853 sec.
Замена loop на dec ecx + jne увеличивает результаты на 0,015 c.

FPC:
Pascal = 1.387 sec.
Asm x86 (original) = 1.199 sec.
Asm x86 (optimized) = 0.510 sec.
Asm MMX = 0.124 sec.

TMT:
Pascal = 0.914 sec.
Asm x86 (original) = 1.037 sec.
Asm x86 (optimized) = 0.494 sec.
Asm MMX = 0.126 sec.

VP:
Pascal = 0.520 sec.
Asm x86 (original) = 1.033 sec.
Asm x86 (optimized) = 0.493 sec.
Asm MMX = 0.146 sec.
С директивами $Q+,R+ первый результат 1.032 sec.
С директивой $Speed- первый результат 0.731 sec.

------------------------------
Celeron 1,86 ГГц, FSB 533 МГц.

Delphi7:
Pascal = 0.025 sec.
Asm x86 (original) = 0.091 sec.
Asm x86 (optimized) = 0.082 sec.
Asm MMX = 0.044 sec.

TMT:
Pascal = 0.109 sec.
Asm x86 (original) = 0.087 sec.
Asm x86 (optimized) = 0.079 sec.
Asm MMX = 0.042 sec.

Запостил: inkanus-gray inkanus-gray, (Updated )

Комментарии (27) RSS

  • На всякий случай кое-какие выводы:
    §1. Оригинальный ассемблерный вариант функции из примера на некоторых машинах работает медленнее паскалевского.
    §2. Код, сгенерированный Дельфи и Виртуал Паскалем, вдвое быстрее оригинального ассемблерного на некоторых машинах.
    §3. Код, сгенерированный Дельфи 7, на современных машинах быстрее примера в MMX.
    §4. Проверка целочисленного переполнения и границ диапазонов не влияет на быстродействие данного кода в Дельфи 7, в отличие от, например, VP, но даже его код получается не тормознее первой версии ассемблерного.
    Ответить
    • если код, сгенеренный дельфи, быстрее, чем ассемблерный - фиговый из вас ассемблерокодер...
      кстати, не так давно я уже встречал эту вонь про "дельфи быстрее ассемблера"
      Ответить
      • > если код, сгенеренный дельфи, быстрее, чем ассемблерный - фиговый из вас ассемблерокодер...
        Спасибо, капитан.
        Ответить
      • А ты лично пробовал обогнать компилятор дельфи на простом целочисленном коде? Не говори о том, чего не знаешь.
        Ответить
          • У него (Д7) есть серьёзный минус - отсутствие инлайна, тупо сделано то, что всякие синусы и даже сраные округления компилируются в вызов функции, но всякая фигня типа распихать целые числа по регистрам у него сделана отлично.
            Ответить
        • если с оптимизацией - сложно. была б она еще и без глюков
          Ответить
          • Расскажи хотя бы про один глюк оптимизации в Д7.
            Только не про
            i: word;
            for i := 0 to L.Count-1 do...
            Ответить
            • попадался код без хинтов и варнингов, без форов вообще, но результат был разный в зависимости от галочки оптимизации. До сути я не докопался (тогда времени не было), так что можно считать мое утверждение бездоказательным. если еще раз попадется обещаю запостить.
              ну или код корявый был:)
              Ответить
              • Я надеюсь, это не про просмотр счётчика цикла в отладчике?
                Ответить
                • нет конечно - про реализацию фора в курсе:)
                  когда найду - выложу.
                  Ответить
    • кончайте спамить.

      для математики есть (во-первых) компетентные компиляторы (например, *любой* С компилятор) и (во-вторых) кучи мат библиотек (таже STL's valarray хорошая стартовая точка).

      переизобретание велосипеда, всего лишь потому что с Дельфой прилагаются только квадратные колеса, наталкивает на мысли что вы пользуетесь неправильной тулзой для поставленой задачи.

      ЗЫ есть такой крутой пример: Quake1, один из самых быстрых SW 3D движков когда либо написаный, не содержит ни одной строчки асма.
      Ответить
      • > кончайте спамить.
        Я сначала не хотел, но в каком-то говнокоде мне предложили опубликовать результаты испытаний отдельным ГК.

        > например, *любой* С компилятор
        Конкретные примеры компиляторов с конкретными примерами ключей и сгенерированного кода имеются? Пока мне удалось заметить только мелочи типа add eax, 1 вместо inc eax в некоторых режимах, а также замену leave на явные операции с регистрами.

        > кучи мат библиотек
        Здесь пример слишком примитивный. Да и целью было не перемножить два вектора, а проиллюстрировать разные подходы.
        Ответить
        • > Конкретные примеры компиляторов с конкретными примерами ключей и сгенерированного кода имеются?

          олололо. сам попросил. aCC 6.06 c +O3 на Итанике 2:
          0000000000000010 <vprod(long*,long*)>:
            10:   [MMI]       alloc r31=ar.pfs,8,8,8
            16:               mov r11=r32
            1c:               mov.i r18=ar.lc
            20:   [MIB]       mov r10=r33
            26:               mov r8=0
            2c:               nop.b 0x0;;
            30:   [MMI]       adds r34=1024,r11
            36:               mov r15=r10
            3c:               mov r9=pr
            40:   [MMI]       mov r14=r11
            46:               cmp.ne.or.andcm p16,p17=42,r0
            4c:               cmp.eq.and p18,p0=42,r0;;
            50:   [MMI]       lfetch [r34],128
            56:               adds r35=1024,r10
            5c:               mov.i ar.lc=24
            60:   [MMI]       mov r17=r10
            66:               adds r16=8,r15
            6c:               mov r15=r11;;
            70:   [MII]       adds r14=8,r14
            76:               mov.i ar.ec=3
            7c:               nop.i 0x0;;
            80:   [MMF] (p16) ld8 r32=[r17],16
            86:         (p16) ld8 r19=[r16],64
            8c:         (p17) xmpy.l f47=f52,f33
            90:   [MII] (p18) add r37=r28,r39
            96:               nop.i 0x0
            9c:               nop.i 0x0;;
            a0:   [MMI] (p16) setf.sig f45=r32
            a6:         (p16) ld8 r33=[r15],16
            ac:         (p18) add r39=r23,r37
            b0:   [MMF] (p16) ld8 r20=[r14],64
            b6:         (p16) setf.sig f48=r19
            bc:         (p17) xmpy.l f52=f38,f35;;
            c0:   [MMF] (p16) setf.sig f46=r33
            c6:         (p16) setf.sig f50=r20
            cc:         (p17) xmpy.l f41=f49,f36
            d0:   [MMF] (p16) ld8 r32=[r15],8
            d6:         (p16) ld8 r19=[r17],8
            dc:         (p17) xmpy.l f38=f51,f34;;
            e0:   [MMI] (p16) setf.sig f49=r32
            e6:         (p16) setf.sig f51=r19
            ec:         (p18) add r19=r22,r39
            f0:   [MMI] (p16) ld8 r28=[r15],8
            f6:         (p16) ld8 r33=[r17],8
            fc:               nop.i 0x0;;
           100:   [MMI] (p17) getf.sig r37=f44
           106:         (p16) setf.sig f32=r33
           10c:               nop.i 0x0
           110:   [MMI] (p16) ld8 r27=[r15],8
           116:         (p16) ld8 r32=[r17],8
          Ответить
        • 11c:               nop.i 0x0;;
           120:   [MMI] (p18) getf.sig r20=f39
           126:         (p16) setf.sig f34=r32
           12c:               nop.i 0x0
           130:   [MMI] (p16) ld8 r26=[r15],8
           136:         (p16) ld8 r33=[r17],8
           13c:               nop.i 0x0;;
           140:   [MMI] (p18) getf.sig r21=f42
           146:         (p16) setf.sig f35=r33
           14c:               nop.i 0x0
           150:   [MMI] (p16) ld8 r32=[r15],8
           156:         (p16) ld8 r23=[r17],8
           15c:               nop.i 0x0;;
           160:   [MMI] (p17) getf.sig r22=f52
           166:         (p16) setf.sig f33=r23
           16c:               nop.i 0x0
           170:   [MMI] (p16) ld8 r33=[r15],8
           176:         (p16) ld8 r24=[r17],8
           17c:               nop.i 0x0;;
           180:   [MMF] (p17) getf.sig r23=f47
           186:         (p16) setf.sig f44=r33
           18c:         (p16) xmpy.l f42=f46,f45
           190:   [MMF]       nop.m 0x0
           196:               nop.m 0x0
           19c:         (p16) xmpy.l f36=f50,f48;;
           1a0:   [MMF] (p17) getf.sig r25=f43
           1a6:         (p16) setf.sig f46=r24
           1ac:         (p16) xmpy.l f39=f49,f51;;
           1b0:   [MMI] (p17) getf.sig r24=f37
           1b6:         (p16) setf.sig f51=r28
           1bc:               nop.i 0x0;;
           1c0:   [MMI] (p17) getf.sig r28=f40
           1c6:         (p16) setf.sig f37=r27
           1cc:         (p18) add r39=r21,r19;;
           1d0:   [MMI] (p16) lfetch [r35]
           1d6:         (p16) setf.sig f48=r26
           1dc:         (p18) add r36=r20,r39
           1e0:   [MII] (p16) setf.sig f50=r32
           1e6:         (p16) adds r33=128,r35;;
           1ec:         (p18) add r8=r38,r36;;
           1f0:   [MMI] (p17) add r36=r25,r8;;
           1f6:         (p17) add r38=r24,r36
           1fc:               nop.i 0x0
           200:   [MFB]       nop.m 0x0
           206:         (p16) xmpy.l f43=f44,f46
           20c:               br.ctop.dptk.many 80 <vprod(long*,long*)+0x70
           210:   [MII]       mov r33=r10
           216:               mov.i ar.lc=r18
           21c:               mov r32=r11;;
           220:   [MIB]       nop.m 0x0
           226:               mov pr=r9,0xfffffffffffffffe
           22c:               br.ret.sptk.many b0;;

          вот тебе и пайплайнинг, и префетч c бранчпредикшн, и все че только можно.
          Ответить
        • а вот и С код, подобно оригиналу использующий слегка кривые константы:
          #define MAX     50
          #define REAL_MAX (MAX*4)
          
          long
          vprod( long *a, long *b )
          {
                  int i;
                  long r = 0;
                  for (i=0; i<REAL_MAX; i++)
                  {
                          r += a[i]*b[i];
                  }
                  return r;
          }
          Ответить
  • несколько рекомендаций по оптимизации на ассемблере:
    1) уменьшить обращения к памяти (тут основные тормоза): mov [...], ... mov ..., [...] push ... pop ...
    2) eax, ecx, edx не нужно сохранять
    3) аргументы в функцию передаются по порядку: eax, edx, ecx, результат возвращается в eax. если метод класса, то первым параметром будет self
    4) FPC в начале и в конце процедуры добавляет push ebp / pop ebp, даже если это не требуется
    PS. оптимизация в старых версиях дельфи глючная.
    Ответить
  • вот этот вариант у меня чуть быстрее того, что с оптимизацией:
    asm
    push ebx
    push esi
    push edi
    xor ebx, ebx
    mov ecx, 2*n
    @@l:
    movzx edi, [eax]
    mov esi, [edx]
    imul edi, esi
    and edi, $FFFF
    add ebx, edi
    movzx edi, [eax + 2]
    shr esi, 16
    imul edi, esi
    add ebx, edi
    add eax, 4
    add edx, 4
    dec ecx
    jnz @@l
    mov eax, ebx
    pop edi
    pop esi
    pop ebx
    end;
    но он не будет работать для нечетного размера массива
    Ответить
    • >но он не будет работать для нечетного размера массива
      Отдельным ГК запостить не желаете? 🙂
      Ответить
  • с$B:Z!J L"T"O?N:SH!U)W:S!D,F$F.T"B?H:H!V H"V?P)OL(Q N?A?T!D(R$R.O.TB$K(Y.A!L:B"U:F F,FJ$D CN$I"Q!K!Z:N E(J:R"E.H?A,Y"L(Q!N G I$F!A,U"D!O V L!E:I.L.T?E:O)G)D.M(H:Q)GX)O,D"K(Y)R?A(X$O$G.D:B,S:NR)D"D?X$I:S(N,O(R(W"L!A M(F!H(Z X!L!J!Z:G)P!G(J F,V:Z)T?Z$F$G:V(J N)V:G!A"X J(L?F H)J.TX!R!G!Q,R.B:YB)W"I A:R"K G(H?H"D R!IS!K"U K:T:V(C(J.M?F:D"Q(DC)C(HF$A:Z"X,U:F?N?AT.L.E"L$A I)U"H O"P(W?S)T(M$L V)X,P U:BB.G$J?W!X:AB)C"J,D$Z!L(W)I!X!W DG!G.E?S$Y:W!T,D"N.Z"K"G$G.J:EY O$KS.V!F:S)U,H:D:W"C$I$U:F,O,W(J B$Z U.L$X(T"R?Q E)O:T H.J"V)J)H?A(H,FJ)P"H"Y!EG,R$N?Q?P(S$R)Z(P"HX)C.N(H W BTE,W.U)V)Y.Z"P(M!N(N)RF.Q.B"Y Z(N.M!AY$M$I"M!E$X,R(W"T)F U?U"J?B(F$Z$H Z M:V:R!K)V Q!C(V?G(T?Z"J.L.AC X$HV)Q,O C,N QI?RO!S)J!E$S)K$D:N,EU(Y?B:HU(R)TM(ZS.GL)T:H W?G)E$Q?K$A$B$D(O,X!M"UWIU$Q)L$W(B"F:V:J$W.P.E!R"V?Z)TD)U!W(L!N A"CH)Q(SP.M!S!S$P?O Z!K)O!K C.O Y!N$GR)K:N!P:Z,V(X:R)B,K!K)Q(D)K(R,K"G"E,W)AH!F?FM"N(B$K)Z?JJ,ON,U(Q$O:I)O)B,X N$X(H"D"R(Z,H(H?P T$D H.Z:F?Y$O$U?H,S.W$V$F(Y"W(E B:U(P:H$L!Y?Q$M O$U.L(D?X:E,V)N)W)Q:M"S?G.TW.C?T(H"M$Q!Y E.U"F)M)Z"F.W,V.F:J(W,K.Z$I.Q:G?Y)D.Q?R:U!H:P GE)UI,Q!R(L:J,Q,LL?A"I$D$QC?W.U O:L(L!AO,B:G:B$D"I.G!LZ?T?Z"Q:Z?E)E"B,A"MR$A,Y"K?U.E)P)C.E$W(K)IK"R?O:MK.S!U,J!Y"C!L(G(W.G(E:R(A)Q"UY(H$E,FW.H.T(KG B?T!C!E(Q:F)G:Y!I.R O,Z.V?SS)V C,R$R S,T"P$KE$V$Z:K$I(A)T(N.P$I:N$H$I(N"G.E"C)E)A?S(D?P,DV.H,Z,KB N$E!CG!ID,Z,A O X?K(Z M!C)T.G.W C!F,X.L?I.C.O)Z(J(Z:Z(X WJ"R:K:I!PC S.M,N)G?ZM)X:U!WV:W:R)M.U Y,W.X,A(H,J)H$N:H$LZ"G"N:U.X"D)F J?J"G$EU$G$M(Q!V"S?R?Q:AG!O,E,B,X:T M$M L,Y.H.A?W"W"E"O$E?Z.T)SТSLLNOTBIRSBJIWROCGNLOFRQXYMFEBQBPTPYYOADWLJCGXESGFWFNSZFZKZCSMHCLYJRUWXBNJQIYCHJSVEKZNYQAOLOBZNFEQALMWOEWWWVHOTKGXOCBMFPPGUDYLHNFBYUGWRRFQMUNQMXUKNPCZIRLMMWOZBIZFZWXLZVMKYORDAZBZZUSTFGVSKDRRSJKBEXIEDWASWOUFDQMQAT
    Ответить

Добавить комментарий

Переведи на "PHP", guest!

    А не использовать ли нам bbcode?


    8