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

Сообщение Re[17]: C# - from indians by indians от 09.06.2015 9:29

Изменено 09.06.2015 9:31 Sinix

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


_>P.S. Естественно повторяющийся код можно было бы вынести в отдельную функцию (а особенно в C++ с его инлайном), но в разных языках (кстати тестировались не только C++/java/C#) с этим есть разные нюансы, так что для чистоты эксперимента везде оставлен одинаковый код в лоб.

C# версия (без фокусов с fixed, которые превращают C# в кривой аналог C) работает в 7 раз медленнее C++ кода.

В общем никаких 7 раз у меня нет. Что легко можно списать на моё незнание плюсов (что знал — успешно забыл)

1920*1080, 500 повторов, массив заполнен
image[i] = i % 321;

для проверки берём image[2000], чтоб не поломать ничего.

Для шарпа:
// x64
fast:  5744 ms,  res 256
orig: 10338 ms,  res 256

// x86
fast:  7422 ms,  res 256
orig: 13758 ms,  res 256


fast — просто перевёл на fixed()

Для плюсов (win32)
Run: 6586 ms, res:  256


VS 2013, со всеми обновлениями, релиз, без отладчика, настройки сборки для плюсов по умолчанию.
Кто померяет яву? Подозреваю, там тоже не 5 раз будет.

  код
код шарпа:
    static long Test(int[] image, int height, int count)
    {
        var sw = Stopwatch.StartNew();
        var buf=(int[])image.Clone();
        int width=image.Length/height;
        for(int n=0; n<count; n++){
            for(int y=1; y<height-1; y++){
                var p=width*y;
                for(int x=1; x<width-1; x++) if(image[p+x]!=0xffffff)
                    buf[p+x]=(image[p-width+x]+image[p+x-1]+image[p-width+x-1]+image[p-width+x+1]+image[p+width+x-1]+image[p+width+x]+image[p+x+1]+image[p+width+x+1])>>3;
            }
            for(int y=1; y<height-1; y++){
                var p=width*y;
                for(int x=1; x<width-1; x++) if(buf[p+x]!=0xffffff)
                    image[p+x]=(buf[p-width+x]+buf[p+x-1]+buf[p-width+x-1]+buf[p-width+x+1]+buf[p+width+x-1]+buf[p+width+x]+buf[p+x+1]+buf[p+width+x+1])>>3;
            }
        }
        sw.Stop();
        return sw.ElapsedMilliseconds;
    }

    static long Test2(int[] image, int height, int count)
    {
        var buf = (int[])image.Clone();
        var sw = Stopwatch.StartNew();

        for (int n = 0; n < count; n++)
        {
            AtoB(image, buf, height);
            AtoB(buf, image, height);
        }

        sw.Stop();
        return sw.ElapsedMilliseconds;
    }

    unsafe static void AtoB(int[] image, int[] buf, int height)
    {
        int width = image.Length / height;
        fixed (int* a = image, b = buf)
        {
            for (int y = 1; y < height - 1; y++)
            {
                var p = width * y;
                for (int x = 1; x < width - 1; x++)
                {
                    var idx = a + p + x;
                    var idx2 = b + p + x;
                    if (*idx != 0xffffff)
                    {
                        *idx2 = (
                            *(idx - width) + *(idx - 1) +
                            *(idx - width - 1) + *(idx - width + 1) +
                            *(idx + width - 1) + *(idx + width) +
                            *(idx + 1) + *(idx + width + 1)) >> 3;
                    }
                }
            }
        }
    }

    static void Main()
    {
        int[] image = new int[1920 * 1080];
        var rnd = new Random(0);
        for (int i = 0; i < image.Length; i++)
        {
            image[i] = i % 321;
        }
        int[] image2 = (int[])image.Clone();

        Console.WriteLine("Begin");
        long t;
        t = Test2(image, 1920, 500);
        Console.WriteLine("fast: {0} ms,\tres {1}", t, image[2000]);
        t = Test(image2, 1920, 500);
        Console.WriteLine("orig: {0} ms,\tres {1}", t, image2[2000]);

        Console.Write("Done.");
        Console.ReadKey();
    }


Для плюсов (да, он меня самого заставляет плакать кговавыми слезами):
int main()
{
    const int size = 1920 * 1080;
    const int height = 1920;
    const int count = 500;
    int* image = new int[size];
    for (int i1 = 0; i1 < size; i1++)
    {
        image[i1] = i1 % 321;
    }

    LARGE_INTEGER frequency;
    LARGE_INTEGER t1, t2;
    QueryPerformanceFrequency(&frequency);
    QueryPerformanceCounter(&t1);

    auto buf = image;
    const int width = size / height;
    for (int n = 0; n<count; n++){
        for (int y = 1; y<height - 1; y++){
            const auto s = image + y*width;
            const auto d = buf + y*width;
            for (int x = 1; x<width - 1; x++) if (s[x] != 0xffffff)
                d[x] = (s[-width + x] + s[x - 1] + s[-width + x - 1] + s[-width + x + 1] + s[width + x - 1] + s[width + x] + s[x + 1] + s[width + x + 1]) >> 3;
        }
        for (int y = 1; y<height - 1; y++){
            const auto s = buf + y*width;
            const auto d = image + y*width;
            for (int x = 1; x<width - 1; x++) if (s[x] != 0xffffff)
                d[x] = (s[-width + x] + s[x - 1] + s[-width + x - 1] + s[-width + x + 1] + s[width + x - 1] + s[width + x] + s[x + 1] + s[width + x + 1]) >> 3;
        }
    }
    QueryPerformanceCounter(&t2);
    std::cout << "Run: " << (int)((t2.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart) << " res:  " << buf[2000];

    delete[] image;
    return 0;
}
Re[17]: C# - from indians by indians
Здравствуйте, alex_public, Вы писали:


_>P.S. Естественно повторяющийся код можно было бы вынести в отдельную функцию (а особенно в C++ с его инлайном), но в разных языках (кстати тестировались не только C++/java/C#) с этим есть разные нюансы, так что для чистоты эксперимента везде оставлен одинаковый код в лоб.

C# версия (без фокусов с fixed, которые превращают C# в кривой аналог C) работает в 7 раз медленнее C++ кода.

В общем никаких 7 раз у меня нет. Что легко можно списать на моё незнание плюсов (что знал — успешно забыл)

1920*1080, 500 повторов, массив заполнен
image[i] = i % 321;

для проверки берём image[2000], чтоб не поломать ничего.

Для шарпа:
// x64
fast:  5744 ms,  res 256
orig: 10338 ms,  res 256

// x86
fast:  7422 ms,  res 256
orig: 13758 ms,  res 256


fast — просто перевёл на fixed()

Для плюсов (win32)
Run: 6586 ms, res:  256


VS 2013, со всеми обновлениями, релиз, без отладчика, настройки сборки для плюсов по умолчанию.
Кто померяет яву? Подозреваю, там тоже не 5 раз будет.

  код
код шарпа:
    static long Test(int[] image, int height, int count)
    {
        var sw = Stopwatch.StartNew();
        var buf=(int[])image.Clone();
        int width=image.Length/height;
        for(int n=0; n<count; n++){
            for(int y=1; y<height-1; y++){
                var p=width*y;
                for(int x=1; x<width-1; x++) if(image[p+x]!=0xffffff)
                    buf[p+x]=(image[p-width+x]+image[p+x-1]+image[p-width+x-1]+image[p-width+x+1]+image[p+width+x-1]+image[p+width+x]+image[p+x+1]+image[p+width+x+1])>>3;
            }
            for(int y=1; y<height-1; y++){
                var p=width*y;
                for(int x=1; x<width-1; x++) if(buf[p+x]!=0xffffff)
                    image[p+x]=(buf[p-width+x]+buf[p+x-1]+buf[p-width+x-1]+buf[p-width+x+1]+buf[p+width+x-1]+buf[p+width+x]+buf[p+x+1]+buf[p+width+x+1])>>3;
            }
        }
        sw.Stop();
        return sw.ElapsedMilliseconds;
    }

    static long Test2(int[] image, int height, int count)
    {
        var sw = Stopwatch.StartNew();
        var buf = (int[])image.Clone();

        for (int n = 0; n < count; n++)
        {
            AtoB(image, buf, height);
            AtoB(buf, image, height);
        }

        sw.Stop();
        return sw.ElapsedMilliseconds;
    }

    unsafe static void AtoB(int[] image, int[] buf, int height)
    {
        int width = image.Length / height;
        fixed (int* a = image, b = buf)
        {
            for (int y = 1; y < height - 1; y++)
            {
                var p = width * y;
                for (int x = 1; x < width - 1; x++)
                {
                    var idx = a + p + x;
                    var idx2 = b + p + x;
                    if (*idx != 0xffffff)
                    {
                        *idx2 = (
                            *(idx - width) + *(idx - 1) +
                            *(idx - width - 1) + *(idx - width + 1) +
                            *(idx + width - 1) + *(idx + width) +
                            *(idx + 1) + *(idx + width + 1)) >> 3;
                    }
                }
            }
        }
    }

    static void Main()
    {
        int[] image = new int[1920 * 1080];
        var rnd = new Random(0);
        for (int i = 0; i < image.Length; i++)
        {
            image[i] = i % 321;
        }
        int[] image2 = (int[])image.Clone();

        Console.WriteLine("Begin");
        long t;
        t = Test2(image, 1920, 500);
        Console.WriteLine("fast: {0} ms,\tres {1}", t, image[2000]);
        t = Test(image2, 1920, 500);
        Console.WriteLine("orig: {0} ms,\tres {1}", t, image2[2000]);

        Console.Write("Done.");
        Console.ReadKey();
    }


Для плюсов (да, он меня самого заставляет плакать кговавыми слезами):
int main()
{
    const int size = 1920 * 1080;
    const int height = 1920;
    const int count = 500;
    int* image = new int[size];
    for (int i1 = 0; i1 < size; i1++)
    {
        image[i1] = i1 % 321;
    }

    LARGE_INTEGER frequency;
    LARGE_INTEGER t1, t2;
    QueryPerformanceFrequency(&frequency);
    QueryPerformanceCounter(&t1);

    auto buf = image;
    const int width = size / height;
    for (int n = 0; n<count; n++){
        for (int y = 1; y<height - 1; y++){
            const auto s = image + y*width;
            const auto d = buf + y*width;
            for (int x = 1; x<width - 1; x++) if (s[x] != 0xffffff)
                d[x] = (s[-width + x] + s[x - 1] + s[-width + x - 1] + s[-width + x + 1] + s[width + x - 1] + s[width + x] + s[x + 1] + s[width + x + 1]) >> 3;
        }
        for (int y = 1; y<height - 1; y++){
            const auto s = buf + y*width;
            const auto d = image + y*width;
            for (int x = 1; x<width - 1; x++) if (s[x] != 0xffffff)
                d[x] = (s[-width + x] + s[x - 1] + s[-width + x - 1] + s[-width + x + 1] + s[width + x - 1] + s[width + x] + s[x + 1] + s[width + x + 1]) >> 3;
        }
    }
    QueryPerformanceCounter(&t2);
    std::cout << "Run: " << (int)((t2.QuadPart - t1.QuadPart) * 1000.0 / frequency.QuadPart) << " res:  " << buf[2000];

    delete[] image;
    return 0;
}