Jom datang beramai-ramai!
Selamat datang. Blog ini mengandungi penulisan dan bahan rujukan berkaitan pengaturcaraan dan penyelidikan yang ingin saya kongsi dengan anda. Semoga bermanfaat. (Nota: Selain teks rumi, blog ini turut mengandungi teks jawi bahasa Melayu)
Friday, April 20, 2018
Wednesday, April 18, 2018
Tutorial - Menggunakan JFreeChart untuk simulasi penjadualan proses
Pengenalan JFreeChart
JFreeChart ialah pustaka kod sumber terbuka (open source) yang dibangunkan oleh David Gilbert sejak tahun 2000. Pustaka ini boleh diperoleh dan digunakan secara percuma (tetapi perlu menyatakan hakcipta pemilik/pencipta asal).
Fungsi pustaka ini ialah untuk membolehkan pengatur cara menghasilkan carta melalui atur cara Java. Contoh-contoh carta yang boleh dihasilkan oleh pustaka ini boleh dirujuk di laman JFreeChart.org. Antaranya termasuklah seperti yang dipaparkan di bawah:
sumber: JFreeChart.org
Tutorial - membina carta Gantt untuk simulasi penjadualan proses.
Tutorial ini bertujuan menunjukkan cara-cara menggunakan JFreeChart dalam aturcara Java untuk membina aplikasi simulasi penjadualan proses.
Contoh aplikasi yang ditunjukkan dalam tutorial ini ialah aplikasi simulasi penjadualan proses untuk penggunaan CPU (Central Processing Unit, atau Unit Pemprosesan Pusat). Aplikasi simulasi ini akan membentuk 5 proses yang akan dijadualkan (untuk menggunakan 'CPU') menggunakan algoritma Round-Robin. Hasil simulasi penjadualan akan ditunjukkan seperti dalam gambarajah di bawah, yang mengandungi 1 tetingkap untuk memaparkan carta Gantt, dan maklumat terperinci dipaparkan dalam paparan konsol (console).
Tutorial ini melibatkan tiga peringkat berikut:
- Memasukkan pustaka JFreeChart dalam projek
- Memasukkan panggilan pustaka JFreeChart yang asas ke dalam atur cara Java
- Membina aplikasi simulasi penjadualan
.
Peringkat 1: Memasukkan pustaka JFreeChart dalam projek.
Untuk menggunakan pustaka JFreeChart, kita boleh mendapatkan kod sumber sepenuhnya dan kemudian mengkompilnya ke dalam bentuk fail JAR (Java ARchive). Walau bagaimanapun kita boleh terus mendapatkan fail JAR yang sudah siap dikompil, kemudian memasukkannya ke dalam projek aplikasi Java yang kita bina.
Untuk tutorial ini, kita perlukan dua fail JAR berikut :
- jCommon.jar
- jFreeChart.jar
Versi terkini fail-fail ini boleh dimuat turun dari laman web JFreeChart.org.
Berikut ialah langkah memasukkan fail JAR ke dalam projek (IDE Netbeans):
- Langkah 1: Muat turun dan letakkan fail-fail JAR tersebut ke dalam sebuah folder/direktori.
- Langkah 2: Buka tetapan (setting) projek, dengan klik butang kanan pada nama projek dan pilih Properties (merujuk 'Project Properties').
- Langkah 3: Dalam tetingkap dialog yang muncul, klik Libraries, dan pilih tab Compile. Tekan butang Add JAR/folder dan cari semula folder yang mengandungi fail-fail JAR yang sudah dimuat turun.
.
Peringkat 2: Memasukkan panggilan pustaka JFreeChart yang asas dalam atur cara Java.
Nota : JFreeChart menggunakan pustaka Java Swing, iaitu salah satu platform atau pustaka GUI bagi Java. Diandaikan anda tahu cara-cara menggunakan Java Swing. Jika tidak tahu, anda perlu belajar dahulu cara menggunakan Java Swing.
Untuk memahami konsep JFreeChart, kita akan bina satu aplikasi asas menggunakan JFreeChart. Dalam aplikasi asas ini, kita membina sebuah kelas JFrame (kelas dari Java Swing) dan memaparkan sebuah carta Gantt di dalamnya.
Umumnya, untuk membina carta Gantt menggunakan JFreeChart,
- Kita perlu sediakan satu siri data menggunakan kelas TaskSeries, dan dimasukkan ke dalam sebuah koleksi dari kelas TaskSeriesCollection (IntervalCategoryDataset ialah super-kelas kepada kelas ini).
...
private IntervalCategoryDataset buildChartDataset() {
// Bina beberapa siri data
TaskSeries series = new TaskSeries("Data Series 1");
Task t1 = new Task("T1", new SimpleTimePeriod( 0, 100 ));
series.add( t1 );
Task t2 = new Task("T2", new SimpleTimePeriod( 110, 180 ));
series.add( t2 );
Task t3 = new Task("T3", new SimpleTimePeriod( 180, 220 ));
series.add( t3 );
TaskSeriesCollection dataset = new TaskSeriesCollection();
dataset.add(series);
return dataset;
}
... - Set data ini akan kita jadikan ke dalam bentuk carta menggunakan metod dari kelas statik ChartFactory.createGanttChart(). Metod ini menghasilkan sebuah objek dari jenis kelas JFreeChart.
...
public TestChart(String title) {
super(title);
// Bina data set untuk carta
IntervalCategoryDataset dataset = buildChartDataset();
// Create chart
JFreeChart chart = ChartFactory.createGanttChart(
"Simple Gantt Chart", // Tajuk
"Task", // Label Y-Axis
"Timeline", // Label X-Axis
dataset);
// set x-axis range supaya bermula dengan 0
( chart.getCategoryPlot() ).setRangeAxis(new NumberAxis());
... - Objek carta yang terhasil dari metod statik ChartFactory.createGanttChart() perlu dimasukkan ke dalam sebuah container dari kelas JPanel. Container yang mengandungi carta akan dimasukkan ke dalam JFrame untuk dipaparkan.
...
ChartPanel panel = new ChartPanel(chart); // tambah ke dalam panel
setContentPane(panel); // paparkan panel
...
Atur cara di bawah menunjukkan keseluruhan atur cara yang menggunakan langkah-langkah yang dinyatakan ini.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import javax.swing.JFrame; | |
import javax.swing.SwingUtilities; | |
import javax.swing.WindowConstants; | |
import org.jfree.chart.ChartFactory; | |
import org.jfree.chart.ChartPanel; | |
import org.jfree.chart.JFreeChart; | |
import org.jfree.chart.axis.NumberAxis; | |
import org.jfree.data.category.IntervalCategoryDataset; | |
import org.jfree.data.gantt.Task; | |
import org.jfree.data.gantt.TaskSeries; | |
import org.jfree.data.gantt.TaskSeriesCollection; | |
import org.jfree.data.time.SimpleTimePeriod; | |
public class TestChart extends JFrame { | |
public TestChart(String title) { | |
super(title); | |
// Bina data set untuk carta | |
IntervalCategoryDataset dataset = buildChartDataset(); | |
// Create chart | |
JFreeChart chart = ChartFactory.createGanttChart( | |
"Simple Gantt Chart", // Tajuk | |
"Task", // Label Y-Axis | |
"Timeline", // Label X-Axis | |
dataset); | |
// set x-axis range supaya bermula dengan 0 | |
( chart.getCategoryPlot() ).setRangeAxis(new NumberAxis()); | |
ChartPanel panel = new ChartPanel(chart); // tambah ke dalam panel | |
setContentPane(panel); // paparkan panel | |
} | |
private IntervalCategoryDataset buildChartDataset() { | |
// Bina beberapa siri data | |
TaskSeries series = new TaskSeries("Data Series 1"); | |
Task t1 = new Task("T1", new SimpleTimePeriod( 0, 100 )); | |
series.add( t1 ); | |
Task t2 = new Task("T2", new SimpleTimePeriod( 110, 180 )); | |
series.add( t2 ); | |
Task t3 = new Task("T3", new SimpleTimePeriod( 180, 220 )); | |
series.add( t3 ); | |
// Menambah siri data ke dalam koleksi. Penggunaan koleksi ini ialah | |
// membolehkan lebih dari satu siri data digunakan dalam carta - misalnya | |
// menggabungkan carta Gantt bagi dua konteks tugas. | |
TaskSeriesCollection dataset = new TaskSeriesCollection(); | |
dataset.add(series); | |
return dataset; | |
} | |
public static void main(String[] args) { | |
SwingUtilities.invokeLater(() -> { | |
TestChart chart = new TestChart("Simple Gantt Chart"); | |
chart.setSize(800, 400); | |
chart.setLocationRelativeTo(null); | |
chart.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); | |
chart.setVisible(true); | |
}); | |
} | |
} |
Peringkat 3: Membina aplikasi simulasi penjadualan.
Setelah mengetahui bagaimana hendak membina carta menggunakan JFreeChart, kita gabungkan kemudahan ini untuk membina simulasi penjadualan proses.
Algoritma Penjadualan Proses
Penjadualan proses ialah antara tugas utama yang dijalankan oleh sistem pengoperasian (OS) dalam mengurus perlaksanaan atur cara dan program komputer. Penjadualan proses boleh dilakukan dengan menggunakan pelbagai jenis algoritma. Antara algoritma penjadualan proses yang asas ialah First-come-first-serve (FCFS), Round-Robin (RR), Shortest-Job-First (SJF) dan Priority-based. Kod atur cara berikut ialah sebahagian atur cara yang mengandungi implementasi algoritma RR (Lihat kod atur cara penuh dipaparkan di bawahnya):
...
private Process[] simulateRR(Process[] pt, int quantum)
{
// RR-queue, to manage the round-robin scheduling
class RRQItem {
public Process process;
public int remaining;
public int stopped;
}
Queue<RRQItem> rrQ = new LinkedList(); // Round-Robin queue
int clk_tick = 0; // reset clk_tick int cpu_tick = 0; // timer for running process
boolean cpu_idle = true; // if not idle, then CPU is busy
int totDone = 0;
while(totDone < pt.length) {
// is it time to execute (submit to queue) ?
for(int p=0; p < pt.length; p++ ) {
if (clk_tick == pt[p].arrivalTime) {
// put inside RR-queue
RRQItem item = new RRQItem();
item.process = pt[p];
item.remaining = pt[p].burstTime;
item.stopped = pt[p].arrivalTime;
rrQ.add(item);
}
}
if(!cpu_idle) {
cpu_tick--; // deplete cpu burst time
if(cpu_tick <= 0) { // if timeout
// remove currently running process
RRQItem running = rrQ.remove();
cpu_idle = true;
if(running.remaining > 0) { // if not yet finish
running.stopped = clk_tick; // record when this process
// is stopped
running.process.numOfTimesStopped++; // record stoppage
// count
rrQ.add(running); // put back into queue
} else {
// process finish, calculate turnaround time
running.process.turnaroundTime =
clk_tick - running.process.arrivalTime;
totDone++;
}
}
}
// if CPU idle, and no process is running
if(cpu_idle) {
// submit next remaining process in queue
if(!rrQ.isEmpty()) {
RRQItem front = rrQ.peek(); // check who is at
// the front of Q
if(front.process.startTime < 0) { // record the first
// time process start
front.process.startTime = clk_tick; // record starting
// time
}
front.process.waitingTime += clk_tick - front.stopped;
// submit and set for how long is the execution time
cpu_idle = false;
cpu_tick = (front.remaining >= quantum ? quantum :
front.remaining);
Process part = new Process( "" + front.process.id + "_" +
front.process.subtask.size(), cpu_tick, clk_tick);
part.startTime = clk_tick;
// record waiting time for this part
part.waitingTime = clk_tick - front.stopped;
// add new part (sub-process)
front.process.subtask.add( part );
// update remaining time for this process
front.remaining -= cpu_tick;
}
}
clk_tick++; // update clk_tick
}
return pt;
}
...
|
Simulasi Penjadualan Proses
Berikut ialah atur cara penuh Java yang digunakan untuk menghasilkan simulasi penjadualan proses menggunakan algoritma Round-Robin.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* | |
* @author yunus sharum | |
* Modified: 13 April 2018 | |
* Version : 0.1 | |
* | |
* About: Demonstration of CPU scheduling simulation using RR Scheduling | |
* algorithm. | |
* | |
* The simulation chart is generated using JFreeChart library. | |
* | |
* | |
*/ | |
import java.awt.Component; | |
import java.awt.Container; | |
import java.util.ArrayList; | |
import java.util.LinkedList; | |
import java.util.Queue; | |
import javax.swing.BoxLayout; | |
import javax.swing.JFrame; | |
import javax.swing.SwingUtilities; | |
import javax.swing.WindowConstants; | |
import org.jfree.chart.ChartFactory; | |
import org.jfree.chart.ChartPanel; | |
import org.jfree.chart.JFreeChart; | |
import org.jfree.chart.axis.NumberAxis; | |
import org.jfree.data.category.IntervalCategoryDataset; | |
import org.jfree.data.gantt.Task; | |
import org.jfree.data.gantt.TaskSeries; | |
import org.jfree.data.gantt.TaskSeriesCollection; | |
import org.jfree.data.time.SimpleTimePeriod; | |
public class RRchart extends JFrame { | |
class Process { | |
public String id; | |
public int burstTime; | |
public int arrivalTime; | |
public int waitingTime; | |
public int turnaroundTime; | |
public int startTime; | |
public int numOfTimesStopped; | |
public ArrayList<Process> subtask; | |
public Process(String id, int burstTime, int arrivalTime) | |
{ | |
this.id = id; | |
this.burstTime = burstTime; | |
this.arrivalTime = arrivalTime; | |
this.waitingTime = 0; | |
this.turnaroundTime = 0; | |
this.startTime = -1; // -1, process has never started | |
this.numOfTimesStopped = 0; | |
this.subtask = new ArrayList(); // to keep track list of subtasks | |
} | |
} | |
public RRchart(String title) { | |
super(title); | |
// Simulation data | |
Process[] pt = new Process[5]; | |
pt[0] = new Process("A", 6, 0); // id, burst time, arrival time, | |
pt[1] = new Process("B", 4, 0); | |
pt[2] = new Process("C", 8, 0); | |
pt[3] = new Process("D", 3, 0); | |
pt[4] = new Process("E", 5, 0); | |
// Run simulation with quantum=4 | |
final int QUANTUM_SLICE = 3; | |
pt = simulateRR(pt, QUANTUM_SLICE); | |
// Create dataset for chart | |
IntervalCategoryDataset dataset = buildChartDataset(pt, "FCFS"); | |
// Create chart | |
JFreeChart chart = ChartFactory.createGanttChart( | |
"CPU Scheduling", // title | |
"Process", // X-Axis label | |
"Timeline", // Y-Axis label | |
dataset); | |
// set x-axis range from 0 | |
( chart.getCategoryPlot() ).setRangeAxis(new NumberAxis()); | |
ChartPanel panel = new ChartPanel(chart); | |
setContentPane(panel); | |
int totWaitTime = 0; | |
System.out.printf( "%10s %10s %10s %10s %10s %10s %10s\n", | |
"id","arrival/t","burst/t","start/t","waiting/t", | |
"t'round/t","stops(n)"); | |
for(int i=0; i < pt.length; i++) { | |
totWaitTime += pt[i].waitingTime; | |
System.out.printf("%10s %10s %10s %10s %10s %10s %10s\n", | |
pt[i].id, | |
pt[i].arrivalTime, | |
pt[i].burstTime, | |
pt[i].startTime, | |
pt[i].waitingTime, | |
pt[i].turnaroundTime, | |
pt[i].numOfTimesStopped); | |
} | |
System.out.println("\nTime quantum = " + QUANTUM_SLICE); | |
System.out.print("Avg waiting time (t) = "); | |
System.out.printf("%.2f\n", (float)totWaitTime / pt.length); | |
} | |
private Process[] simulateRR(Process[] pt, int quantum) | |
{ | |
// RR-queue, to manage the round-robin scheduling | |
class RRQItem { | |
public Process process; | |
public int remaining; | |
public int stopped; | |
} | |
Queue<RRQItem> rrQ = new LinkedList(); // Round-Robin queue | |
int clk_tick = 0; // reset clk_tick | |
int cpu_tick = 0; // timer for running process | |
boolean cpu_idle = true; // if not idle, then CPU is busy | |
int totDone = 0; | |
while(totDone < pt.length) { | |
// is it time to execute (submit to queue) ? | |
for(int p=0; p < pt.length; p++ ) { | |
if (clk_tick == pt[p].arrivalTime) { | |
// put inside RR-queue | |
RRQItem item = new RRQItem(); | |
item.process = pt[p]; | |
item.remaining = pt[p].burstTime; | |
item.stopped = pt[p].arrivalTime; | |
rrQ.add(item); | |
} | |
} | |
if(!cpu_idle) { | |
cpu_tick--; // deplete cpu burst time | |
if(cpu_tick <= 0) { // if timeout | |
// remove currently running process | |
RRQItem running = rrQ.remove(); | |
cpu_idle = true; | |
if(running.remaining > 0) { // if not yet finish | |
running.stopped = clk_tick; // record when this process | |
// is stopped | |
running.process.numOfTimesStopped++; // record stoppage | |
// count | |
rrQ.add(running); // put back into queue | |
} else { | |
// process finish, calculate turnaround time | |
running.process.turnaroundTime = | |
clk_tick - running.process.arrivalTime; | |
totDone++; | |
} | |
} | |
} | |
// if CPU idle, and no process is running | |
if(cpu_idle) { | |
// submit next remaining process in queue | |
if(!rrQ.isEmpty()) { | |
RRQItem front = rrQ.peek(); // check who is at | |
// the front of Q | |
if(front.process.startTime < 0) { // record the first | |
// time process start | |
front.process.startTime = clk_tick; // record starting | |
// time | |
} | |
front.process.waitingTime += clk_tick - front.stopped; | |
// submit and set for how long is the execution time | |
cpu_idle = false; | |
cpu_tick = (front.remaining >= quantum ? quantum : | |
front.remaining); | |
Process part = new Process( "" + front.process.id + "_" + | |
front.process.subtask.size(), cpu_tick, clk_tick); | |
part.startTime = clk_tick; | |
// record waiting time for this part | |
part.waitingTime = clk_tick - front.stopped; | |
// add new part (sub-process) | |
front.process.subtask.add( part ); | |
// update remaining time for this process | |
front.remaining -= cpu_tick; | |
} | |
} | |
clk_tick++; // update clk_tick | |
} | |
return pt; | |
} | |
private IntervalCategoryDataset buildChartDataset(Process[] pt, String label) { | |
TaskSeries series = new TaskSeries(label); | |
for(int i=0; i < pt.length; i++) { | |
Task t = new Task( pt[i].id, | |
new SimpleTimePeriod( pt[i].startTime, | |
pt[i].turnaroundTime)); | |
// show subtasks (if any) | |
for(int j=0; j < pt[i].subtask.size(); j++) { | |
Process p = pt[i].subtask.get(j); | |
Task subt = new Task( p.id, | |
new SimpleTimePeriod( p.startTime, p.startTime + | |
p.burstTime)); | |
t.addSubtask(subt); | |
} | |
series.add( t ); | |
} | |
TaskSeriesCollection dataset = new TaskSeriesCollection(); | |
dataset.add(series); | |
return dataset; | |
} | |
public static void main(String[] args) { | |
SwingUtilities.invokeLater(() -> { | |
RRchart chart = new RRchart("CPU Scheduling Algorithm"); | |
chart.setSize(800, 400); | |
chart.setLocationRelativeTo(null); | |
chart.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); | |
chart.setVisible(true); | |
}); | |
} | |
} |
Output yang dipaparkan daripada aplikasi simulasi penjadualan proses:
Subscribe to:
Posts (Atom)
-
Sumber : PRPM DBP - Kamus Dewan Edisi Empat Muat turun - (Komp) tindakan memindahkan fail dr stesen komputer utama ke stesen komputer pe...
-
Sebelum ini saya pernah menulis tentang kenapa kita (masyarakat) perlu menulis bahan-bahan bertulis / rujukan ilmiah ( Rujuk Sini ). Namun d...