Membandingkan Kinerja C # dan C ++ untuk Tugas Pemrosesan Gambar

Ada pendapat bahwa C # tidak memiliki tempat dalam tugas komputasi, dan pendapat ini cukup dibenarkan: kompiler JIT dipaksa untuk mengkompilasi dan mengoptimalkan kode dengan cepat selama eksekusi program dengan penundaan minimal, ia tidak memiliki kesempatan untuk menghabiskan lebih banyak sumber daya komputasi untuk menghasilkan kode yang lebih efisien , berbeda dengan compiler C ++, yang dapat memerlukan waktu beberapa menit bahkan berjam-jam untuk masalah ini.





Namun, dalam beberapa tahun terakhir, efisiensi compiler JIT telah meningkat secara nyata, dan sejumlah chip yang berguna telah dimasukkan ke dalam framework itu sendiri, misalnya, intrinsics .





Dan kemudian saya bertanya-tanya: apakah mungkin pada tahun 2020, menggunakan .NET 5.0, untuk menulis kode yang kinerjanya tidak akan jauh lebih rendah daripada C ++? Ternyata Anda bisa.





Motivasi

Saya terlibat dalam pengembangan algoritme pemrosesan gambar, dan pada level yang cukup rendah. Artinya, ini tidak menyulap batu bata dengan Python, tetapi mengembangkan sesuatu yang baru dan, lebih disukai, produktif. Kode Python membutuhkan waktu yang sangat lama, sementara menggunakan C ++ menyebabkan penurunan kecepatan pengembangan. Keseimbangan optimal antara produktivitas dan kinerja untuk tugas-tugas semacam itu dicapai dengan menggunakan C # dan Java. Sebagai konfirmasi atas kata-kata saya - proyek Fiji .





Sebelumnya, saya menggunakan C # untuk pembuatan prototipe, dan saya menulis ulang algoritme siap pakai yang sangat penting untuk kinerja di C ++, memasukkannya ke dalam lib dan menarik lib dari C #. Tetapi dalam kasus ini, portabilitas menderita, dan sangat tidak nyaman untuk men-debug kode.





, .NET , , C++ C#?





: , , , . C++. .





, , C# C++:





  • GetPixel(x, y) SetPixel(x, y, value);





  • ;





  • (AVX).





(Array.Sort, std::sort), , , , . .





, , C# unmanaged - . - , C++ UB , C# - .





Github, , C#:





[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public static void Sum_ThisProperty(NativeImage<float> img1, NativeImage<float> img2, NativeImage<float> res)
{
    for (var j = 0; j < res.Height; j++)
    for (var i = 0; i < res.Width; i++)
        res[i, j] = img1[i, j] + img2[i, j];
}

[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public static void Sum_Optimized(NativeImage<float> img1, NativeImage<float> img2, NativeImage<float> res)
{
    var w = res.Width;

    for (var j = 0; j < res.Height; j++)
    {
        var p1 = img1.PixelAddr(0, j);
        var p2 = img2.PixelAddr(0, j);
        var r = res.PixelAddr(0, j);

        for (var i = 0; i < w; i++)
            r[i] = p1[i] + p2[i];
    }
}

[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public static void Sum_Avx(NativeImage<float> img1, NativeImage<float> img2, NativeImage<float> res)
{
    var w8 = res.Width / 8 * 8;

    for (var j = 0; j < res.Height; j++)
    {
        var p1 = img1.PixelAddr(0, j);
        var p2 = img2.PixelAddr(0, j);
        var r = res.PixelAddr(0, j);

        for (var i = 0; i < w8; i += 8)
        {
            Avx.StoreAligned(r, Avx.Add(Avx.LoadAlignedVector256(p1), Avx.LoadAlignedVector256(p2)));

            p1 += 8;
            p2 += 8;
            r += 8;
        }
        
        for (var i = w8; i < res.Width; i++)
            *r++ = *p1++ + *p2++;
    }
}

      
      







. (1/10 ) 256x256 float 32 bit.









dotnet build -c Release





g++ 10.2.0 -O0





g++ 10.2.0 -O1





g++ 10.2.0 -O2





g++ 10.2.0 -O3





clang 11.0.0 -O2





clang 11.0.0 -O3





Sum (naive)





115.8





757.6





124.4





36.26





19.51





20.14





19.81





Sum (opt)





40.69





255.6





36.07





24.48





19.60





20.11





19.81





Sum (avx)





21.15





60.41





20.00





20.18





20.37





20.23





20.20





Rotate (naive)





90.29





500.3





87.15





36.01





14.49





14.04





14.16





Rotate (opt)





34.99





237.1





35.11





34.17





14.55





14.10





14.27





Rotate (avx)





14.83





51.04





14.14





14.25





14.37





14.22





14.72





Median 3x3





4163





26660





2930





1607





2508





2301





2330





Median 5x5





11550





10090





8240





5554





5870





5610





6051





Median 7x7





23540





24470





17540





13640





12620





12920





13510





Convolve 7x7 (naive)





5519





30900





3240





3694





2775





3047





2761





Convolve 7x7 (opt)





2913





11780





2759





2628





2754





2434





2262





Convolve 7x7 (avx)





709.2





3759





729.8





669.8





684.2





643.8





638.3





Convolve 7x7 (avx*)





505.6





2984





523.4





511.5





507.8





443.2





443.3





: Convolve 7x7 (avx*) - , , .





Core i7-2600K @ 4.0 GHz.





:





  • (avx), C#, , C++. , C# !





  • C# , C# , C++ .





  • C# C++ 2 6 . .





, C# , C++. : , C++ , C# . C#, C++.





P.S. .NET - - . (, ), C++ , , , C# , .












All Articles