-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathOS_Simulation.java
More file actions
597 lines (550 loc) · 23.1 KB
/
OS_Simulation.java
File metadata and controls
597 lines (550 loc) · 23.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
//OS Scheduling Simulator
// Build: javac OSSimBasic.java
// Run: java OSSimBasic
//
// What this does (simple):
// 1) Reads processes from a text file you enter at start.
// Columns: PID Arrival Burst Priority [Mem(optional)]
// If Mem is missing, we use need = Burst * 10 (just to have a number).
// 2) FCFS or Priority (non-preemptive) scheduling.
// 3) Prints a very plain Gantt chart and WT/TAT/averages/CPU Utilization.
// 4) Memory allocation: First-Fit, Best-Fit, Worst-Fit (fixed blocks you type).
// 5) Paging demo: FIFO.
import java.io.*;
import java.util.*;
public class OS_Simulation {
// Process class holds all info about a process
static class Process {
int pid; // process ID
int arrival; // arrival time
int burst; // CPU burst time
int priority; // priority number (lower = higher priority)
int mem; // memory needed (optional, 0 if not given)
// computed fields:
int start; // when the process starts executing
int completion; // when it finishes
int waiting; // waiting time
int tat; // turnaround time
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// get the input file name from user
System.out.print("Enter process file name (default: processes.txt): ");
String fname = sc.nextLine().trim();
if (fname.length() == 0) fname = "processes.txt";
// load all processes from the file
ArrayList<Process> processes = readProcesses(fname);
if (processes.size() == 0) {
System.out.println("No processes found in " + fname + ". Make sure the file exists.");
return;
}
// main menu loop
while (true) {
System.out.println("\n=== OS Simulator ===");
System.out.println("1) FCFS Scheduling");
System.out.println("2) Priority Scheduling (non-preemptive)");
System.out.println("3) Memory Allocation (First-Fit / Best-Fit / Worst-Fit)");
System.out.println("4) Paging (FIFO)");
System.out.println("q) Quit");
System.out.print("Choice: ");
String choice = sc.nextLine().trim();
if (choice.equalsIgnoreCase("q")) break;
// make a copy so we don't mess with the original list
ArrayList<Process> procs = copyList(processes);
if (choice.equals("1")) {
// FCFS scheduling
sortByArrivalThenPid(procs);
scheduleFCFS(procs);
printGantt(procs);
printMetrics(procs);
} else if (choice.equals("2")) {
// Priority scheduling
schedulePriority(procs);
printGantt(procs);
printMetrics(procs);
} else if (choice.equals("3")) {
// Memory allocation
System.out.println("\nEnter memory block sizes (comma separated). Example: 100,200,60,80");
String line = sc.nextLine().trim();
ArrayList<Integer> blocks = parseCSV(line);
if (blocks.size() == 0) {
System.out.println("No blocks given.");
} else {
System.out.print("Choose method (first/best/worst): ");
String method = sc.nextLine().trim().toLowerCase();
if (method.equals("first")) {
firstFit(blocks, procs);
} else if (method.equals("best")) {
bestFit(blocks, procs);
} else if (method.equals("worst")) {
worstFit(blocks, procs);
} else {
System.out.println("Unknown method.");
}
}
} else if (choice.equals("4")) {
// Paging simulation
System.out.print("\nEnter number of frames (e.g., 3): ");
int frames = 3;
try { frames = Integer.parseInt(sc.nextLine().trim()); } catch (Exception e) {}
ArrayList<Integer> refs = readRefs("references.txt");
if (refs.size() == 0) {
System.out.println("references.txt missing or empty. Put numbers like: 7 0 1 2 0 3 0 4");
} else {
fifoPaging(refs, frames);
}
} else {
System.out.println("Invalid choice.");
}
}
System.out.println("Bye.");
}
// --------------------- Reading Input ---------------------
// reads process data from a text file
static ArrayList<Process> readProcesses(String path) {
ArrayList<Process> list = new ArrayList<Process>();
try {
BufferedReader br = new BufferedReader(new FileReader(path));
String line;
boolean headerChecked = false;
while ((line = br.readLine()) != null) {
line = line.trim();
if (line.length() == 0) continue; // skip empty lines
// remove comments (anything after #)
int hash = line.indexOf('#');
if (hash >= 0) line = line.substring(0, hash).trim();
if (line.length() == 0) continue;
// check if first line is a header (has letters)
if (!headerChecked) {
headerChecked = true;
boolean hasLetter = false;
for (int i=0;i<line.length();i++) {
char c = line.charAt(i);
if (Character.isLetter(c)) { hasLetter = true; break; }
}
if (hasLetter) continue; // skip header
}
// parse process data: PID Arrival Burst Priority [Mem]
String[] parts = line.split("\\s+");
if (parts.length < 4) continue; // need at least 4 columns
Process p = new Process();
try {
p.pid = Integer.parseInt(parts[0]);
p.arrival = Integer.parseInt(parts[1]);
p.burst = Integer.parseInt(parts[2]);
p.priority = Integer.parseInt(parts[3]);
if (parts.length >= 5) {
p.mem = Integer.parseInt(parts[4]);
} else {
p.mem = 0; // will use burst*10 for memory later
}
list.add(p);
} catch (Exception e) {
// skip lines that can't be parsed
}
}
br.close();
} catch (Exception e) {
System.out.println("Could not read " + path + ": " + e.getMessage());
}
return list;
}
// reads page references from file (for paging simulation)
static ArrayList<Integer> readRefs(String path) {
ArrayList<Integer> refs = new ArrayList<Integer>();
try {
BufferedReader br = new BufferedReader(new FileReader(path));
String line;
while ((line = br.readLine()) != null) {
line = line.trim();
if (line.length() == 0) continue;
// split by spaces or commas
String[] parts = line.split("\\s+|,");
for (int i=0;i<parts.length;i++) {
String t = parts[i].trim();
if (t.length() == 0) continue;
try { refs.add(Integer.parseInt(t)); } catch (Exception e) {}
}
}
br.close();
} catch (Exception e) {
// ignore errors
}
return refs;
}
// --------------------- Helpers ---------------------
// makes a deep copy of process list so we don't modify the original
static ArrayList<Process> copyList(ArrayList<Process> src) {
ArrayList<Process> out = new ArrayList<Process>();
for (int i=0;i<src.size();i++) {
Process a = src.get(i);
Process b = new Process();
b.pid = a.pid;
b.arrival = a.arrival;
b.burst = a.burst;
b.priority = a.priority;
b.mem = a.mem;
out.add(b);
}
return out;
}
// sorts processes by arrival time, then by PID
static void sortByArrivalThenPid(ArrayList<Process> ps) {
// simple bubble sort
for (int i=0;i<ps.size();i++) {
for (int j=0;j+1<ps.size();j++) {
Process a = ps.get(j);
Process b = ps.get(j+1);
boolean swap = false;
if (a.arrival > b.arrival) swap = true;
else if (a.arrival == b.arrival && a.pid > b.pid) swap = true;
if (swap) {
ps.set(j, b);
ps.set(j+1, a);
}
}
}
}
// sorts by priority (lower number = higher priority), then arrival, then PID
static void sortByPriorityArrivalPid(ArrayList<Process> ps) {
for (int i=0;i<ps.size();i++) {
for (int j=0;j+1<ps.size();j++) {
Process a = ps.get(j);
Process b = ps.get(j+1);
boolean swap = false;
if (a.priority > b.priority) swap = true;
else if (a.priority == b.priority) {
if (a.arrival > b.arrival) swap = true;
else if (a.arrival == b.arrival && a.pid > b.pid) swap = true;
}
if (swap) {
ps.set(j, b);
ps.set(j+1, a);
}
}
}
}
// --------------------- Scheduling ---------------------
// First Come First Serve - runs processes in order they arrive
static void scheduleFCFS(ArrayList<Process> ps) {
int time = 0; // current time
for (int i=0;i<ps.size();i++) {
Process p = ps.get(i);
// if CPU is idle, jump to arrival time
if (time < p.arrival) time = p.arrival;
p.start = time;
time += p.burst; // run the process
p.completion = time;
p.waiting = p.start - p.arrival;
p.tat = p.completion - p.arrival;
}
}
// Priority Scheduling - runs highest priority process first (non-preemptive)
static void schedulePriority(ArrayList<Process> ps) {
ArrayList<Process> done = new ArrayList<Process>(); // tracks finished processes
int time = 0;
int finished = 0;
int n = ps.size();
while (finished < n) {
// find all processes that have arrived
ArrayList<Process> avail = new ArrayList<Process>();
for (int i=0;i<n;i++) {
Process p = ps.get(i);
if (!done.contains(p) && p.arrival <= time) {
avail.add(p);
}
}
// if no process available, jump to next arrival
if (avail.size() == 0) {
int nextArr = Integer.MAX_VALUE;
for (int i=0;i<n;i++) {
Process p = ps.get(i);
if (!done.contains(p)) {
if (p.arrival < nextArr) nextArr = p.arrival;
}
}
if (nextArr == Integer.MAX_VALUE) break;
time = nextArr;
continue;
}
// pick the highest priority process
sortByPriorityArrivalPid(avail);
Process run = avail.get(0);
run.start = time;
time += run.burst; // run it completely
run.completion = time;
run.waiting = run.start - run.arrival;
run.tat = run.completion - run.arrival;
done.add(run);
finished++;
}
// sort by start time for better Gantt chart display
for (int i=0;i<ps.size();i++) {
for (int j=0;j+1<ps.size();j++) {
if (ps.get(j).start > ps.get(j+1).start) {
Process a = ps.get(j);
Process b = ps.get(j+1);
ps.set(j, b);
ps.set(j+1, a);
}
}
}
}
// --------------------- Output ---------------------
// prints a simple Gantt chart showing process execution
static void printGantt(ArrayList<Process> ps) {
if (ps.isEmpty()) { System.out.println("(no processes)"); return; }
// make sure processes are ordered by start time
for (int i=0;i<ps.size();i++) {
for (int j=0;j+1<ps.size();j++) {
if (ps.get(j).start > ps.get(j+1).start) {
Process a = ps.get(j);
Process b = ps.get(j+1);
ps.set(j, b);
ps.set(j+1, a);
}
}
}
StringBuilder top = new StringBuilder();
StringBuilder times = new StringBuilder();
int cur = ps.get(0).start;
// helper function to place time numbers below the chart
java.util.function.IntConsumer placeTimeAtBar = (t) -> {
int barPos = top.length();
while (times.length() < barPos) times.append(' ');
String s = String.valueOf(t);
times.append(s);
};
// start with the initial time
placeTimeAtBar.accept(cur);
while (times.length() < top.length()) times.append(' ');
// build the chart
for (int i=0;i<ps.size();i++) {
Process p = ps.get(i);
// if there's idle time, show it
if (cur < p.start) {
top.append("| IDLE ");
while (times.length() < top.length()) times.append(' ');
cur = p.start;
placeTimeAtBar.accept(cur);
while (times.length() < top.length()) times.append(' ');
}
// show the running process
top.append("| P").append(p.pid).append(' ');
while (times.length() < top.length()) times.append(' ');
cur = p.completion;
placeTimeAtBar.accept(cur);
while (times.length() < top.length()) times.append(' ');
}
top.append('|'); // close the chart
System.out.println("\nGantt Chart:");
System.out.println(top.toString());
System.out.println(times.toString());
}
// prints metrics for each process and averages
static void printMetrics(ArrayList<Process> ps) {
System.out.println("\nPer-Process Metrics:");
System.out.println("PID Arr Burst Prio Start Comp WT TAT");
double sumWT = 0;
double sumTAT = 0;
int maxEnd = 0;
int busy = 0; // total CPU busy time
// find max completion time and total burst time
for (int i=0;i<ps.size();i++) {
Process p = ps.get(i);
if (p.completion > maxEnd) maxEnd = p.completion;
busy += p.burst;
}
// print each process
for (int i=0;i<ps.size();i++) {
Process p = ps.get(i);
sumWT += p.waiting;
sumTAT += p.tat;
System.out.printf("%-4d %-4d %-6d %-5d %-6d %-5d %-3d %-4d\n",
p.pid, p.arrival, p.burst, p.priority, p.start, p.completion, p.waiting, p.tat);
}
// calculate and print averages
double avgWT = sumWT / ps.size();
double avgTAT = sumTAT / ps.size();
double util = 0.0;
if (maxEnd > 0) util = (100.0 * busy) / maxEnd;
System.out.printf("\nAverage Waiting Time: %.2f\n", avgWT);
System.out.printf("Average Turnaround Time: %.2f\n", avgTAT);
System.out.printf("CPU Utilization: %.2f%%\n", util);
}
// --------------------- Memory (First/Best/Worst Fit) ---------------------
// parses comma-separated values from a string
static ArrayList<Integer> parseCSV(String s) {
ArrayList<Integer> out = new ArrayList<Integer>();
String[] parts = s.split(",");
for (int i=0;i<parts.length;i++) {
String t = parts[i].trim();
if (t.length() == 0) continue;
try { out.add(Integer.parseInt(t)); } catch (Exception e) {}
}
return out;
}
// figures out how much memory a process needs
static int needFor(Process p) {
if (p.mem > 0) return p.mem;
return p.burst * 10; // use burst*10 if mem not specified
}
// displays current state of memory blocks
static void showBlocks(ArrayList<Integer> blocks, int[] blockPid, int[] blockWaste) {
System.out.println("\nMemory Blocks:");
int totalWaste = 0;
int totalFree = 0;
for (int b=0;b<blocks.size();b++) {
int size = blocks.get(b);
if (blockPid[b] == -1) {
System.out.println(" Block " + b + " [" + size + "] : FREE");
totalFree += size;
} else {
System.out.println(" Block " + b + " [" + size + "] : P" + blockPid[b] + " (waste " + blockWaste[b] + ")");
totalWaste += blockWaste[b];
}
}
System.out.println("Total internal fragmentation (waste): " + totalWaste);
System.out.println("Total free memory: " + totalFree);
}
// First-Fit: allocates process to the first block that fits
static void firstFit(ArrayList<Integer> blocks, ArrayList<Process> ps) {
int[] blockPid = new int[blocks.size()]; // which process is in each block
int[] blockWaste = new int[blocks.size()]; // wasted space in each block
for (int i=0;i<blockPid.length;i++) { blockPid[i] = -1; blockWaste[i] = 0; }
ArrayList<Integer> notPlaced = new ArrayList<Integer>(); // processes that couldn't fit
for (int i=0;i<ps.size();i++) {
Process p = ps.get(i);
int need = needFor(p);
int where = -1;
// find first free block that's big enough
for (int b=0;b<blocks.size();b++) {
if (blockPid[b] == -1 && blocks.get(b) >= need) { where = b; break; }
}
if (where != -1) {
blockPid[where] = p.pid;
blockWaste[where] = blocks.get(where) - need;
} else {
notPlaced.add(p.pid);
}
}
showBlocks(blocks, blockPid, blockWaste);
if (notPlaced.size() > 0) {
System.out.print("Could not place processes: ");
for (int i=0;i<notPlaced.size();i++) {
if (i>0) System.out.print(", ");
System.out.print("P"+notPlaced.get(i));
}
System.out.println();
}
}
// Best-Fit: allocates process to the smallest block that fits
static void bestFit(ArrayList<Integer> blocks, ArrayList<Process> ps) {
int[] blockPid = new int[blocks.size()];
int[] blockWaste = new int[blocks.size()];
for (int i=0;i<blockPid.length;i++) { blockPid[i] = -1; blockWaste[i] = 0; }
ArrayList<Integer> notPlaced = new ArrayList<Integer>();
for (int i=0;i<ps.size();i++) {
Process p = ps.get(i);
int need = needFor(p);
int best = -1;
int bestWaste = Integer.MAX_VALUE;
// find the block with minimum waste
for (int b=0;b<blocks.size();b++) {
if (blockPid[b] == -1 && blocks.get(b) >= need) {
int waste = blocks.get(b) - need;
if (waste < bestWaste) {
bestWaste = waste;
best = b;
}
}
}
if (best != -1) {
blockPid[best] = p.pid;
blockWaste[best] = blocks.get(best) - need;
} else {
notPlaced.add(p.pid);
}
}
showBlocks(blocks, blockPid, blockWaste);
if (notPlaced.size() > 0) {
System.out.print("Could not place processes: ");
for (int i=0;i<notPlaced.size();i++) {
if (i>0) System.out.print(", ");
System.out.print("P"+notPlaced.get(i));
}
System.out.println();
}
}
// Worst-Fit: allocates process to the largest available block
static void worstFit(ArrayList<Integer> blocks, ArrayList<Process> ps) {
int[] blockPid = new int[blocks.size()];
int[] blockWaste = new int[blocks.size()];
for (int i=0;i<blockPid.length;i++) { blockPid[i] = -1; blockWaste[i] = 0; }
ArrayList<Integer> notPlaced = new ArrayList<Integer>();
for (int i=0;i<ps.size();i++) {
Process p = ps.get(i);
int need = needFor(p);
int worst = -1;
int worstSize = -1;
// find the largest free block
for (int b=0;b<blocks.size();b++) {
if (blockPid[b] == -1 && blocks.get(b) >= need) {
int size = blocks.get(b);
if (size > worstSize) {
worstSize = size;
worst = b;
}
}
}
if (worst != -1) {
blockPid[worst] = p.pid;
blockWaste[worst] = blocks.get(worst) - need;
} else {
notPlaced.add(p.pid);
}
}
showBlocks(blocks, blockPid, blockWaste);
if (notPlaced.size() > 0) {
System.out.print("Could not place processes: ");
for (int i=0;i<notPlaced.size();i++) {
if (i>0) System.out.print(", ");
System.out.print("P"+notPlaced.get(i));
}
System.out.println();
}
}
// --------------------- Paging (FIFO) ---------------------
// FIFO page replacement - replaces the oldest page in memory
static void fifoPaging(ArrayList<Integer> refs, int frames) {
int faults = 0; // count of page faults
ArrayList<Integer> frame = new ArrayList<Integer>(); // pages currently in memory
int head = 0; // points to oldest page (for replacement)
for (int i=0;i<refs.size();i++) {
int r = refs.get(i); // current page reference
boolean hit = false;
// check if page is already in a frame
for (int f=0; f<frame.size(); f++) {
if (frame.get(f) == r) { hit = true; break; }
}
if (!hit) {
faults++; // page fault occurred
if (frame.size() < frames) {
// still have empty frames
frame.add(r);
} else {
// replace oldest page
frame.set(head, r);
head = (head + 1) % frames; // move pointer to next oldest
}
}
}
// calculate and print results
double rate = 0.0;
if (refs.size() > 0) rate = (100.0 * faults) / refs.size();
System.out.println("\nPaging FIFO with " + frames + " frames");
System.out.println("References: " + refs.size());
System.out.println("Page faults: " + faults);
System.out.printf("Fault rate: %.2f%%\n", rate);
}
}