Информация об изменениях

Сообщение Re[9]: 2D-Linq и оптимизация цифровых фильтров - 3 от 03.07.2018 9:10

Изменено 03.07.2018 9:31 vdimas

Re[9]: 2D-Linq и оптимизация цифровых фильтров - 3
Здравствуйте, Sinclair, Вы писали:

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

V>>Напиши один раз "библиотечный" индексер и пользуйся.
S>Жду пример кода C4 фильтрации на основе "библиотечного" индексера.

Вдогонку, расширил пример на новомодный Span (который сам по себе уже абстрактный индексер).
Заодно из Span<T> легко получить unsafe, поэтому прогнал и его тоже.
Выходит, он удобен сугубо для получения slice-ов из произвольного участка managed или unmanaged памяти, разве что с последующим приведением к unsafe. ))

  Дополнительный код
    unsafe readonly ref struct SpanIndexer2D<T>
    {
        public Span<T> array { get; }
        public int dx { get; }
        public int dy { get; }

        public SpanIndexer2D(int dx, int dy)
        {
            this.dx = dx;
            this.dy = dy;
            array = new T[dx * dy];
        }

        public T this[int x, int y]
        {
            get => array[dx * y + x];
            set => array[dx * y + x] = value;
        }
    }

    unsafe readonly ref struct UnsafeIntArray2D
    {
        private readonly int* _array;
        public int dx { get; }
        public int dy { get; }

        public UnsafeIntArray2D(int* array, int dx, int dy)
        {
            this.dx = dx;
            this.dy = dy;
            _array = array;
        }

        public int this[int x, int y]
        {
            get => _array[dx * y + x];
            set => _array[dx * y + x] = value;
        }
    }

//...

        static void SpanTest()
        {
            int dx = 1000, dy = 1000;
            var array = new SpanIndexer2D<int>(dx, dy);

            int sum = 0;

            var rnd = new Random((int)DateTime.Now.TimeOfDay.Ticks);

            for (int x = 0; x < array.dx; x++)
                for (int y = 0; y < array.dy; y++)
                    array[x, y] = rnd.Next();

            Stopwatch sw = new Stopwatch();
            sw.Start();

            for (int i = 0; i < 1000; i++)
            {
                for (int x = 0; x < dx; x++)
                    for (int y = 0; y < dy; y++)
                        sum += array[x, y];
            }

            sw.Stop();

            Console.WriteLine("Elapsed(ms)={0}", sw.Elapsed);
        }

        static unsafe void UnsafeTest()
        {
            int dx = 1000, dy = 1000;
            var indexer = new SpanIndexer2D<int>(dx, dy);

            fixed (int* intArray = indexer.array)
            {
                var array = new UnsafeIntArray2D(intArray, dx, dy);

                int sum = 0;

                var rnd = new Random((int)DateTime.Now.TimeOfDay.Ticks);

                for (int x = 0; x < array.dx; x++)
                    for (int y = 0; y < array.dy; y++)
                        array[x, y] = rnd.Next();

                Stopwatch sw = new Stopwatch();
                sw.Start();

                for (int i = 0; i < 1000; i++)
                {
                    for (int x = 0; x < dx; x++)
                        for (int y = 0; y < dy; y++)
                            sum += array[x, y];
                }

                sw.Stop();

                Console.WriteLine("Elapsed(ms)={0}", sw.Elapsed);
            }
        }

Результаты:
Native 2D array: Elapsed(ms)=00:00:00.7712649
Emulated 2D array: Elapsed(ms)=00:00:00.6893393
Span 2D array: Elapsed(ms)=00:00:00.9882120
Unsafe 2D array: Elapsed(ms)=00:00:00.5858264
Re[9]: 2D-Linq и оптимизация цифровых фильтров - 3
Здравствуйте, Sinclair, Вы писали:

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

V>>Напиши один раз "библиотечный" индексер и пользуйся.
S>Жду пример кода C4 фильтрации на основе "библиотечного" индексера.

Вдогонку, расширил пример на новомодный Span (который сам по себе уже абстрактный индексер).
Заодно из Span<T> легко получить unsafe, поэтому прогнал и его тоже.
Выходит, он удобен сугубо для получения slice-ов из произвольного участка managed или unmanaged памяти, разве что с последующим приведением к unsafe. ))

  Дополнительный код
    unsafe readonly ref struct SpanIndexer2D<T>
    {
        public Span<T> array { get; }
        public int dx { get; }
        public int dy { get; }

        public SpanIndexer2D(int dx, int dy)
        {
            this.dx = dx;
            this.dy = dy;
            array = new T[dx * dy];
        }

        public T this[int x, int y]
        {
            get => array[dx * y + x];
            set => array[dx * y + x] = value;
        }
    }

    unsafe readonly ref struct UnsafeIntArray2D
    {
        private readonly int* _array;
        public int dx { get; }
        public int dy { get; }

        public UnsafeIntArray2D(int* array, int dx, int dy)
        {
            this.dx = dx;
            this.dy = dy;
            _array = array;
        }

        public int this[int x, int y]
        {
            get => _array[dx * y + x];
            set => _array[dx * y + x] = value;
        }
    }

//...

        static void SpanTest()
        {
            int dx = 1000, dy = 1000;
            var array = new SpanIndexer2D<int>(dx, dy);

            int sum = 0;

            var rnd = new Random((int)DateTime.Now.TimeOfDay.Ticks);

            for (int x = 0; x < array.dx; x++)
                for (int y = 0; y < array.dy; y++)
                    array[x, y] = rnd.Next();

            Stopwatch sw = new Stopwatch();
            sw.Start();

            for (int i = 0; i < 1000; i++)
            {
                for (int x = 0; x < dx; x++)
                    for (int y = 0; y < dy; y++)
                        sum += array[x, y];
            }

            sw.Stop();

            Console.WriteLine("Elapsed(ms)={0}", sw.Elapsed);
        }

        static unsafe void UnsafeTest()
        {
            int dx = 1000, dy = 1000;
            var indexer = new SpanIndexer2D<int>(dx, dy);

            fixed (int* intArray = indexer.array)
            {
                var array = new UnsafeIntArray2D(intArray, dx, dy);

                int sum = 0;

                var rnd = new Random((int)DateTime.Now.TimeOfDay.Ticks);

                for (int x = 0; x < array.dx; x++)
                    for (int y = 0; y < array.dy; y++)
                        array[x, y] = rnd.Next();

                Stopwatch sw = new Stopwatch();
                sw.Start();

                for (int i = 0; i < 1000; i++)
                {
                    for (int x = 0; x < dx; x++)
                        for (int y = 0; y < dy; y++)
                            sum += array[x, y];
                }

                sw.Stop();

                Console.WriteLine("Elapsed(ms)={0}", sw.Elapsed);
            }
        }

Результаты:
Native 2D array: Elapsed(ms)=00:00:00.7712649
Emulated 2D array: Elapsed(ms)=00:00:00.6893393
Span 2D array: Elapsed(ms)=00:00:00.9882120
Unsafe 2D array: Elapsed(ms)=00:00:00.5858264


Upd. Перегнал релизный выхлоп в нейтив посредством NetNative, результаты те же.
Мде...