<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.haidhi.my.id/wiki/index.php?action=history&amp;feed=atom&amp;title=OpenMP%3A_Parallel_For_%26_Scheduling</id>
	<title>OpenMP: Parallel For &amp; Scheduling - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.haidhi.my.id/wiki/index.php?action=history&amp;feed=atom&amp;title=OpenMP%3A_Parallel_For_%26_Scheduling"/>
	<link rel="alternate" type="text/html" href="https://wiki.haidhi.my.id/wiki/index.php?title=OpenMP:_Parallel_For_%26_Scheduling&amp;action=history"/>
	<updated>2026-11-01T21:44:10Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.0</generator>
	<entry>
		<id>https://wiki.haidhi.my.id/wiki/index.php?title=OpenMP:_Parallel_For_%26_Scheduling&amp;diff=796&amp;oldid=prev</id>
		<title>SanzSkuy: Created page with &quot;&#039;&#039;&#039;&lt;code&gt;#pragma omp parallel for&lt;/code&gt;&#039;&#039;&#039; adalah konstruksi OpenMP yang paling sering dipakai: satu baris pragma yang membagi iterasi loop ke banyak thread. Artikel ini membahas cara kerjanya, aturan data sharing, dan yang paling sering disepelekan padahal menentukan performa: &#039;&#039;&#039;kebijakan scheduling&#039;&#039;&#039; — siapa mengerjakan iterasi yang mana.  Prasyarat: OpenMP: Setup &amp; Hello World. Semua contoh di sini di-compile dengan:  &lt;pre&gt; g++ -O2 -fopenmp -o program program...&quot;</title>
		<link rel="alternate" type="text/html" href="https://wiki.haidhi.my.id/wiki/index.php?title=OpenMP:_Parallel_For_%26_Scheduling&amp;diff=796&amp;oldid=prev"/>
		<updated>2026-07-11T06:10:44Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;&amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;#pragma omp parallel for&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; adalah konstruksi OpenMP yang paling sering dipakai: satu baris pragma yang membagi iterasi loop ke banyak thread. Artikel ini membahas cara kerjanya, aturan data sharing, dan yang paling sering disepelekan padahal menentukan performa: &amp;#039;&amp;#039;&amp;#039;kebijakan scheduling&amp;#039;&amp;#039;&amp;#039; — siapa mengerjakan iterasi yang mana.  Prasyarat: &lt;a href=&quot;/wiki/index.php/OpenMP:_Setup_%26_Hello_World&quot; title=&quot;OpenMP: Setup &amp;amp; Hello World&quot;&gt;OpenMP: Setup &amp;amp; Hello World&lt;/a&gt;. Semua contoh di sini di-compile dengan:  &amp;lt;pre&amp;gt; g++ -O2 -fopenmp -o program program...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;#pragma omp parallel for&amp;lt;/code&amp;gt;&amp;#039;&amp;#039;&amp;#039; adalah konstruksi OpenMP yang paling sering dipakai: satu baris pragma yang membagi iterasi loop ke banyak thread. Artikel ini membahas cara kerjanya, aturan data sharing, dan yang paling sering disepelekan padahal menentukan performa: &amp;#039;&amp;#039;&amp;#039;kebijakan scheduling&amp;#039;&amp;#039;&amp;#039; — siapa mengerjakan iterasi yang mana.&lt;br /&gt;
&lt;br /&gt;
Prasyarat: [[OpenMP: Setup &amp;amp; Hello World]]. Semua contoh di sini di-compile dengan:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
g++ -O2 -fopenmp -o program program.cpp&lt;br /&gt;
OMP_NUM_THREADS=8 ./program&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Dasar: parallel for =&lt;br /&gt;
&lt;br /&gt;
Contoh paling sederhana, SAXPY (y = a·x + y):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdio&amp;gt;&lt;br /&gt;
#include &amp;lt;vector&amp;gt;&lt;br /&gt;
#include &amp;lt;omp.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
    const int N = 10&amp;#039;000&amp;#039;000;&lt;br /&gt;
    std::vector&amp;lt;double&amp;gt; x(N, 1.0), y(N, 2.0);&lt;br /&gt;
    const double a = 3.0;&lt;br /&gt;
&lt;br /&gt;
    #pragma omp parallel for&lt;br /&gt;
    for (int i = 0; i &amp;lt; N; ++i)&lt;br /&gt;
        y[i] = a * x[i] + y[i];    // tiap iterasi independen — syarat mutlak&lt;br /&gt;
&lt;br /&gt;
    printf(&amp;quot;y[0] = %.1f, y[N-1] = %.1f\n&amp;quot;, y[0], y[N-1]);&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Yang terjadi di balik pragma itu:&lt;br /&gt;
# Runtime membentuk &amp;#039;&amp;#039;&amp;#039;team of threads&amp;#039;&amp;#039;&amp;#039; (fork), biasanya sebanyak core / nilai &amp;lt;code&amp;gt;OMP_NUM_THREADS&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Ruang iterasi &amp;lt;code&amp;gt;0..N-1&amp;lt;/code&amp;gt; &amp;#039;&amp;#039;&amp;#039;dibagi&amp;#039;&amp;#039;&amp;#039; ke thread-thread sesuai kebijakan schedule.&lt;br /&gt;
# Di akhir loop ada &amp;#039;&amp;#039;&amp;#039;implicit barrier&amp;#039;&amp;#039;&amp;#039;: semua thread saling tunggu, baru program lanjut (join).&lt;br /&gt;
&lt;br /&gt;
Dalam bahasa [[Work-Span Model &amp;amp; Brent&amp;#039;s Theorem|work-span]]: badan loop yang independen berarti span-nya Θ(1) — parallelism Θ(N), ini kasus terbaik (&amp;quot;embarrassingly parallel&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== parallel vs for: dua konstruksi berbeda ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;parallel for&amp;lt;/code&amp;gt; sebenarnya gabungan dua hal: &amp;lt;code&amp;gt;parallel&amp;lt;/code&amp;gt; (bikin team) dan &amp;lt;code&amp;gt;for&amp;lt;/code&amp;gt; (bagi iterasi ke team yang sudah ada). Memisahkannya berguna kalau ada beberapa loop berurutan — team dibuat sekali saja, tidak fork-join berulang:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#pragma omp parallel          // fork sekali&lt;br /&gt;
{&lt;br /&gt;
    #pragma omp for nowait    // loop 1; nowait = hapus barrier di akhirnya&lt;br /&gt;
    for (int i = 0; i &amp;lt; N; ++i)&lt;br /&gt;
        a[i] = f(i);&lt;br /&gt;
&lt;br /&gt;
    #pragma omp for           // loop 2; barrier di sini tetap ada&lt;br /&gt;
    for (int i = 0; i &amp;lt; M; ++i)&lt;br /&gt;
        b[i] = g(i);&lt;br /&gt;
}                             // join sekali&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;nowait&amp;lt;/code&amp;gt; hanya aman kalau loop berikutnya &amp;#039;&amp;#039;&amp;#039;tidak membaca&amp;#039;&amp;#039;&amp;#039; hasil loop sebelumnya dari iterasi milik thread lain. Kalau ragu, biarkan barrier-nya.&lt;br /&gt;
&lt;br /&gt;
= Syarat Loop: Canonical Form =&lt;br /&gt;
&lt;br /&gt;
Tidak semua loop bisa ditempeli &amp;lt;code&amp;gt;parallel for&amp;lt;/code&amp;gt;. OpenMP menuntut &amp;#039;&amp;#039;&amp;#039;canonical loop form&amp;#039;&amp;#039;&amp;#039;: jumlah iterasi harus bisa dihitung &amp;#039;&amp;#039;sebelum&amp;#039;&amp;#039; loop jalan.&lt;br /&gt;
&lt;br /&gt;
* Variabel loop bertipe integer (atau random-access iterator C++).&lt;br /&gt;
* Kondisi berbentuk &amp;lt;code&amp;gt;i &amp;lt; n&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i &amp;lt;= n&amp;lt;/code&amp;gt;, dsb. — batas tidak berubah selama loop.&lt;br /&gt;
* Increment tetap: &amp;lt;code&amp;gt;++i&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;i += k&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Tidak ada &amp;lt;code&amp;gt;break&amp;lt;/code&amp;gt; atau &amp;lt;code&amp;gt;return&amp;lt;/code&amp;gt; keluar dari loop (&amp;lt;code&amp;gt;continue&amp;lt;/code&amp;gt; boleh).&lt;br /&gt;
* &amp;lt;code&amp;gt;while&amp;lt;/code&amp;gt; dan loop linked-list tidak bisa — untuk itu pakai [[OpenMP: Tasking]].&lt;br /&gt;
&lt;br /&gt;
Dan satu syarat semantik yang jadi tanggung jawab kita, bukan compiler: &amp;#039;&amp;#039;&amp;#039;tidak ada loop-carried dependency&amp;#039;&amp;#039;&amp;#039; — iterasi i tidak boleh butuh hasil iterasi lain. Compiler tidak memeriksa ini; pragma adalah janji kita ke compiler. Janji palsu = hasil salah tanpa peringatan.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// TIDAK BISA diparalelkan begitu saja: iterasi i butuh hasil iterasi i-1&lt;br /&gt;
for (int i = 1; i &amp;lt; N; ++i)&lt;br /&gt;
    prefix[i] = prefix[i-1] + x[i];   // DAG-nya rantai lurus, span Θ(N)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(Kasus prefix sum ini punya solusi khusus — lihat [[Parallel Prefix Sum (Scan)]].)&lt;br /&gt;
&lt;br /&gt;
= Data Sharing: shared, private, firstprivate, lastprivate =&lt;br /&gt;
&lt;br /&gt;
Aturan default: variabel yang dideklarasikan &amp;#039;&amp;#039;&amp;#039;di luar&amp;#039;&amp;#039;&amp;#039; region paralel = &amp;lt;code&amp;gt;shared&amp;lt;/code&amp;gt; (satu untuk semua thread), yang &amp;#039;&amp;#039;&amp;#039;di dalam&amp;#039;&amp;#039;&amp;#039; = private per thread. Variabel loop-nya sendiri otomatis private.&lt;br /&gt;
&lt;br /&gt;
Klausa untuk mengatur eksplisit:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Klausa !! Arti&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;shared(v)&amp;lt;/code&amp;gt; || Satu &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; untuk semua thread. Aman dibaca bersama; menulis bersama = race.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;private(v)&amp;lt;/code&amp;gt; || Tiap thread dapat salinan &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; sendiri, &amp;#039;&amp;#039;&amp;#039;tidak diinisialisasi&amp;#039;&amp;#039;&amp;#039;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;firstprivate(v)&amp;lt;/code&amp;gt; || Seperti private, tapi salinannya diinisialisasi dari nilai &amp;lt;code&amp;gt;v&amp;lt;/code&amp;gt; sebelum loop.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;lastprivate(v)&amp;lt;/code&amp;gt; || Seperti private, tapi nilai dari &amp;#039;&amp;#039;&amp;#039;iterasi terakhir&amp;#039;&amp;#039;&amp;#039; disalin balik keluar loop.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;default(none)&amp;lt;/code&amp;gt; || Wajib deklarasi eksplisit semua variabel. &amp;#039;&amp;#039;&amp;#039;Selalu pakai ini&amp;#039;&amp;#039;&amp;#039; — memaksa mikir, menangkap race saat compile.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Contoh dengan &amp;lt;code&amp;gt;default(none)&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
double skala = 2.5;&lt;br /&gt;
std::vector&amp;lt;double&amp;gt; v(N);&lt;br /&gt;
&lt;br /&gt;
#pragma omp parallel for default(none) shared(v) firstprivate(skala)&lt;br /&gt;
for (int i = 0; i &amp;lt; (int)v.size(); ++i)   // hati-hati: size() perlu di-cast/di-hoist&lt;br /&gt;
    v[i] = skala * i;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Lupa satu variabel saja dengan &amp;lt;code&amp;gt;default(none)&amp;lt;/code&amp;gt; → error compile. Jauh lebih murah daripada race yang muncul sekali tiap seribu run.&lt;br /&gt;
&lt;br /&gt;
= Race Condition: Bug Nomor Satu =&lt;br /&gt;
&lt;br /&gt;
Program lengkap yang menunjukkan kenapa menulis ke variabel &amp;lt;code&amp;gt;shared&amp;lt;/code&amp;gt; itu fatal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdio&amp;gt;&lt;br /&gt;
#include &amp;lt;omp.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
    const int N = 1000000;&lt;br /&gt;
    long salah = 0, benar = 0;&lt;br /&gt;
&lt;br /&gt;
    #pragma omp parallel for&lt;br /&gt;
    for (int i = 0; i &amp;lt; N; ++i)&lt;br /&gt;
        salah += 1;               // RACE: semua thread menulis variabel yang sama&lt;br /&gt;
&lt;br /&gt;
    #pragma omp parallel for reduction(+:benar)&lt;br /&gt;
    for (int i = 0; i &amp;lt; N; ++i)&lt;br /&gt;
        benar += 1;               // tiap thread punya salinan, digabung di akhir&lt;br /&gt;
&lt;br /&gt;
    printf(&amp;quot;salah = %ld  (harusnya %d)\n&amp;quot;, salah, N);&lt;br /&gt;
    printf(&amp;quot;benar = %ld\n&amp;quot;, benar);&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Output nyata (16 thread):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
salah = 937500  (harusnya 1000000)&lt;br /&gt;
benar = 1000000&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;salah += 1&amp;lt;/code&amp;gt; itu tiga operasi (baca–tambah–tulis); dua thread yang interleave saling menimpa hasil. Perbaikannya &amp;#039;&amp;#039;&amp;#039;bukan&amp;#039;&amp;#039;&amp;#039; &amp;lt;code&amp;gt;critical&amp;lt;/code&amp;gt; atau &amp;lt;code&amp;gt;atomic&amp;lt;/code&amp;gt; di dalam loop (itu menserialisasi lagi, kadang lebih lambat dari sekuensial) tapi klausa &amp;lt;code&amp;gt;reduction&amp;lt;/code&amp;gt;. Detail di [[OpenMP: Reduction &amp;amp; Sinkronisasi]].&lt;br /&gt;
&lt;br /&gt;
= Scheduling: Siapa Mengerjakan Iterasi yang Mana =&lt;br /&gt;
&lt;br /&gt;
Sintaks: &amp;lt;code&amp;gt;schedule(jenis[, chunk])&amp;lt;/code&amp;gt;. Ilustrasi 16 iterasi, 4 thread:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
static          T0:[ 0  1  2  3] T1:[ 4  5  6  7] T2:[ 8  9 10 11] T3:[12 13 14 15]&lt;br /&gt;
                blok kontigu sama besar, ditentukan di awal&lt;br /&gt;
&lt;br /&gt;
static,2        T0:[0 1][8 9]    T1:[2 3][10 11]  T2:[4 5][12 13]  T3:[6 7][14 15]&lt;br /&gt;
                chunk 2 iterasi, dibagi round-robin, tetap ditentukan di awal&lt;br /&gt;
&lt;br /&gt;
dynamic,2       T0:[0 1][6 7]... T1:[2 3][10 11]..  &amp;lt;- siapa cepat dia dapat&lt;br /&gt;
                thread yang selesai ambil chunk berikutnya dari antrean&lt;br /&gt;
&lt;br /&gt;
guided          [0..5][6..9][10..12][13 14][15]     &amp;lt;- chunk mengecil&lt;br /&gt;
                mulai besar (sisa/p), makin lama makin kecil, diambil dinamis&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;schedule(static)&amp;lt;/code&amp;gt; — default di kebanyakan implementasi&lt;br /&gt;
: Pembagian ditentukan sebelum loop jalan, &amp;#039;&amp;#039;&amp;#039;overhead nol&amp;#039;&amp;#039;&amp;#039;, deterministik. Bonus besar: kalau loop yang sama dijalankan berulang (misal tiap timestep), thread yang sama pegang elemen yang sama → data masih hangat di cache-nya, dan cocok dengan pola first-touch di sistem [[NUMA]] (lihat [[OpenMP: Affinity &amp;amp; First-Touch]]).&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;schedule(static, chunk)&amp;lt;/code&amp;gt;&lt;br /&gt;
: Sama-sama ditentukan di awal, tapi interleaved. Berguna kalau beban naik/turun secara &amp;#039;&amp;#039;teratur&amp;#039;&amp;#039; sepanjang ruang iterasi.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;schedule(dynamic, chunk)&amp;lt;/code&amp;gt;&lt;br /&gt;
: Thread ambil chunk dari antrean bersama tiap kali selesai. Menyeimbangkan beban timpang, tapi tiap pengambilan ada overhead sinkronisasi. &amp;lt;code&amp;gt;dynamic,1&amp;lt;/code&amp;gt; (chunk default) = load balancing terbaik, overhead terburuk; chunk besar = sebaliknya. Lokalitas cache juga hancur karena pembagian berubah tiap run.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;schedule(guided, chunk)&amp;lt;/code&amp;gt;&lt;br /&gt;
: Seperti dynamic tapi chunk mengecil eksponensial (mulai ≈ sisa_iterasi/jumlah_thread, minimum &amp;lt;code&amp;gt;chunk&amp;lt;/code&amp;gt;). Kompromi: sedikit pengambilan di awal, granularitas halus di akhir buat menambal ketimpangan.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;schedule(auto)&amp;lt;/code&amp;gt;&lt;br /&gt;
: Terserah compiler/runtime.&lt;br /&gt;
&lt;br /&gt;
; &amp;lt;code&amp;gt;schedule(runtime)&amp;lt;/code&amp;gt;&lt;br /&gt;
: Baca dari environment variable &amp;lt;code&amp;gt;OMP_SCHEDULE&amp;lt;/code&amp;gt; (misal &amp;lt;code&amp;gt;OMP_SCHEDULE=&amp;quot;dynamic,64&amp;quot;&amp;lt;/code&amp;gt;) atau &amp;lt;code&amp;gt;omp_set_schedule()&amp;lt;/code&amp;gt;. Emas buat eksperimen: ganti kebijakan tanpa recompile.&lt;br /&gt;
&lt;br /&gt;
= Benchmark: Membandingkan Semua Schedule =&lt;br /&gt;
&lt;br /&gt;
Program lengkap. Bebannya sengaja timpang — iterasi ke-i mengerjakan i putaran, jadi iterasi akhir jauh lebih berat (beban segitiga). Trik &amp;lt;code&amp;gt;schedule(runtime)&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;omp_set_schedule()&amp;lt;/code&amp;gt; dipakai supaya satu binary bisa menguji semua kebijakan:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;cstdio&amp;gt;&lt;br /&gt;
#include &amp;lt;cmath&amp;gt;&lt;br /&gt;
#include &amp;lt;omp.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// Kerja per iterasi sengaja dibuat timpang:&lt;br /&gt;
// iterasi ke-i mengerjakan i putaran, jadi iterasi akhir jauh&lt;br /&gt;
// lebih berat dari iterasi awal (beban berbentuk segitiga).&lt;br /&gt;
double kerja(long i) {&lt;br /&gt;
    double s = 0.0;&lt;br /&gt;
    for (long j = 0; j &amp;lt; i; ++j)&lt;br /&gt;
        s += std::sin(j * 1e-9);&lt;br /&gt;
    return s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void jalankan(omp_sched_t jenis, int chunk, const char *nama, long n) {&lt;br /&gt;
    omp_set_schedule(jenis, chunk);&lt;br /&gt;
    double total = 0.0;&lt;br /&gt;
&lt;br /&gt;
    double t0 = omp_get_wtime();&lt;br /&gt;
    #pragma omp parallel for schedule(runtime) reduction(+:total)&lt;br /&gt;
    for (long i = 0; i &amp;lt; n; ++i)&lt;br /&gt;
        total += kerja(i);&lt;br /&gt;
    double t1 = omp_get_wtime();&lt;br /&gt;
&lt;br /&gt;
    printf(&amp;quot;%-16s : %6.3f s  (checksum %.4f)\n&amp;quot;, nama, t1 - t0, total);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main() {&lt;br /&gt;
    const long N = 30000;&lt;br /&gt;
    printf(&amp;quot;threads = %d, N = %ld\n\n&amp;quot;, omp_get_max_threads(), N);&lt;br /&gt;
&lt;br /&gt;
    jalankan(omp_sched_static,  0,   &amp;quot;static&amp;quot;,      N);&lt;br /&gt;
    jalankan(omp_sched_static,  100, &amp;quot;static,100&amp;quot;,  N);&lt;br /&gt;
    jalankan(omp_sched_dynamic, 1,   &amp;quot;dynamic,1&amp;quot;,   N);&lt;br /&gt;
    jalankan(omp_sched_dynamic, 100, &amp;quot;dynamic,100&amp;quot;, N);&lt;br /&gt;
    jalankan(omp_sched_guided,  0,   &amp;quot;guided&amp;quot;,      N);&lt;br /&gt;
    return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hasil nyata di mesin 16 thread (angka pasti beda-beda tiap mesin, polanya yang penting):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
threads = 16, N = 30000&lt;br /&gt;
&lt;br /&gt;
static           :  0.259 s  (checksum 4499.5500)&lt;br /&gt;
static,100       :  0.191 s  (checksum 4499.5500)&lt;br /&gt;
dynamic,1        :  0.183 s  (checksum 4499.5500)&lt;br /&gt;
dynamic,100      :  0.192 s  (checksum 4499.5500)&lt;br /&gt;
guided           :  0.181 s  (checksum 4499.5500)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Analisisnya:&lt;br /&gt;
* &amp;lt;code&amp;gt;static&amp;lt;/code&amp;gt; paling lambat (~40% di belakang): thread terakhir kebagian blok iterasi terberat, thread lain selesai duluan lalu &amp;#039;&amp;#039;&amp;#039;nganggur menunggu barrier&amp;#039;&amp;#039;&amp;#039;. Waktu loop = waktu thread paling sial.&lt;br /&gt;
* &amp;lt;code&amp;gt;static,100&amp;lt;/code&amp;gt; sudah hampir menyelesaikan masalah: interleaving meratakan beban segitiga, tanpa overhead dinamis.&lt;br /&gt;
* &amp;lt;code&amp;gt;dynamic,1&amp;lt;/code&amp;gt; menang di sini karena badan iterasinya besar (ribuan sin), jadi overhead ambil-chunk tenggelam. Kalau badan loop-nya cuma beberapa instruksi, &amp;lt;code&amp;gt;dynamic,1&amp;lt;/code&amp;gt; justru bisa lebih lambat dari sekuensial.&lt;br /&gt;
* Checksum harus identik di semua kebijakan — schedule mengubah &amp;#039;&amp;#039;pembagian kerja&amp;#039;&amp;#039;, bukan hasil. Kalau checksum berubah-ubah, ada race.&lt;br /&gt;
&lt;br /&gt;
= Panduan Memilih =&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Situasi !! Pakai&lt;br /&gt;
|-&lt;br /&gt;
| Beban tiap iterasi seragam (SAXPY, stencil, matmul) || &amp;lt;code&amp;gt;static&amp;lt;/code&amp;gt; — overhead nol, cache &amp;amp; NUMA friendly&lt;br /&gt;
|-&lt;br /&gt;
| Beban bervariasi tapi polanya teratur (segitiga, dsb.) || &amp;lt;code&amp;gt;static,chunk&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Beban tak tertebak, badan iterasi besar (Mandelbrot, ray tracing, simulasi partikel) || &amp;lt;code&amp;gt;dynamic,chunk&amp;lt;/code&amp;gt; — mulai dari chunk sedang (32–128), tuning&lt;br /&gt;
|-&lt;br /&gt;
| Beban tak tertebak, mau kompromi tanpa tuning || &amp;lt;code&amp;gt;guided&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Belum tahu / mau eksperimen || &amp;lt;code&amp;gt;runtime&amp;lt;/code&amp;gt; + &amp;lt;code&amp;gt;OMP_SCHEDULE&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Prinsipnya trade-off tiga arah: &amp;#039;&amp;#039;&amp;#039;load balance&amp;#039;&amp;#039;&amp;#039; vs &amp;#039;&amp;#039;&amp;#039;overhead scheduling&amp;#039;&amp;#039;&amp;#039; vs &amp;#039;&amp;#039;&amp;#039;lokalitas cache&amp;#039;&amp;#039;&amp;#039;. &amp;lt;code&amp;gt;static&amp;lt;/code&amp;gt; mengorbankan yang pertama demi dua sisanya; &amp;lt;code&amp;gt;dynamic,1&amp;lt;/code&amp;gt; kebalikannya; sisanya ada di tengah.&lt;br /&gt;
&lt;br /&gt;
= collapse: Loop Bersarang =&lt;br /&gt;
&lt;br /&gt;
Kalau loop luar iterasinya sedikit (misal N=8 baris di mesin 16 thread), separuh thread nganggur. &amp;lt;code&amp;gt;collapse(2)&amp;lt;/code&amp;gt; menggabungkan dua ruang iterasi jadi satu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
// tanpa collapse: hanya N iterasi dibagi ke thread → N=8, 16 thread = rugi&lt;br /&gt;
// dengan collapse(2): N*M iterasi dibagi ke thread&lt;br /&gt;
#pragma omp parallel for collapse(2)&lt;br /&gt;
for (int i = 0; i &amp;lt; N; ++i)&lt;br /&gt;
    for (int j = 0; j &amp;lt; M; ++j)&lt;br /&gt;
        c[i][j] = a[i][j] + b[i][j];&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Syarat: kedua loop harus &amp;#039;&amp;#039;perfectly nested&amp;#039;&amp;#039; (tidak ada statement di antara &amp;lt;code&amp;gt;for i&amp;lt;/code&amp;gt; dan &amp;lt;code&amp;gt;for j&amp;lt;/code&amp;gt;) dan batas loop dalam tidak boleh bergantung pada loop luar. Kalau loop luar sudah punya iterasi jauh lebih banyak dari jumlah thread, &amp;lt;code&amp;gt;collapse&amp;lt;/code&amp;gt; tidak perlu — malah bisa merusak lokalitas akses baris.&lt;br /&gt;
&lt;br /&gt;
= Jebakan Umum =&lt;br /&gt;
&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Pragma adalah janji.&amp;#039;&amp;#039;&amp;#039; Compiler percaya begitu saja bahwa iterasi independen. Loop-carried dependency tidak terdeteksi — hasil salah, tanpa error, kadang cuma sesekali.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Loop terlalu kecil.&amp;#039;&amp;#039;&amp;#039; Fork-join dan barrier itu ada harganya (orde mikrodetik). Loop 1000 iterasi ringan bisa lebih lambat diparalelkan. Ukur dulu, paralelkan loop yang memang makan waktu. Bisa juga pakai klausa &amp;lt;code&amp;gt;if(N &amp;gt; 10000)&amp;lt;/code&amp;gt; supaya paralel hanya untuk masalah besar.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Menulis elemen bertetangga dari thread berbeda.&amp;#039;&amp;#039;&amp;#039; Benar secara logika, lambat secara hardware — dua thread menulis ke cache line yang sama saling melempar line-nya bolak-balik. Lihat [[OpenMP: False Sharing]] dan [[Cache line]].&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Memanggil fungsi yang tidak thread-safe&amp;#039;&amp;#039;&amp;#039; di dalam loop (&amp;lt;code&amp;gt;rand()&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;strtok()&amp;lt;/code&amp;gt;, ...). Pakai versi reentrant atau state per thread.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;&amp;lt;code&amp;gt;std::vector::push_back&amp;lt;/code&amp;gt; di dalam parallel for.&amp;#039;&amp;#039;&amp;#039; Mengubah struktur container dari banyak thread = race. Pre-allocate lalu tulis via indeks.&lt;br /&gt;
* &amp;#039;&amp;#039;&amp;#039;Nested parallelism tak sengaja&amp;#039;&amp;#039;&amp;#039; — &amp;lt;code&amp;gt;parallel for&amp;lt;/code&amp;gt; di dalam fungsi yang dipanggil dari &amp;lt;code&amp;gt;parallel for&amp;lt;/code&amp;gt; lain. Default-nya region dalam jalan serial (aman), tapi kalau &amp;lt;code&amp;gt;OMP_NESTED=true&amp;lt;/code&amp;gt; bisa terjadi ledakan thread.&lt;br /&gt;
&lt;br /&gt;
= Ringkasan =&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;parallel for&amp;lt;/code&amp;gt; = fork team + bagi iterasi + implicit barrier. Syaratnya: canonical form dan iterasi benar-benar independen.&lt;br /&gt;
* Selalu &amp;lt;code&amp;gt;default(none)&amp;lt;/code&amp;gt;; akumulasi pakai &amp;lt;code&amp;gt;reduction&amp;lt;/code&amp;gt;, bukan menulis ke &amp;lt;code&amp;gt;shared&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Schedule = trade-off load balance vs overhead vs lokalitas: &amp;lt;code&amp;gt;static&amp;lt;/code&amp;gt; untuk beban rata, &amp;lt;code&amp;gt;dynamic/guided&amp;lt;/code&amp;gt; untuk beban timpang, &amp;lt;code&amp;gt;runtime&amp;lt;/code&amp;gt; untuk eksperimen.&lt;br /&gt;
* Waktu loop paralel = waktu thread paling lambat; barrier membuat semua orang menunggu si paling sial.&lt;br /&gt;
&lt;br /&gt;
= Lihat Juga =&lt;br /&gt;
&lt;br /&gt;
* [[OpenMP: Setup &amp;amp; Hello World]] — prasyarat&lt;br /&gt;
* [[OpenMP: Reduction &amp;amp; Sinkronisasi]] — kelanjutan langsung dari klausa &amp;lt;code&amp;gt;reduction&amp;lt;/code&amp;gt;&lt;br /&gt;
* [[OpenMP: Tasking]] — untuk kerja yang tidak berbentuk loop canonical&lt;br /&gt;
* [[OpenMP: False Sharing]] — kenapa hasil benar tapi lambat&lt;br /&gt;
* [[OpenMP: Affinity &amp;amp; First-Touch]] — interaksi schedule dengan [[NUMA]]&lt;br /&gt;
* [[Work-Span Model &amp;amp; Brent&amp;#039;s Theorem]] — teori di balik &amp;quot;iterasi independen = parallelism maksimal&amp;quot;&lt;br /&gt;
* [[Parallel Prefix Sum (Scan)]] — cara menangani loop yang punya dependency&lt;br /&gt;
&lt;br /&gt;
[[Kategori:HPC]]&lt;br /&gt;
[[Kategori:OpenMP]]&lt;/div&gt;</summary>
		<author><name>SanzSkuy</name></author>
	</entry>
</feed>