Минутка WTF-9: немного археологии.
От: Sinix  
Дата: 10.05.16 13:37
Оценка: 4 (1)
Раз загадки щёлкают без проблем
Автор: Sinix
Дата: 28.04.16
, подкинем классический пример сфероконя в вакууме.
Практической ценности пример не имеет, разве что как объяснение "как легко намерять фигню".

ВАЖНО: замеры под x86, .Net 4.5+
Попробуйте угадать стоимость вызовов для
  вот этого кода
using System;
using System.Diagnostics;

namespace CodeDrafts
{
    static class Program
    {
        struct A
        {
            public uint a1;
            public uint a2;
        }

        struct B
        {
            public ulong b1;
        }

        unsafe static B FromAUnsafe(A a)
        {
            return *(B*) &a;
        }

        static void Main(string[] args)
        {
            if (IntPtr.Size != 4)
                throw new InvalidOperationException("Run as x86");

            Console.WindowWidth = 120;

            const int Count = 100*1000*1000;

            Measure("BCallBoxStore", () =>
            {
                var a = new A() { a1 = 1, a2 = 2};
                var b = new B();
                for (int i = 0; i < Count; i++)
                {
                    b = FromAUnsafe(a);
                }
                Call1(b);
                return Count;
            });

            Measure("BCallStore", () =>
            {
                var a = new A() { a1 = 1, a2 = 2 };
                var b = new B();
                for (int i = 0; i < Count; i++)
                {
                    b = FromAUnsafe(a);
                }
                Call2(b);
                return Count;
            });

            Measure("BCallBox", () =>
            {
                var a = new A() { a1 = 1, a2 = 2 };
                var b = new B();
                for (int i = 0; i < Count; i++)
                {
                    b = FromAUnsafe(a);
                }
                Call3(b);
                return Count;
            });

            Measure("BCall", () =>
            {
                var a = new A() { a1 = 1, a2 = 2 };
                var b = new B();
                for (int i = 0; i < Count; i++)
                {
                    b = FromAUnsafe(a);
                }
                Call4(b);
                return Count;
            });

            Measure("BNoCall", () =>
            {
                var a = new A() { a1 = 1, a2 = 2 };
                var b = new B();
                for (int i = 0; i < Count; i++)
                {
                    b = FromAUnsafe(a);
                }
                return Count;
            });
            Console.Write("Done...");
            Console.ReadKey();
        }

        private static object _b1;

        private static void Call1(object b)
        {
            _b1 = (B) b;
        }

        private static B _b2;

        private static void Call2(B b)
        {
            _b2 = b;
        }

        private static void Call3(object b)
        {
        }

        private static void Call4(B b)
        {
        }

        private static void Measure(string name, Func<long> callback)
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();

            var mem = GC.GetTotalMemory(true);
            var gc00 = GC.CollectionCount(0);
            var gc01 = GC.CollectionCount(1);
            var gc02 = GC.CollectionCount(2);

            var sw = Stopwatch.StartNew();
            var result = callback();
            sw.Stop();

            var mem2 = GC.GetTotalMemory(false);
            var gc10 = GC.CollectionCount(0);
            var gc11 = GC.CollectionCount(1);
            var gc12 = GC.CollectionCount(2);

            var memDelta = (mem2 - mem)/1024.0;
            var gcDelta0 = gc10 - gc00;
            var gcDelta1 = gc11 - gc01;
            var gcDelta2 = gc12 - gc02;

            Console.WriteLine(
                "{0,20}: {1,5}ms, ips: {2,22:N} | Mem: {3,9:N2} kb, GC 0/1/2: {4}/{5}/{6} => {7,6}",
                name, sw.ElapsedMilliseconds, result/sw.Elapsed.TotalSeconds, memDelta, gcDelta0, gcDelta1, gcDelta2, result);
        }
    }
}


Результаты для нетерпеливых скину отдельным постом.
Отредактировано 07.01.2017 16:46 Sinix . Предыдущая версия . Еще …
Отредактировано 10.05.2016 13:44 Sinix . Предыдущая версия .
минутка wtf
Re: Минутка WTF-9: немного археологии.
От: Sinix  
Дата: 10.05.16 13:39
Оценка: 5 (1)
Здравствуйте, Sinix, Вы писали:

S>Результаты для нетерпеливых скину отдельным постом.

  для нетерпеливых
  и настойчивых
       BCallBoxStore:   123ms, ips:         811 834 600,07 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
          BCallStore:    58ms, ips:       1 700 090 444,81 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
            BCallBox:   104ms, ips:         953 618 840,46 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
               BCall:   584ms, ips:         170 999 158,34 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
             BNoCall:   579ms, ips:         172 541 086,78 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000


ну и как с вот этим теперь жить?
Re: Минутка WTF-9: немного археологии.
От: vasmann  
Дата: 10.05.16 13:49
Оценка: 44 (1) +1
Здравствуйте, Sinix, Вы писали:

S>Раз загадки щёлкают без проблем
Автор: Sinix
Дата: 28.04.16
, подкинем классический пример сфероконя в вакууме.

S>Практической ценности пример не имеет, разве что как объяснение "как легко намерять фигню".

S>ВАЖНО: замеры под x86, .Net 4.5+

S>Попробуйте угадать стоимость вызовов для

Не совсем честно с моей стороны ибо уже разбирался.
  Ответ
В порядке возрастания времени:
1. Самый быстрый: Call2 (там где используется результат и структура передается как собственно структура)
2. Call1 (аналогично Call2 но из-за боксинга будет медленнее)
3. Предполагают оба два вызова Call3 и 4 дадут одинаковый результат, самый медленный
Re[2]: Минутка WTF-9: немного археологии.
От: vasmann  
Дата: 10.05.16 13:51
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, Sinix, Вы писали:


S>>Результаты для нетерпеливых скину отдельным постом.

S>
  для нетерпеливых
S>
  и настойчивых
S>
S>       BCallBoxStore:   123ms, ips:         811 834 600,07 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
S>          BCallStore:    58ms, ips:       1 700 090 444,81 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
S>            BCallBox:   104ms, ips:         953 618 840,46 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
S>               BCall:   584ms, ips:         170 999 158,34 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
S>             BNoCall:   579ms, ips:         172 541 086,78 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
S>


S>ну и как с вот этим теперь жить?


S>


О! Результатов 5, а я описал 4. Вчитаюсь внимательней
Re[2]: Минутка WTF-9: немного археологии.
От: vasmann  
Дата: 10.05.16 13:55
Оценка:
Здравствуйте, vasmann, Вы писали:

V>Здравствуйте, Sinix, Вы писали:


S>>Раз загадки щёлкают без проблем
Автор: Sinix
Дата: 28.04.16
, подкинем классический пример сфероконя в вакууме.

S>>Практической ценности пример не имеет, разве что как объяснение "как легко намерять фигню".

S>>ВАЖНО: замеры под x86, .Net 4.5+

S>>Попробуйте угадать стоимость вызовов для

V>Не совсем честно с моей стороны ибо уже разбирался.

V>
  Ответ
V>В порядке возрастания времени:
V>1. Самый быстрый: Call2 (там где используется результат и структура передается как собственно структура)
V>2. Call1 (аналогично Call2 но из-за боксинга будет медленнее)
V>3. Предполагают оба два вызова Call3 и 4 дадут одинаковый результат, самый медленный



  С корректировал ответ, сразу незаметил что вызов 5
1. BCallStore — без боксинга, результат используется
2. BCallBox (аналогичен BCallBoxStore) — результат используется (инструкция боксинга)
3. BCallBoxStore — аналогично 2, но дольше из за внутреннего анбоксинга и повторного боксинга
4. BNoCall — результат не используется поэтому переменная создается/освобождается на стеке в цикле.
Re[2]: Минутка WTF-9: немного археологии.
От: vasmann  
Дата: 10.05.16 14:04
Оценка: :)
Здравствуйте, Sinix, Вы писали:

S>ну и как с вот этим теперь жить?


У меня вот например жизнь поделилась на два этапа: до твоего утреннего сообщение и после. Мир для меня никогда не будет прежним .
Re[3]: Минутка WTF-9: немного археологии.
От: vasmann  
Дата: 10.05.16 15:43
Оценка:
Здравствуйте, vasmann, Вы писал

Ранее написал что посадка возможна из-за дерганины памяти. Но это не так. Поскольку память Под стек уже выделена. А значит остаётся затраты на проверку выхода указателя головы стека за его пределы + на операции сложения вычитания указателя головы с размером структуры ну и собственно копирование туда данных.
Re[4]: Минутка WTF-9: немного археологии.
От: Lexey Россия  
Дата: 10.05.16 16:18
Оценка:
Здравствуйте, vasmann, Вы писали:

V>Ранее написал что посадка возможна из-за дерганины памяти. Но это не так. Поскольку память Под стек уже выделена. А значит остаётся затраты на проверку выхода указателя головы стека за его пределы + на операции сложения вычитания указателя головы с размером структуры ну и собственно копирование туда данных.


Что-то как-то совсем не убедительно. Стек, AFAIR, всю жизнь проверялся с помощью guard page. Напрямую его проверять особого смысла нет.
У меня есть мысль, что эта фигня может быть из-за кривого выравнивания A. Если так, то изменение порядка вызова тестов должно менять результат.

Upd: Мда, порядок не влияет. Значит не выравнивание все-таки.
Upd2: Или все-таки выравнивание, но для переменных, которые в стеке аллоцируются.
Upd3: И все-таки оно, да. Ибо при замене FromAUnsafe на такое, например, все перекосы уходят:
        unsafe static B FromAUnsafe(A a)
        {
            return new B { b1 = ((ulong)a.a2 << 32) + a.a1};
        }
"Будь достоин победы" (c) 8th Wizard's rule.
Отредактировано 10.05.2016 17:23 Lexey . Предыдущая версия . Еще …
Отредактировано 10.05.2016 17:02 Lexey . Предыдущая версия .
Отредактировано 10.05.2016 16:28 Lexey . Предыдущая версия .
Re[3]: Минутка WTF-9: немного археологии.
От: Sinix  
Дата: 10.05.16 16:28
Оценка: +1
Здравствуйте, vasmann, Вы писали:


V>CallBoxStore — аналогично 2, но дольше из за внутреннего анбоксинга и повторного боксинга


А посмотри код внимательней — CallX вне цикла расположен. По сравнению с 100млн итераций он сам по себе копейки занимает.
Re[4]: Минутка WTF-9: немного археологии.
От: vasmann  
Дата: 10.05.16 17:03
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, vasmann, Вы писали:



V>>CallBoxStore — аналогично 2, но дольше из за внутреннего анбоксинга и повторного боксинга


S>А посмотри код внимательней — CallX вне цикла расположен. По сравнению с 100млн итераций он сам по себе копейки занимает.


Так они все вне цикла. По ildasm-у разница в операции боксинга. А CallBoxStore их (боксингов) 2:
1. при собственно вызове структура боксится
2. значение разбоксивается но тут же боксикстя во статическое поле: private static object _b1;
Re[5]: Минутка WTF-9: немного археологии.
От: rameel https://github.com/rsdn/CodeJam
Дата: 11.05.16 12:03
Оценка: +1
Здравствуйте, vasmann, Вы писали:

V>Так они все вне цикла. По ildasm-у разница в операции боксинга. А CallBoxStore их (боксингов) 2:


Хоть 10, на фоне 100 000 000 их не видно в микроскоп. Все дело какой джит генерирует код. См. ответ на стартовое сообщение
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re: Минутка WTF-9: немного археологии.
От: rameel https://github.com/rsdn/CodeJam
Дата: 11.05.16 12:03
Оценка: 9 (2) +1
Здравствуйте, Sinix, Вы писали:

Хм, решил я посмотреть, что же там такое генерирует джит.

Смотрю только самое интересное BCallStore и BCall. BNoCall в плане сгенерированного кода одинаков с BCall.

Если смотреть на листинги ниже, то видно, что во втором случае на каждое действие выполняется операция загрузки из памяти в регистры, потом обратно — из регистров в память, и так отдельно для a и b с каждым полем, и на каждой итерации все с самого начала.
В общем, занимается переливанием из пустого в порожнее с особым усердием

По листингу, так вообще кажется, что это выхлоп для дебажной версии, а не релизной, возможно внутри где-то что-то сглюгивает, и вместо релизной получаем версию для отладки
  BCallStore
                    var a = new A() { a1 = 1, a2 = 2 };
00690E4E  mov         eax,1  
00690E53  lea         edx,[eax+1]  
00690E56  mov         ebx,eax  
00690E58  mov         ecx,edx  
                    for (int i = 0; i < Count; i++) {
00690E5A  xor         edi,edi  
                        b = FromAUnsafe(a);
00690E5C  lea         esi,[ebp-14h]  
00690E5F  mov         dword ptr [esi],ebx  
00690E61  mov         dword ptr [esi+4],ecx  
00690E64  lea         esi,[ebp-14h]  
00690E67  mov         edx,dword ptr [esi]  
00690E69  mov         esi,dword ptr [esi+4]  
                    for (int i = 0; i < Count; i++) {
00690E6C  inc         edi  
00690E6D  cmp         edi,5F5E100h  
00690E73  jl          00690E5C  
                    }
                    Call2(b);
00690E75  mov         edi,esi  
00690E77  mov         esi,dword ptr ds:[34E34E4h]  
00690E7D  add         esi,4  
00690E80  mov         dword ptr [esi],edx  
00690E82  mov         dword ptr [esi+4],edi  
                    return Count;
00690E85  mov         eax,5F5E100h  
00690E8A  xor         edx,edx  
00690E8C  lea         esp,[ebp-0Ch]  
00690E8F  pop         ebx  
00690E90  pop         esi  
00690E91  pop         edi  
00690E92  pop         ebp  
00690E93  ret

  BCall
                    var a = new A() { a1 = 1, a2 = 2 };
006913D6  mov         eax,1  
006913DB  lea         edx,[eax+1]  
006913DE  mov         dword ptr [ebp-20h],eax  
006913E1  mov         dword ptr [ebp-24h],edx  
                    var b = new B();
006913E4  lea         edi,[ebp-14h]  
006913E7  xorps       xmm0,xmm0  
006913EA  movq        mmword ptr [edi],xmm0  
                    for (int i = 0; i < Count; i++) {
006913EE  xor         ebx,ebx  
                        b = FromAUnsafe(a);
006913F0  lea         edx,[ebp-1Ch]  
006913F3  mov         eax,dword ptr [ebp-20h]  
006913F6  mov         dword ptr [edx],eax  
006913F8  mov         eax,dword ptr [ebp-24h]  
006913FB  mov         dword ptr [edx+4],eax  
006913FE  lea         edi,[ebp-14h]  
00691401  lea         esi,[ebp-1Ch]  
00691404  movq        xmm0,mmword ptr [esi]  
00691408  movq        mmword ptr [edi],xmm0  
                    for (int i = 0; i < Count; i++) {
0069140C  inc         ebx  
0069140D  cmp         ebx,5F5E100h  
00691413  jl          006913F0  
                    return Count;
00691415  mov         eax,5F5E100h  
0069141A  xor         edx,edx  
0069141C  lea         esp,[ebp-0Ch]  
0069141F  pop         ebx  
00691420  pop         esi  
00691421  pop         edi  
00691422  pop         ebp  
00691423  ret
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Отредактировано 11.05.2016 12:37 rameel . Предыдущая версия . Еще …
Отредактировано 11.05.2016 12:25 rameel . Предыдущая версия .
Re[5]: Минутка WTF-9: немного археологии.
От: rameel https://github.com/rsdn/CodeJam
Дата: 11.05.16 12:07
Оценка:
Здравствуйте, Lexey, Вы писали:

L>Upd3: И все-таки оно, да. Ибо при замене FromAUnsafe на такое, например, все перекосы уходят:


Перекосы кстати также уходят если добавить NoInline для Call'ов
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[2]: Минутка WTF-9: немного археологии.
От: Sinix  
Дата: 11.05.16 12:23
Оценка: :)
Здравствуйте, rameel, Вы писали:

R>По листингу, так вообще кажется, что это выхлоп для дебажной версии, а не релизной, возможно внутри где-то что-то сглюгивает, и вместо релизной получаем версию для отладки

Вот 1-в-1 мысли

Самое забавное, по памяти, что поведение сохраняется даже при таргетинге на 3.5.
И тот же самый код, но скомпилированный в 2008й студии, работает нормально.

Надо бы кстати перепроверить, а то туфту гоню, возможно.
По факту — баг конечно, но ловится в очень экзотических условиях и только на ископаемом JIT под x86. Археология, как и было сказано.


2All: Поскольку спасибы для ув rameel уже закончились — отсыпьте за меня, ок?
Re[3]: Минутка WTF-9: немного археологии.
От: rameel https://github.com/rsdn/CodeJam
Дата: 11.05.16 12:41
Оценка:
Здравствуйте, Sinix, Вы писали:

S>И тот же самый код, но скомпилированный в 2008й студии, работает нормально.

S>Надо бы кстати перепроверить, а то туфту гоню, возможно.

2008 как ты и сказал археология) Я ее уже у себя не найду

S>По факту — баг конечно, но ловится в очень экзотических условиях и только на ископаемом JIT под x86. Археология, как и было сказано.


+1
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[4]: Минутка WTF-9: немного археологии.
От: Sinix  
Дата: 11.05.16 13:22
Оценка: 3 (1)
Здравствуйте, rameel, Вы писали:


S>>Надо бы кстати перепроверить, а то туфту гоню, возможно.

R>2008 как ты и сказал археология) Я ее уже у себя не найду

Ну чего: хорошая новость — я гоню туфту, разницы нет. Видимо под x64 запускал.

И новость из разряда "ну офигеть теперь" — RyuJIT однако стабилен. В своём роде.
  простыня замеров
vs2015, 4.6.1:
VS2015
x86
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
       BCallBoxStore:   124ms, ips:         803 018 063,09 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
          BCallStore:    57ms, ips:       1 724 363 882,16 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
            BCallBox:   104ms, ips:         953 907 203,91 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
               BCall:   586ms, ips:         170 545 467,51 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
             BNoCall:   575ms, ips:         173 631 187,22 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
Done...

VS2015
x64
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
       BCallBoxStore:   492ms, ips:         202 864 034,44 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
          BCallStore:   492ms, ips:         203 064 734,19 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
            BCallBox:   492ms, ips:         203 092 530,58 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
               BCall:   548ms, ips:         182 251 077,83 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
             BNoCall:   543ms, ips:         183 994 874,64 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
Done...



vs2015, 3.5:
VS2015
x86
mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
       BCallBoxStore:   123ms, ips:         808 945 644,52 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
          BCallStore:    58ms, ips:       1 723 825 859,11 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
            BCallBox:   121ms, ips:         822 695 198,83 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
               BCall:   433ms, ips:         230 815 109,71 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
             BNoCall:   316ms, ips:         315 741 780,06 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
Done...

VS2015
x64
mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
       BCallBoxStore:    66ms, ips:       1 514 593 869,23 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
          BCallStore:    64ms, ips:       1 543 743 516,28 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
            BCallBox:    64ms, ips:       1 554 552 351,10 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
               BCall:    66ms, ips:       1 512 603 008,26 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
             BNoCall:    29ms, ips:       3 385 836 369,30 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
Done...


vs2008, 3.5:
VS2015
x86
mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
       BCallBoxStore:   123ms, ips:         808 945 644,52 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
          BCallStore:    58ms, ips:       1 723 825 859,11 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
            BCallBox:   121ms, ips:         822 695 198,83 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
               BCall:   433ms, ips:         230 815 109,71 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
             BNoCall:   316ms, ips:         315 741 780,06 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
Done...

VS2015
x64
mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
       BCallBoxStore:    66ms, ips:       1 514 593 869,23 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
          BCallStore:    64ms, ips:       1 543 743 516,28 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
            BCallBox:    64ms, ips:       1 554 552 351,10 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
               BCall:    66ms, ips:       1 512 603 008,26 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
             BNoCall:    29ms, ips:       3 385 836 369,30 | Mem:      8,00 kb, GC 0/1/2: 0/0/0 => 100000000
Done...


Саммари: при возне с unsafe надо оччень внимательно проверять бенчмарки — они могут врать.

Написать чтоль в CoreClr? *чешет в затылке.
Re[5]: Минутка WTF-9: немного археологии.
От: rameel https://github.com/rsdn/CodeJam
Дата: 11.05.16 13:44
Оценка: 1 (1)
Здравствуйте, Sinix, Вы писали:

S>И новость из разряда "ну офигеть теперь" — RyuJIT однако стабилен. В своём роде.


Однако, возможно как и говорили адрес не выровнен. У десктопа буду проверю. У меня листинг сохранился для x64, там код чище и как минимум не хуже, чем для x86, но тормозит-с однако в сравнении с ним в 10 раз
  x64
00007FF9E1410D99  mov         eax,1  
00007FF9E1410D9E  mov         edx,2  
                    for (int i = 0; i < Count; i++) {
00007FF9E1410DA3  xor         ecx,ecx  
                        b = FromAUnsafe(a);
00007FF9E1410DA5  mov         dword ptr [rsp+20h],eax  ; <-----
00007FF9E1410DA9  mov         dword ptr [rsp+24h],edx  ; <-----
00007FF9E1410DAD  mov         r8,qword ptr [rsp+20h]   ; <-----
                    for (int i = 0; i < Count; i++) {
00007FF9E1410DB2  inc         ecx  
00007FF9E1410DB4  cmp         ecx,5F5E100h  
00007FF9E1410DBA  jl          00007FF9E1410DA5  
                    }
                    Call2(b);
00007FF9E1410DBC  mov         rax,17451D459A8h  
00007FF9E1410DC6  mov         rax,qword ptr [rax]  
00007FF9E1410DC9  mov         qword ptr [rax+8],r8  
                    return Count;
00007FF9E1410DCD  mov         eax,5F5E100h  
00007FF9E1410DD2  add         rsp,28h  
00007FF9E1410DD6  ret


S>Саммари: при возне с unsafe надо оччень внимательно проверять бенчмарки — они могут врать.


+1

S>Написать чтоль в CoreClr? *чешет в затылке.


Не повредит
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[6]: Минутка WTF-9: немного археологии.
От: Sinix  
Дата: 11.05.16 14:43
Оценка:
Здравствуйте, rameel, Вы писали:


S>>Написать чтоль в CoreClr? *чешет в затылке.

R>Не повредит

Убедил
Re[5]: Минутка WTF-9: немного археологии.
От: Lexey Россия  
Дата: 11.05.16 16:54
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Ну чего: хорошая новость — я гоню туфту, разницы нет. Видимо под x64 запускал.


Под 2012 с 4.5 картина аналогична 2015 с 4.6.1.
"Будь достоин победы" (c) 8th Wizard's rule.
Re[6]: Минутка WTF-9: немного археологии.
От: Sinix  
Дата: 11.05.16 16:58
Оценка:
Здравствуйте, Lexey, Вы писали:

L>Под 2012 с 4.5 картина аналогична 2015 с 4.6.1.


Угу. Мне уже вот тут намекнули, что единственный мой правильный вывод в этой ветке — про "как легко намерять фигню"

Надо всё-таки найти оригинальный пример, насколько помню, там результаты от текущего элемента в массиве зависели.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.