Berikut adalah kutipan dari program yang dimaksud. Matriks img[][]
memiliki ukuran SIZE × SIZE, dan diinisialisasi pada:
img[j][i] = 2 * j + i
Kemudian, Anda membuat matriks res[][]
, dan setiap bidang di sini dibuat menjadi rata-rata dari 9 bidang di sekitarnya dalam matriks img. Batas dibiarkan pada 0 untuk kesederhanaan.
for(i=1;i<SIZE-1;i++)
for(j=1;j<SIZE-1;j++) {
res[j][i]=0;
for(k=-1;k<2;k++)
for(l=-1;l<2;l++)
res[j][i] += img[j+l][i+k];
res[j][i] /= 9;
}
Itu semua ada untuk program ini. Demi kelengkapan, inilah yang terjadi sebelumnya. Tidak ada kode yang muncul setelahnya. Seperti yang Anda lihat, itu hanya inisialisasi.
#define SIZE 8192
float img[SIZE][SIZE]; // input image
float res[SIZE][SIZE]; //result of mean filter
int i,j,k,l;
for(i=0;i<SIZE;i++)
for(j=0;j<SIZE;j++)
img[j][i] = (2*j+i)%8196;
Pada dasarnya, program ini lambat ketika SIZE adalah kelipatan 2048, misalnya waktu eksekusi:
SIZE = 8191: 3.44 secs
SIZE = 8192: 7.20 secs
SIZE = 8193: 3.18 secs
Kompilernya adalah GCC. Dari apa yang saya tahu, ini karena manajemen memori, tetapi saya tidak terlalu tahu banyak tentang subjek itu, itulah sebabnya saya bertanya di sini.
Juga cara memperbaikinya akan menyenangkan, tetapi jika seseorang dapat menjelaskan waktu eksekusi ini saya sudah cukup senang.
Saya sudah tahu tentang malloc / gratis, tetapi masalahnya bukan jumlah memori yang digunakan, ini hanya waktu eksekusi, jadi saya tidak tahu bagaimana itu akan membantu.
sumber
Jawaban:
Perbedaan ini disebabkan oleh masalah super-alignment yang sama dari pertanyaan terkait berikut:
Tapi itu hanya karena ada satu masalah lain dengan kode.
Mulai dari loop asli:
Pertama perhatikan bahwa dua loop dalam itu sepele. Mereka dapat dibuka gulungannya sebagai berikut:
Sehingga menyisakan dua loop luar yang kami minati.
Sekarang kita dapat melihat masalahnya adalah sama dalam pertanyaan ini: Mengapa urutan loop mempengaruhi kinerja ketika iterasi melalui array 2D?
Anda iterasi matriks kolom-bijaksana bukan baris-bijaksana.
Untuk mengatasi masalah ini, Anda harus menukar kedua loop.
Ini menghilangkan semua akses non-sekuensial sepenuhnya sehingga Anda tidak lagi mendapatkan perlambatan acak pada kekuatan besar dua.
Core i7 920 @ 3.5 GHz
Kode asli:
Loop Luar Tertukar:
sumber
Tes-tes berikut telah dilakukan dengan kompiler Visual C ++ seperti yang digunakan oleh instalasi Qt Creator default (saya kira tanpa flag optimasi). Saat menggunakan GCC, tidak ada perbedaan besar antara versi Mystical dan kode saya "dioptimalkan". Jadi kesimpulannya adalah bahwa optimasi kompiler merawat optimasi mikro lebih baik daripada manusia (akhirnya saya). Saya meninggalkan sisa jawaban saya untuk referensi.
Tidak efisien untuk memproses gambar dengan cara ini. Lebih baik menggunakan array dimensi tunggal. Memproses semua piksel dilakukan dalam satu loop. Akses acak ke titik dapat dilakukan dengan menggunakan:
Dalam kasus khusus ini, lebih baik untuk menghitung dan menyimpan jumlah tiga kelompok piksel secara horizontal karena masing-masing digunakan tiga kali.
Saya telah melakukan beberapa tes dan saya pikir ini layak untuk dibagikan. Setiap hasil adalah rata-rata dari lima tes.
Kode asli oleh user1615209:
Versi mistik:
Dua lintasan menggunakan larik 1D: lintasan pertama untuk jumlah horizontal, kedua lintasan untuk jumlah vertikal dan rata-rata. Two pass addressing dengan tiga pointer dan hanya penambahan seperti ini:
Dua pass menggunakan array 1D dan menangani seperti ini:
Satu lulus caching jumlah horisontal hanya satu baris di depan sehingga mereka tetap di cache:
Kesimpulan:
Saya yakin itu mungkin dilakukan jauh lebih baik.
CATATAN Tolong, perhatikan bahwa saya menulis jawaban ini untuk menargetkan masalah kinerja umum daripada masalah cache yang dijelaskan dalam jawaban Mystical yang sangat baik. Pada awalnya itu hanya kode semu. Saya diminta untuk melakukan tes di komentar ... Ini adalah versi yang sepenuhnya di-refactored dengan tes.
sumber