/**
 * Kalkulator tuning GC atas angka pasti: live set hasil heap dump, laju
 * alokasi hasil profil, dan jeda hasil -Xlog:gc. Seluruh keluaran adalah
 * matematika murni atas masukan tetap, bukan pengukuran runtime.
 */
public class KalkulatorTuning {

    record Kasus(String skenario, String sla, String rekomendasi) {}

    public static void main(String[] args) {
        // Masukan hasil pengukuran (angka tetap untuk contoh ini)
        int liveSetMb = 4096;               // heap dump setelah major GC
        int lajuAlokasiMbPerMenit = 12_000; // profil alokasi: 12 GB/menit
        int jedaPerMinorMs = 40;            // -Xlog:gc: rata-rata minor GC
        int anggaranGcPersen = 1;           // SLA: maksimal 1% waktu untuk GC

        // ---- 1. Ukuran heap total: panduan umum 3x live set ----
        int heapMb = 3 * liveSetMb;
        System.out.println("== Ukuran heap ==");
        System.out.println("live set        = " + liveSetMb + " MB");
        System.out.println("heap disarankan = 3 x live set = " + heapMb + " MB");
        System.out.printf("rasio live/heap = %.0f%%%n", 100.0 * liveSetMb / heapMb);

        // ---- 2. Young gen minimum dari anggaran jeda ----
        // (A / Y) * jeda <= anggaran% x 60.000 ms  =>  Y >= A * jeda / anggaran
        int yMin = (int) Math.ceil((double) lajuAlokasiMbPerMenit * jedaPerMinorMs
            / (anggaranGcPersen / 100.0 * 60_000));
        System.out.println();
        System.out.println("== Ukuran young gen ==");
        System.out.println("laju alokasi    = " + lajuAlokasiMbPerMenit + " MB/menit");
        System.out.println("jeda per minor  = " + jedaPerMinorMs + " ms");
        System.out.println("anggaran GC     = " + anggaranGcPersen + "% x 60.000 ms = "
            + (anggaranGcPersen / 100.0 * 60_000) + " ms/menit");
        System.out.println("young gen min   = " + yMin + " MB");

        // ---- 3. Bandingkan kandidat young gen ----
        System.out.println();
        System.out.println("== Kandidat young gen (jeda total per menit) ==");
        System.out.printf("%8s %10s %14s %11s%n", "Y (MB)", "GC/menit", "jeda/menit", "% waktu GC");
        for (int yMb : new int[] {512, 1024, 2048, 3072}) {
            double gcPerMenit = (double) lajuAlokasiMbPerMenit / yMb;
            double jedaPerMenit = gcPerMenit * jedaPerMinorMs;
            double persen = 100.0 * jedaPerMenit / 60_000;
            String status = yMb >= yMin ? "OK" : "terlalu kecil";
            System.out.printf("%8d %10.1f %9.0f ms %10.2f%%  %s%n",
                yMb, gcPerMenit, jedaPerMenit, persen, status);
        }

        // ---- 4. Region G1 ----
        System.out.println();
        System.out.println("== Region G1 (ukuran dibulatkan ke pangkat dua) ==");
        System.out.println("heap 12.288 MB / region 4 MB  = " + (12_288 / 4) + " region");
        System.out.println("heap    256 MB / region 1 MB  = " + (256 / 1) + " region"
            + "  <- cocok dengan output jcmd GC.heap_info mesin uji");

        // ---- 5. Pilihan collector dari SLA ----
        System.out.println();
        System.out.println("== Peta keputusan collector ==");
        System.out.printf("%-28s %-34s %s%n", "skenario", "SLA", "collector");
        for (Kasus k : new Kasus[] {
                new Kasus("ETL malam tanpa pengguna", "throughput maksimal", "-XX:+UseParallelGC"),
                new Kasus("Web API umum", "p99 di bawah 200 ms", "-XX:+UseG1GC (bawaan)"),
                new Kasus("Trading, heap 100 GB", "p99 di bawah 20 ms", "-XX:+UseZGC")}) {
            System.out.printf("%-28s %-34s %s%n", k.skenario(), k.sla(), k.rekomendasi());
        }
        System.out.println();
        System.out.println("Urutan kerja: ukur (heap dump, profil alokasi, -Xlog:gc),");
        System.out.println("hitung (kalkulator ini), lalu ubah satu variabel pada satu waktu.");
    }
}
