Re[8]: C# - from indians by indians
От: petr_t  
Дата: 04.06.15 09:42
Оценка: :))
Здравствуйте, gandjustas, Вы писали:

G>Тебе ситуация кажется странной, потому что ты не понимаешь экономических мотивов технологических решений.


Да ладно, какие там экономические мотивы. Переехать с VSS на что-то более приличное — достаточно пары дней максимум.
Это просто множество говнокодеров и говноменеджеров, которые будут сопротивляться любым изменениям.
Re[26]: C# - from indians by indians
От: Sinclair Россия https://github.com/evilguest/
Дата: 04.06.15 09:43
Оценка: +1
Здравствуйте, mik1, Вы писали:

M>Меня больше пугают 30% вариативности результатов сишного примера. В Яве там практически нулевое стандартное отклонение.

Я правильно понимаю, что то, что вы написали некорректный код, вас не пугает совсем?
Может вы перемерите производительность корректного кода?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[28]: C# - from indians by indians
От: Evgeny.Panasyuk Россия  
Дата: 04.06.15 09:59
Оценка:
Здравствуйте, Aртём, Вы писали:

EP>>>>Сложность вставки в середину std::deque — линейная.

Aё>>>Это типа ключ к производительности?
EP>>Это такая структура данных. Структуры данных бывают разные, и каждая полезна при каких-то определённых условиях
Aё>Вы сначала привели std::deque как пример производительности, потом в кусты. Нехорошо.

Это передёргивание чистой воды Я не говорил что вставка в середину deque — быстрая.

Aё>>>Поля объекта вектор для Вас это value type?

EP>>Изучай
Aё>Гуглить я умею. Вы не ответили на мой вопрос- Вы действительно считаете, что поля объекта data типа vector являются типами по значению для типа Foo? Или таки при копировании Foo для data будет вызван копирующий конструктор?

Открой ссылку и прочитай что такое value type.

EP>>>>Опять таки, то что на Java можно написать быстрый код дорогой ценной — я сказал в том же сообщении.

Aё>>>У вас обоих код тормозной и написан за минуту. С тем отличием, у mik1 код без запашка.
EP>>Как минимум с тем отличием что у mik1 логическая ошибка, как раз в самом характерном месте.
Aё>Не вдавался в подробности, что там нарушил mik1 при перемножении- но сомневаюсь, что дело в адресной арифметике.

Причём тут адресная арифметика? Сам придумал, сам сомневается

Aё>Вообще как-то удивляет, что вроде бы более низкоуровневый программист на C++ боится адресной арифметики в Java и вообще не ожидает такого от Java-иста.


Мой тезис в том что быстрый код на C++ более высокоуровневый чем быстрый код на Java.

EP>>Уже третьи сутки пошли, а корректного кода на Java так и нет.

Aё>Дам Вам вопрос на засыпку- напишете без сторонних библиотек элегантный и быстрый код для reverse matrix со стороной N?

Что такое "reverse" matrix? Как это вообще относится к теме?
Ты даже не в состоянии найти баг в реализации mik1, да и вообще твоей версии кода здесь не было — при этом зачем-то просишь написать код для какого-то стороннего примера

EP>>Это вообще ортогонально — в Java можно создать mutable строку, в C++ — immutable

Aё>Просто для информации- в Java String immutable из коробки, в C++ std::string mutable из коробки.

Ещё раз — это ортогонально к обсуждаемому вопросу. Лишняя индерекция никуда не делась
Re[27]: C# - from indians by indians
От: mik1  
Дата: 04.06.15 11:26
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Как минимум с тем отличием что у mik1 логическая ошибка, как раз в самом характерном месте. Писал бы он медленный Java-style с объектами Complex — такой ошибки бы не было.

EP>Уже третьи сутки пошли, а корректного кода на Java так и нет.

Тебя мучает, что я одно присваивание неправильно написал? Первым же юнит тестом его бы накрыло. Писал я его в 2 часа ночи по местному времени.
В отличии от тебя я сюда заглядываю, а не сижу тут.
Re[27]: C# - from indians by indians
От: mik1  
Дата: 04.06.15 11:33
Оценка:
Здравствуйте, Sinclair, Вы писали:

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


M>>Меня больше пугают 30% вариативности результатов сишного примера. В Яве там практически нулевое стандартное отклонение.

S>Я правильно понимаю, что то, что вы написали некорректный код, вас не пугает совсем?
S>Может вы перемерите производительность корректного кода?

Сразу после того, как вы в Яве статический конструктор скомпилируете.
    public double testVectorMult()
    {
        double t;
        for ( int i = 0; i < u_ar.length / 2; ++i ) {
            t = u.re(i) * v.re(i) - u.im(i) * v.im(i);
            v.im(i, u.re(i)*v.im(i) + u.im(i)*v.re(i));
            v.re(i, t);
        }
        return u.re( 0 );
    }

# Warmup: 10 iterations, 1 s each
# Measurement: 10 iterations, 1 s each
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: info.javaperformance.gccheck.ComplexTest2.testVectorMult

# Run progress: 0.00% complete, ETA 00:00:20
# Fork: 1 of 1
# Warmup Iteration   1: 61.510 ms/op
# Warmup Iteration   2: 58.380 ms/op
# Warmup Iteration   3: 58.579 ms/op
# Warmup Iteration   4: 58.505 ms/op
# Warmup Iteration   5: 58.697 ms/op
# Warmup Iteration   6: 58.694 ms/op
# Warmup Iteration   7: 58.468 ms/op
# Warmup Iteration   8: 58.574 ms/op
# Warmup Iteration   9: 58.720 ms/op
# Warmup Iteration  10: 58.659 ms/op
Iteration   1: 58.489 ms/op
Iteration   2: 58.605 ms/op
Iteration   3: 58.536 ms/op
Iteration   4: 58.544 ms/op
Iteration   5: 58.226 ms/op
Iteration   6: 58.249 ms/op
Iteration   7: 57.912 ms/op
Iteration   8: 58.510 ms/op
Iteration   9: 58.434 ms/op
Iteration  10: 58.742 ms/op


Result: 58.425 ±(99.9%) 0.358 ms/op [Average]
  Statistics: (min, avg, max) = (57.912, 58.425, 58.742), stdev = 0.237
  Confidence interval (99.9%): [58.067, 58.783]
Re[27]: C# - from indians by indians
От: mik1  
Дата: 04.06.15 11:59
Оценка:
Здравствуйте, Sinclair, Вы писали:

M>>Меня больше пугают 30% вариативности результатов сишного примера. В Яве там практически нулевое стандартное отклонение.

S>Я правильно понимаю, что то, что вы написали некорректный код, вас не пугает совсем?
S>Может вы перемерите производительность корректного кода?

Да, так что насчет такого разброса результатов в си? Как-то меня он очень смущает...
Re[28]: C# - from indians by indians
От: Evgeny.Panasyuk Россия  
Дата: 04.06.15 14:11
Оценка:
Здравствуйте, mik1, Вы писали:

Aё>>>У вас обоих код тормозной и написан за минуту. С тем отличием, у mik1 код без запашка.

EP>>Как минимум с тем отличием что у mik1 логическая ошибка, как раз в самом характерном месте. Писал бы он медленный Java-style с объектами Complex — такой ошибки бы не было.
EP>>Уже третьи сутки пошли, а корректного кода на Java так и нет.
M>Тебя мучает, что я одно присваивание неправильно написал? Первым же юнит тестом его бы накрыло. Писал я его в 2 часа ночи по местному времени.

У тебя баг именно в том месте, которого могло бы и не быть при наличии структур в языке, "кодом без запашка" это точно не является (на что я и отвечал). Писал бы ты в Java-style с полноценным объектом Complex — то этой ошибки бы не было.
Если бы ошибся например с замером времени, или например нарандомил денормализированных чисел — то и вопросов никаких не было бы, так как это к теме совершенно не относится, все ошибаются.

M>В отличии от тебя я сюда заглядываю, а не сижу тут.


А мне нравится обмениваться опытом, не всегда конечно здесь это результативно, но тем не менее попадаются очень интересные дискуссии.
А на что я трачу своё личное время из своего свободного графика — это к теме совершенно не относится. В любом случае код я показал сразу же.
Отредактировано 04.06.2015 14:14 Evgeny.Panasyuk . Предыдущая версия .
Re[22]: C# - from indians by indians
От: greenpci  
Дата: 05.06.15 08:13
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>>>>Пока ты редактировал сообщение, я уже сделал в таком виде Убрать зависимость boost конечно не сложно, но давай уже сделаем это после того как увидим Java версию.


Теперь разберем дотнет

Я поменял плюсный код, так как у меня пока нет С++14 компилятора на машине. Еще добавил чтение из файла, чтобы сверить результаты, и они сходятся.

  C++
#include <algorithm>
#include <iterator>
#include <iostream>
#include <fstream>
#include <numeric>
#include <cstdlib>
#include <vector>
#include <chrono>
#include <iomanip>
#include "assert.h"

using namespace std;

struct Complex
{
    double re;
    double im;
};

Complex operator+(Complex x, Complex y)
{
    Complex ret_val = { x.re + y.re, x.im + y.im };
    return ret_val;
}

Complex operator*(Complex x, Complex y)
{
    Complex ret_val = { x.re*y.re - x.im*y.im, x.re*y.im + x.im*y.re };
    return ret_val;
}

Complex random_complex()
{
    Complex ret_val = { rand() / 1000. - 1000., rand() / 1000. - 1000. };
    return ret_val;
}

template<typename F>
void benchmark(F f)
{
    using namespace chrono;
    auto start = high_resolution_clock::now();
    f();
    auto end = high_resolution_clock::now();
    auto elapsed = end - start;
    cout << "Elapsed = " << duration_cast<duration<double>>(elapsed).count() * 1000 << " ms" << endl;
}

basic_ostream<char> & operator<<(basic_ostream<char> &stm, Complex c)
{
    stm << c.re << " " << c.im << std::endl;
    return stm;
}

basic_istream<char> & operator>>(basic_istream<char> &stm, Complex &c)
{
    stm >> c.re;
    stm >> c.im;
    return stm;
}

void generate_complex_sequence(vector<Complex> &v, vector<Complex> &u)
{
    constexpr auto N = 1u << 24;
    v.reserve(N);
    generate_n(back_inserter(v), N, random_complex);
    u = v;
    random_shuffle(begin(v), end(v));
    random_shuffle(begin(u), end(u));
}

void save_complex_sequence(vector<Complex> &v, vector<Complex> &u)
{
    ofstream stm("complex.dat", ios_base::out);
    assert(stm);
    stm << std::setprecision(14);
    ostream_iterator<Complex> it(stm);
    std::copy(v.begin(), v.end(), it);
    std::copy(u.begin(), u.end(), it);
}

void load_complex_sequence(vector<Complex> &v, vector<Complex> &u)
{
    constexpr auto N = 1u << 24;
    constexpr auto buf_len = 5u << 20;
    char *buffer = new char[buf_len];
    v.reserve(N);
    u.reserve(N);
    ifstream stm;
    stm.rdbuf()->pubsetbuf(buffer, buf_len);
    stm.open("complex.dat", ios_base::in);
    assert(stm);
    stm.precision(16);
    std::string str;
    unsigned i = 0;
    vector<Complex> *cur = &v;
    while(std::getline(stm, str))
    {
        char *ptr = nullptr;
        double re = ::strtod(str.data(), &ptr);
        double im = ::strtod(ptr, &ptr);
        Complex c = {re, im};
        cur->push_back(c);
        i++;
        if(i == N)
            cur = &u;
    }
    // istream_iterator<Complex> it(stm);
    // std::copy_n(it, N, back_inserter(v)); 
    // std::copy_n(it, N, back_inserter(u)); 
    std::cout << "v.size() = " << v.size() << std::endl;
    std::cout << "u.size() = " << u.size() << std::endl;
}

int main()
{
    vector<Complex> v, u;
    std::cout << "Benchmark loading:" << std::endl;
    // load_complex_sequence(v, u);
    generate_complex_sequence(v, u);

    benchmark([&]
    {
        transform(begin(v), end(v), begin(u), begin(v), [](Complex x, Complex y) { return x*y; });
    });

    auto result = accumulate(begin(v), end(v), Complex{});
    std::cout << std::setprecision(16) << " Re: " << result.re << " Im: " << result.im << std::endl;
    return 0;
}


  C#
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace ConsoleApplication1
{
    struct Complex
    {
        public Complex(double re, double im)
        {
            Re = re;
            Im = im;
        }

        public double Re;
        public double Im;

        public static Complex operator +(Complex x, Complex y)
        {
            return new Complex(x.Re + y.Re, x.Im + y.Im);
        }

        public unsafe static Complex operator *(Complex x, Complex y)
        {
            return new Complex(x.Re * y.Re - x.Im * y.Im, x.Re * y.Im + x.Im * y.Re);
        }

        private const int RandMax = 32767;
        private static Random random = new Random();

        public static Complex RandomComplex()
        {
            return new Complex(random.Next(RandMax) / 1000D, random.Next(RandMax) / 1000D);
        }
    }

    static class Funcs
    {
        public static void Shuffle<T>(IList<T> list)
        {
            Random rng = new Random();
            int n = list.Count;
            while (n > 1)
            {
                n--;
                int k = rng.Next(n + 1);
                T value = list[k];
                list[k] = list[n];
                list[n] = value;
            }
        }

        public static void PopulateWithRandom(Complex[] v, Complex[] u)
        {
            const int n = 1 << 24;
            for (int i = 0; i < n; i++ )
            {
                Complex random = Complex.RandomComplex();
                v[i] = random;
                u[i] = random;
            }

            Funcs.Shuffle(u);
            Funcs.Shuffle(v);
        }

        public static void LoadComplexSequence(Complex[] v, Complex[] u)
        {
            const int n = 1 << 24;

            using (var stm = File.OpenRead(@".\NativeBenchmark\complex.dat"))
            {
                using (var tr = new StreamReader(stm))
                {
                    foreach(var list in new Complex[][]{v, u})
                    {
                        int i = 0;
                        string line;
                        while (i < n && (line = tr.ReadLine()) != null)
                        {
                            var components = line.Split(' ');

                            if (components.Length != 2)
                                throw new ApplicationException("There should be two components");

                            list[i] = new Complex(Convert.ToDouble(components[0]), Convert.ToDouble(components[1]));
                            i++;
                        }

                        Console.WriteLine("Added {0} elements", i);
                    }
                }
            }
        }
    }

    class Program
    {
        [DllImport("winmm.dll")]
        internal static extern uint timeBeginPeriod(uint period);
        [DllImport("winmm.dll")]
        internal static extern uint timeEndPeriod(uint period);

        static void Main(string[] args)
        {

            const int n = 1 << 24;
            Console.WriteLine("n={0}", n);
            var v = new Complex[n];
            var u = new Complex[n];

            var watch = Stopwatch.StartNew();
            Funcs.PopulateWithRandom(v, u);
            //Funcs.LoadComplexSequence(v, u);
            watch.Stop();

            Console.WriteLine("Loading time: {0:F4}", watch.ElapsedMilliseconds);

            timeBeginPeriod(5);
            unsafe
            {
                watch = Stopwatch.StartNew();
                for (int i = 0; i < n; i++)
                {
                    v[i] = v[i] * u[i];
                }
            }
            watch.Stop();
            timeEndPeriod(5);

            var result = new Complex(0D, 0D);
            v.ToList().ForEach(c=>{result = result + c;});
            Console.WriteLine(".NET Elapsed: {0:F4} ms", watch.ElapsedMilliseconds);
            Console.WriteLine("Result: {0}, {1}", result.Re, result.Im);

        }
    }
}


Замеры:

Просто Elapsed это плюсы.

.NET Elapsed: 179.0000 ms
Elapsed = 94.006 ms
.NET Elapsed: 195.0000 ms
Elapsed = 85.005 ms
.NET Elapsed: 182.0000 ms
Elapsed = 87.005 ms
.NET Elapsed: 215.0000 ms
Elapsed = 95.005 ms
.NET Elapsed: 187.0000 ms
Elapsed = 87.005 ms
.NET Elapsed: 190.0000 ms
Elapsed = 91.006 ms
.NET Elapsed: 191.0000 ms
Elapsed = 95.006 ms
.NET Elapsed: 186.0000 ms
Elapsed = 99.006 ms
.NET Elapsed: 181.0000 ms
Elapsed = 95.006 ms
.NET Elapsed: 192.0000 ms
Elapsed = 97.006 ms


Народ, дайте знать, если можно оптимизировать дотнетный код еще. Я поправлю и замерю.
Re[23]: C# - from indians by indians
От: Aртём Австралия жж
Дата: 05.06.15 08:36
Оценка: :)))
Здравствуйте, greenpci, Вы писали:

G>Народ, дайте знать, если можно оптимизировать дотнетный код еще. Я поправлю и замерю.


Подключи blas/lapack и замерь: управляемый код, который крутит матрицы в специализированной библиотеке (под Java точно есть обёртки), и C++- самописная реализация. До того, размахивать флагом что C++ тормозит чуть быстрей, чем _подставить по вкусу_, бессмысленно. Я уже упоминал программу Mathematica, стандарт де-факто в узких кругах- кросс-платформа на Java, крутит вычисления в специализированных библиотеках, в том числе может задействовать CUDA.
Re[23]: C# - from indians by indians
От: Evgeny.Panasyuk Россия  
Дата: 05.06.15 08:54
Оценка:
Здравствуйте, greenpci, Вы писали:

G>Замеры:

G>Просто Elapsed это плюсы.
G>

G>.NET Elapsed: 179.0000 ms
G>Elapsed = 94.006 ms

G>Народ, дайте знать, если можно оптимизировать дотнетный код еще. Я поправлю и замерю.

У меня разница в десятки процентов. Возможно у тебя что-то не так с окружением.
Ты C# версию как запускаешь? Случайно не по "F5"?
Re[24]: C# - from indians by indians
От: greenpci  
Дата: 05.06.15 09:08
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>У меня разница в десятки процентов. Возможно у тебя что-то не так с окружением.

EP>Ты C# версию как запускаешь? Случайно не по "F5"?

Из командной строки, правда из под mingw. Запустил из вижуал студии команд лайн, те же цифры. Си плюс плюс компилировал mingw gcc.
Re[23]: C# - from indians by indians
От: Sinix  
Дата: 05.06.15 11:42
Оценка: 4 (2)
Здравствуйте, greenpci, Вы писали:

G>Теперь разберем дотнет

G>Народ, дайте знать, если можно оптимизировать дотнетный код еще. Я поправлю и замерю.

Если говорить про этот цикл:
            unsafe
            {
                watch = Stopwatch.StartNew();
                for (int i = 0; i < n; i++)
                {
                    v[i] = v[i] * u[i];
                }
            }
            watch.Stop();

то всё ок там, нечего оптимизировать
Не, можно заиспользовать RyuJIT+SIMD или распараллелить *(конкретно тут не поможет, время слишком мелкое), но это читерство и несерьёзно.

UPD. Ещё, обычно рандом инициализируют константой,
            Random rng = new Random(0);
, чтобы повторяемые результаты были. Опять-таки это скорее вопрос для собеседования, чем смертельно важный факт


Такая просьба: запусти дотнетный код с Target platform = x86. Текущий JIT под x64 любит на ровном месте кривой код генерить. У меня соотношение 58ms/116ms в пользу x86.

Да, можно вытащить в отдельный метод
        unsafe private static void Run(int n, Complex[] v, Complex[] u)
        {
            for (int i = 0; i < n; i++)
            {
                v[i] = v[i] * u[i];
            }
        }

— это уменьшит ограничение времени на JIT и даст возможность сгенерить чуть-чуть лучший код, но это копейки: 60 vs 58 ms.

UPD2. Тот же код с классами вместо структур:
.NET Elapsed: 4723,0000 ms

Наглядная иллюстрация gc pressure и золотого правила "ежели один человек построил, другой завсегда разобрать может"

UPD3.
На той же машине плюсовый код от ув. greenpci (vs2013, релиз, win32, без отладчика) на настройках проекта по умолчанию выдаёт
Elapsed = 189.011 ms

Что-то я делаю не так
Отредактировано 05.06.2015 12:24 Sinix . Предыдущая версия . Еще …
Отредактировано 05.06.2015 11:53 Sinix . Предыдущая версия .
Re[24]: C# - from indians by indians
От: greenpci  
Дата: 05.06.15 12:29
Оценка: 2 (1) +2 :)
Здравствуйте, Sinix, Вы писали:

S>Такая просьба: запусти дотнетный код с Target platform = x86. Текущий JIT под x64 любит на ровном месте кривой код генерить. У меня соотношение 58ms/116ms в пользу x86.


да, отличный совет! Вот он секрет низких процентов у Евгения.

.NET Elapsed: 107.0000 ms
Elapsed = 98.005 ms
.NET Elapsed: 115.0000 ms
Elapsed = 96.006 ms
.NET Elapsed: 112.0000 ms
Elapsed = 89.005 ms
.NET Elapsed: 111.0000 ms
Elapsed = 96.005 ms
.NET Elapsed: 114.0000 ms
Elapsed = 96.005 ms
.NET Elapsed: 108.0000 ms
Elapsed = 94.005 ms
.NET Elapsed: 106.0000 ms
Elapsed = 90.005 ms
.NET Elapsed: 113.0000 ms
Elapsed = 94.006 ms
.NET Elapsed: 117.0000 ms
Elapsed = 99.005 ms
.NET Elapsed: 111.0000 ms
Elapsed = 89.005 ms


S>Да, можно вытащить в отдельный метод

S>
S>        unsafe private static void Run(int n, Complex[] v, Complex[] u)
S>        {
S>            for (int i = 0; i < n; i++)
S>            {
S>                v[i] = v[i] * u[i];
S>            }
S>        }
S>

S>- это уменьшит ограничение времени на JIT и даст возможность сгенерить чуть-чуть лучший код, но это копейки: 60 vs 58 ms.

это практически ничего не изменило:

.NET Elapsed: 114.0000 ms
Elapsed = 92.005 ms
.NET Elapsed: 118.0000 ms
Elapsed = 94.005 ms
.NET Elapsed: 114.0000 ms
Elapsed = 95.005 ms
.NET Elapsed: 118.0000 ms
Elapsed = 102.006 ms
.NET Elapsed: 117.0000 ms
Elapsed = 95.005 ms
.NET Elapsed: 117.0000 ms
Elapsed = 93.006 ms
.NET Elapsed: 114.0000 ms
Elapsed = 95.005 ms
.NET Elapsed: 118.0000 ms
Elapsed = 98.006 ms
.NET Elapsed: 116.0000 ms
Elapsed = 93.005 ms
.NET Elapsed: 113.0000 ms
Elapsed = 93.005 ms


S>UPD2. Тот же код с классами вместо структур:

S>
S>.NET Elapsed: 4723,0000 ms
S>


А вот List вместо массивов, ради интереса.

.NET Elapsed: 470.0000 ms
Elapsed = 93.0053 ms
.NET Elapsed: 475.0000 ms
Elapsed = 94.0053 ms
.NET Elapsed: 474.0000 ms
Elapsed = 98.0057 ms
.NET Elapsed: 490.0000 ms
Elapsed = 98.0056 ms
.NET Elapsed: 453.0000 ms
Elapsed = 100.006 ms
.NET Elapsed: 472.0000 ms
Elapsed = 93.0053 ms
.NET Elapsed: 471.0000 ms
Elapsed = 89.0051 ms
.NET Elapsed: 468.0000 ms
Elapsed = 94.0054 ms
.NET Elapsed: 456.0000 ms
Elapsed = 91.0052 ms
.NET Elapsed: 483.0000 ms
Elapsed = 95.0054 ms


S>Наглядная иллюстрация gc pressure и золотого правила "ежели один человек построил, другой завсегда разобрать может"


У меня был обратный опыт. Один деятель на работе решил, что если методов нет, то надо поменять class на struct. Он попросил меня помочь разобраться, почему у него чертовщина с разными значениями полей в разных местах начала твориться. Типа, вот смотри я поменял значение в методе, а в вызывающем методе они опять старые.
Re[24]: C# - from indians by indians
От: Evgeny.Panasyuk Россия  
Дата: 05.06.15 12:40
Оценка: 2 (1) +1
Здравствуйте, Sinix, Вы писали:

S>Не, можно заиспользовать RyuJIT+SIMD


От SIMD тут будет не так много эффекта, так как значительную часть времени здесь занимает перекачка данных из памяти. Точнее он будет, но не кратен увеличению max flop/s.
GCC кстати делает векторизацию C++ кода выше автоматом (опции компиляции):
  ASM
.L94:
    vmovupd    (%rcx), %xmm3
    addq    $1, %r10
    addq    $64, %rcx
    addq    $64, %rdi
    vinsertf128    $0x1, -48(%rcx), %ymm3, %ymm1
    vmovupd    -32(%rcx), %xmm3
    vinsertf128    $0x1, -16(%rcx), %ymm3, %ymm3
    vmovupd    -64(%rdi), %xmm4
    vinsertf128    $1, %xmm3, %ymm1, %ymm0
    vperm2f128    $49, %ymm3, %ymm1, %ymm3
    vunpcklpd    %ymm3, %ymm0, %ymm2
    vunpckhpd    %ymm3, %ymm0, %ymm3
    vinsertf128    $0x1, -48(%rdi), %ymm4, %ymm0
    vmovupd    -32(%rdi), %xmm4
    vinsertf128    $0x1, -16(%rdi), %ymm4, %ymm4
    vinsertf128    $1, %xmm4, %ymm0, %ymm5
    vperm2f128    $49, %ymm4, %ymm0, %ymm4
    vunpcklpd    %ymm4, %ymm5, %ymm1
    vunpckhpd    %ymm4, %ymm5, %ymm4
    vmulpd    %ymm1, %ymm2, %ymm0
    vmulpd    %ymm4, %ymm3, %ymm5
    vmulpd    %ymm4, %ymm2, %ymm2
    vmulpd    %ymm1, %ymm3, %ymm1
    vsubpd    %ymm5, %ymm0, %ymm0
    vaddpd    %ymm1, %ymm2, %ymm1
    vinsertf128    $1, %xmm0, %ymm0, %ymm2
    vperm2f128    $49, %ymm0, %ymm0, %ymm0
    vinsertf128    $1, %xmm1, %ymm1, %ymm3
    vperm2f128    $49, %ymm1, %ymm1, %ymm1
    vshufpd    $12, %ymm3, %ymm2, %ymm2
    vshufpd    $12, %ymm1, %ymm0, %ymm0
    vmovups    %xmm2, -64(%rcx)
    vextractf128    $0x1, %ymm2, -48(%rcx)
    vmovups    %xmm0, -32(%rcx)
    vextractf128    $0x1, %ymm0, -16(%rcx)
    cmpq    %rsi, %r10
    jb    .L94


S>или распараллелить *(конкретно тут не поможет, время слишком мелкое)


Распараллеливание существенно помогает даже на Coliru.
Причём распараллеливается двумя строчками — добавлением #include <parallel/algorithm> и заменой std::transform на __gnu_parallel::transform (у него такая же сигнатура)

S>но это читерство и несерьёзно.


Пример же совершенно не про SIMD и Parallel. Как я уже говорил выше — отсутствие структур и лишние индерекци бьют далеко не только по интенсивным вычислениям, а практически по всему коду.

S>UPD2. Тот же код с классами вместо структур:

S>
S>.NET Elapsed: 4723,0000 ms
S>


Я об этом и говорил выше — разница может быть на порядки.

S>Наглядная иллюстрация gc pressure и золотого правила "ежели один человек построил, другой завсегда разобрать может"


А дело тут не в GC, а в постоянных cache miss'ах. Если на C++ сделать такой же memory layout — то точно также получим тормоза (подобный пример
Автор: Evgeny.Panasyuk
Дата: 18.10.14
).
Отредактировано 05.06.2015 12:45 Evgeny.Panasyuk . Предыдущая версия .
Re[25]: C# - from indians by indians
От: Sinix  
Дата: 05.06.15 12:45
Оценка: +1
Здравствуйте, greenpci, Вы писали:

G>Вот он секрет низких процентов у Евгения.

Ну вот, ложечки нашлись. Вообще, безобразие с двумя версиями JIT всех, кто работает с числомолотилками порядком достало, особенно после таких вот багов
Автор: Sinix
Дата: 25.06.14
.
Ждём следующего релиза (который не 2015, а после него), наконец обещают общий код для всех целевых платформ. Хоть баги будут одинаковые, и то хлеб.



S>>Наглядная иллюстрация gc pressure и золотого правила "ежели один человек построил, другой завсегда разобрать может"


G>У меня был обратный опыт. Один деятель на работе решил, что если методов нет, то надо поменять class на struct. Он попросил меня помочь разобраться, почему у него чертовщина с разными значениями полей в разных местах начала твориться. Типа, вот смотри я поменял значение в методе, а в вызывающем методе они опять старые.

Re[25]: C# - from indians by indians
От: greenpci  
Дата: 05.06.15 13:00
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>А дело тут не в GC, а в постоянных cache miss'ах. Если на C++ сделать такой же memory layout — то точно также получим тормоза (подобный пример
Автор: Evgeny.Panasyuk
Дата: 18.10.14
).


А вот List, похоже, тормозит из-за проверки индекса, которую нельзя убрать, с помощью unsafe

        public T this[int index] {
#if !FEATURE_CORECLR
            [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
#endif
            get {
                // Following trick can reduce the range check by one
                if ((uint) index >= (uint)_size) {
                    ThrowHelper.ThrowArgumentOutOfRangeException();
                }
                Contract.EndContractBlock();
                return _items[index]; 
            }


Кстати, ты плюсный код 13й студией компилировал? У меня нету на машине, не могу проверить если есть разница.
Re[26]: C# - from indians by indians
От: Evgeny.Panasyuk Россия  
Дата: 05.06.15 13:45
Оценка: +1
Здравствуйте, greenpci, Вы писали:

EP>>А дело тут не в GC, а в постоянных cache miss'ах. Если на C++ сделать такой же memory layout — то точно также получим тормоза (подобный пример
Автор: Evgeny.Panasyuk
Дата: 18.10.14
).

G>А вот List, похоже, тормозит из-за проверки индекса, которую нельзя убрать, с помощью unsafe

Не думаю что из-за проверки индекса будет такая разница — branch predictor должен с ней неплохо справится. Желательно посмотреть какой там ASM получается.
На MSVC++ если использовать std::vector::at, внутри которого такая же проверка, то там разница на десятки процентов а не в разы.

G>Кстати, ты плюсный код 13й студией компилировал? У меня нету на машине, не могу проверить если есть разница.


Под рукой 2012.
Re[27]: C# - from indians by indians
От: Sinix  
Дата: 05.06.15 14:17
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Не думаю что из-за проверки индекса будет такая разница — branch predictor должен с ней неплохо справится. Желательно посмотреть какой там ASM получается.

+1. У меня разница между массивом и списком 60ms/88ms.

EP>На MSVC++ если использовать std::vector::at, внутри которого такая же проверка, то там разница на десятки процентов а не в разы.


Кстати, а есть возможность проверить плюсовый код отсюда
Автор: greenpci
Дата: 05.06.15
с дефолтными настройками проекта (console application)?

У меня какая-то ересь получается.
VS2013, релиз, win32, без отладчика на настройках проекта по умолчанию выдаёт
Elapsed = 189.011 ms


Чтоб собралось без особых вмешательств — убрал constexpr, отключил precompiled headers в настройках и убрал load_complex_sequence() (всё равно не используется).
Re[28]: C# - from indians by indians
От: Evgeny.Panasyuk Россия  
Дата: 05.06.15 15:15
Оценка: 2 (1)
Здравствуйте, Sinix, Вы писали:

EP>>Не думаю что из-за проверки индекса будет такая разница — branch predictor должен с ней неплохо справится. Желательно посмотреть какой там ASM получается.

S>+1. У меня разница между массивом и списком 60ms/88ms.

Это хорошо.

EP>>На MSVC++ если использовать std::vector::at, внутри которого такая же проверка, то там разница на десятки процентов а не в разы.

S>Кстати, а есть возможность проверить плюсовый код отсюда
Автор: greenpci
Дата: 05.06.15
с дефолтными настройками проекта (console application)?

S>У меня какая-то ересь получается.
S>VS2013, релиз, win32, без отладчика на настройках проекта по умолчанию выдаёт
S>
S>Elapsed = 189.011 ms
S>

S>Чтоб собралось без особых вмешательств — убрал constexpr, отключил precompiled headers в настройках и убрал load_complex_sequence() (всё равно не используется).

Я сделал тоже самое MSVS2012 — у меня на Sandy Bridge C++ 60ms (C# 69ms), на Nehalem C++ 84ms (C# 88ms)
Re[29]: C# - from indians by indians
От: Sinix  
Дата: 05.06.15 18:09
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Я сделал тоже самое MSVS2012 — у меня на Sandy Bridge C++ 60ms (C# 69ms), на Nehalem C++ 84ms (C# 88ms)

Sandy bridge тоже. Значит, проблема или в vs2013, или в /dev/hands. Второе вероятнее
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.