OpenMp: cara memastikan setiap thread berfungsi minimal 1 iterasi dalam penjadwalan dinamis

Saya menggunakan penjadwalan dinamis untuk iterasi loop. Namun ketika pekerjaan di setiap iterasi terlalu kecil, beberapa thread tidak berfungsi atau ketika jumlah thread sangat banyak. Misalnya. Ada 100 iterasi dan ada 90 thread, saya ingin setiap thread melakukan minimal satu iterasi dan 10 iterasi sisanya bisa dibagikan ke thread yang sudah melakukan tugasnya. Bagaimana saya bisa melakukan itu?


person nanda    schedule 29.02.2020    source sumber


Jawaban (1)


Anda tidak dapat memaksa runtime OpenMP untuk melakukan hal ini. Namun, Anda dapat memberikan petunjuk kepada runtime OpenMP sehingga kemungkinan akan melakukan hal tersebut ketika (diputuskan bahwa) hal tersebut dimungkinkan dengan biaya overhead yang lebih tinggi. Caranya adalah dengan menentukan granularitas loop yang dijadwalkan secara dinamis. Berikut ini contohnya:

#pragma omp parallel for schedule(dynamic,1)
for(int i=0 ; i<100 ; ++i)
    compute(i);

Dengan kode seperti itu, runtime bebas membagi pekerjaan secara merata antar thread (menggunakan penjadwal pembagian kerja) atau membiarkan thread mencuri pekerjaan dari thread master yang menggerakkan komputasi paralel (menggunakan penjadwal pencurian pekerjaan). Pada pendekatan kedua, meskipun granularitasnya adalah 1 iterasi perulangan, beberapa thread dapat mencuri lebih banyak pekerjaan daripada yang sebenarnya dibutuhkan (mis. untuk umumnya meningkatkan kinerja). Jika perulangan loop cukup cepat, pekerjaan mungkin tidak akan seimbang antar thread.

Membuat 90 thread membutuhkan biaya yang mahal dan mengirimkan pekerjaan ke 90 thread juga jauh dari kata gratis karena sebagian besar dibatasi oleh latensi operasi atom yang relatif tinggi, salabilitasnya, serta latensi thread yang aktif. Selain itu, meskipun operasi tersebut tampak sinkron dari sudut pandang pengguna, hal ini tidak terjadi dalam praktiknya (terutama dengan 90 thread dan pada arsitektur berbasis multi-soket NUMA). Akibatnya, beberapa thread mungkin selesai menghitung satu iterasi dari loop sementara yang lain mungkin tidak mengetahui komputasi paralel atau bahkan belum dibuat. Biaya overhead untuk membuat thread menyadari komputasi yang harus dilakukan umumnya bertambah seiring dengan bertambahnya jumlah thread yang digunakan. Dalam beberapa kasus, overhead ini bisa lebih tinggi dari komputasi sebenarnya dan akan lebih efisien jika menggunakan lebih sedikit thread.

Pengembang runtime OpenMP terkadang harus menyeimbangkan pekerjaan dengan overhead komunikasi yang lebih kecil. Oleh karena itu, keputusan tersebut dapat berdampak buruk pada kasus Anda, namun dapat meningkatkan kelayakan aplikasi jenis lain. Hal ini terutama berlaku pada penjadwal yang mencuri pekerjaan (mis. runtime Clang/ICC OpenMP). Perhatikan bahwa peningkatan skalabilitas runtime OpenMP adalah bidang penelitian yang sedang berlangsung.

Saya menyarankan Anda untuk mencoba beberapa runtime OpenMP (termasuk runtime penelitian yang mungkin baik atau tidak baik untuk digunakan dalam kode produksi). Anda juga dapat bermain-main dengan variabel OMP_WAIT_POLICY untuk mengurangi biaya tambahan saat bangun benang. Anda juga dapat mencoba menggunakan tugas OpenMP untuk memaksa runtime lebih banyak agar tidak menggabungkan iterasi. Saya juga menyarankan Anda untuk membuat profil kode Anda untuk melihat apa yang terjadi dan menemukan potensi hambatan perangkat lunak/perangkat keras.

Memperbarui

Jika Anda menggunakan lebih banyak thread OpenMP daripada jumlah thread perangkat keras di mesin Anda, prosesor tidak dapat mengeksekusinya secara bersamaan (hanya dapat mengeksekusi satu thread OpenMP pada setiap thread perangkat keras). Akibatnya, sistem operasi pada mesin Anda menjadwalkan thread OpenMP pada thread perangkat keras sehingga tampaknya dijalankan secara bersamaan dari sudut pandang pengguna. Namun, keduanya tidak berjalan secara bersamaan, namun dieksekusi dengan cara disisipkan dalam kuantum waktu yang sangat kecil (misalnya 100 ms).

Misalnya, jika Anda memiliki prosesor dengan 8 thread perangkat keras dan Anda menggunakan 8 thread OpenMP, secara kasar Anda dapat berasumsi bahwa thread tersebut akan berjalan secara bersamaan. Namun jika Anda menggunakan 16 thread OpenMP, sistem operasi Anda dapat memilih untuk menjadwalkannya menggunakan cara berikut:

  • 8 thread pertama dieksekusi selama 100 ms;
  • 8 thread terakhir dieksekusi selama 100 ms;
  • 8 thread pertama dieksekusi lagi selama 100 ms;
  • 8 thread terakhir dieksekusi lagi selama 100 ms;
  • dll.

Jika komputasi Anda berlangsung kurang dari 100 ms, penjadwal dinamis/terpandu OpenMP akan memindahkan pekerjaan dari 8 thread terakhir ke 8 thread pertama sehingga waktu eksekusi keseluruhan akan lebih cepat. Akibatnya, 8 thread pertama dapat menjalankan semua pekerjaan dan 8 thread terakhir tidak akan memiliki apa pun untuk dieksekusi setelahnya. Hal inilah yang menyebabkan terjadinya ketidakseimbangan kerja antar thread.

Jadi, jika Anda ingin mengukur kinerja program OpenMP, Anda TIDAK boleh menggunakan lebih banyak thread OpenMP daripada thread perangkat keras (kecuali Anda benar-benar mengetahui apa yang Anda lakukan dan sepenuhnya menyadari efek tersebut).

person Jérôme Richard    schedule 29.02.2020
comment
Saya menggunakan pendekatan pertama dan tidak berfungsi seperti yang diharapkan. Beberapa thread tidak berfungsi. Saya memeriksa yang mana yang berfungsi dan hasilnya membingungkan saya. Misalnya. utas 1,2,5,10,88 hanya berfungsi. Jika hasilnya thread 1,2,3,4,5 hanya berfungsi pada 90 thread, saya berasumsi pekerjaan sudah selesai sebelum semua thread dibuat. Dan memang benar bahwa lebih banyak thread tidak berarti runtime lebih cepat. Yang saya inginkan adalah membandingkan ukuran thread perbedaan runtime. misalnya jalankan program dengan 1 thread, jalankan program dengan 2 thread.... maksimal 100 thread (sebanyak iterasinya). Sehingga saya bisa membandingkan runtime. - person nanda; 29.02.2020
comment
Apa hasil std::thread::hardware_concurrency() di mesin Anda? - person Jérôme Richard; 29.02.2020
comment
Ketika saya berlari, jam sudah menunjukkan pukul 8. - person nanda; 01.03.2020
comment
Saya telah menemukan jika saya memasukkan nomor utas lebih dari 8, hanya 8 utas yang berfungsi baik dalam penjadwalan dinamis dan terpandu. Namun dalam penjadwalan statis, semua thread berfungsi. Bagaimana hal itu terjadi? - person nanda; 01.03.2020
comment
Jawabannya telah diperbarui untuk mempertimbangkan informasi ini. - person Jérôme Richard; 01.03.2020