Pertanyaan Apakah ada solusi untuk batas inline C # 28-kali?


Saya sedang bekerja untuk mengoptimalkan program simulasi fisika menggunakan Performanceer Profil Red Gate. Salah satu bagian dari kode yang berhubungan dengan deteksi tabrakan memiliki sekitar 52 cek kecil berikut, berurusan dengan sel di 26 arah dalam 3 dimensi, di bawah dua kasus.

CollisionPrimitiveList cell = innerGrid[cellIndex + 1];
if (cell.Count > 0)
    contactsMade += collideWithCell(obj, cell, data, ref attemptedContacts);

cell = innerGrid[cellIndex + grid.XExtent];
if (cell.Count > 0)
    contactsMade += collideWithCell(obj, cell, data, ref attemptedContacts);

cell = innerGrid[cellIndex + grid.XzLayerSize];
if (cell.Count > 0)
    contactsMade += collideWithCell(obj, cell, data, ref attemptedContacts);

Sebagai lingkaran yang sangat ketat dari program ini, semua ini harus dalam metode yang sama, tetapi saya menemukan bahwa, tiba-tiba, setelah saya memperluas area dari dua dimensi ke tiga dimensi (naik hitungan ke 52 cek dari 16), tiba-tiba sel.Count tidak lagi digarisbawahi, meskipun itu adalah pengambil yang sederhana. public int Count { get { return count; } } Hal ini menyebabkan hit kinerja yang luar biasa, dan saya butuh waktu yang cukup lama untuk menemukan bahwa, ketika cell.Count muncul dalam metode 28 kali atau kurang, itu digariskan setiap kali, tetapi sekali cell.Count muncul dalam metode 29 kali atau lebih , itu tidak inlined satu kali (meskipun sebagian besar panggilan berasal dari bagian skenario terburuk dari kode yang jarang dieksekusi.)

Jadi kembali ke pertanyaan saya, apakah ada yang punya ide untuk mengatasi batas ini? Saya pikir solusi mudahnya hanyalah membuat bidang hitung bersifat internal dan bukan pribadi, tetapi saya ingin solusi yang lebih baik dari ini, atau setidaknya hanya pemahaman yang lebih baik tentang situasi. Saya berharap hal semacam ini akan disebutkan di laman Aplikasi Pengelolaan Tinggi Kinerja Penulisan Microsoft di http://msdn.microsoft.com/en-us/library/ms973858.aspx tapi sayangnya itu tidak (mungkin karena bagaimana sewenang-wenang batas jumlah 28 adalah?)

Saya menggunakan .NET 4.0.

EDIT: Sepertinya saya salah menafsirkan pengujian kecil saya. Saya menemukan bahwa kegagalan untuk inline disebabkan bukan oleh metode itu sendiri yang disebut sekitar 28+ kali, tetapi karena metode yang seharusnya mereka lakukan adalah "terlalu panjang" oleh beberapa standar. Ini masih membingungkan saya, karena saya tidak melihat bagaimana seorang pengambil yang sederhana bisa secara rasional tidak inline (dan kinerja secara signifikan lebih baik dengan mereka digarisbawahi sebagai profiler saya jelas menunjukkan saya), tetapi rupanya compiler CLI JIT menolak untuk inline apa saja hanya karena metode ini sudah besar (bermain-main dengan sedikit variasi menunjukkan kepada saya bahwa batas ini adalah ukuran kode (dari idasm) 1500, di atas itu tidak ada penyisipan yang dilakukan, bahkan dalam kasus getter saya, yang beberapa pengujian menunjukkan tidak menambahkan kode tambahan overhead untuk digarisbawahi).

Terima kasih.


32
2018-04-27 07:48


asal


Jawaban:


Saya belum menguji ini, tetapi sepertinya satu solusi yang mungkin adalah memiliki beberapa properti yang semuanya mengembalikan hal yang sama. Bisa dibayangkan Anda bisa mendapatkan 28 inlines per properti.

Perhatikan bahwa berapa kali metode inlined kemungkinan besar tergantung pada ukuran kode asli untuk metode itu (Lihat http://blogs.msdn.com/b/vancem/archive/2008/08/19/to-inline-or-not-to-inline-that-is-the-question.aspx), nomor 28 khusus untuk properti yang satu itu. Sebuah properti sederhana kemungkinan akan mendapatkan lebih banyak kali daripada metode yang lebih kompleks.


4
2018-04-27 09:58



Langsung off, ini tidak menjelaskan mengapa 28 adalah angka ajaib, tapi aku ingin tahu apa yang akan terjadi jika Anda menyusun semua kandidat Anda CollisionListPrimitive instance ke dalam array, dan kemudian memanggil blok "if count> 0" Anda dalam satu lingkaran dari array?

Apakah panggilan cell.Count kemudian dibuat inline lagi?

misalnya

CollisionPrimitiveList[] cells = new CollisionPrimitiveList {
    innerGrid[cellIndex + 1],
    innerGrid[cellIndex + grid.XExtent],
    innerGrid[cellIndex + grid.XzLayerSize]
    // and all the rest
};

// Loop over cells - for demo only. Use for loop or LINQ'ify if faster
foreach (CollisionPrimitiveList cell in cells) 
{
    if (cell.Count > 0)
        contactsMade += collideWithCell(obj, cell, data, ref attemptedContacts);  
}

Saya tahu kinerja adalah masalah, dan Anda akan memiliki overhead membangun array dan looping melalui itu, tetapi jika sel.Count adalah inline lagi, mungkin kinerja masih lebih baik / cukup baik secara keseluruhan?


1
2018-04-27 10:07



Saya menduga (meskipun tidak positif) bahwa ini mungkin harus dilakukan dengan enregistration masalah yang disebutkan - mungkin bahwa CLR mengalokasikan variabel baru untuk setiap pernyataan if, dan bahwa mereka melebihi total 64 variabel. Apakah Anda pikir ini mungkin terjadi?


0
2018-04-28 07:21