jsos
college code for operating system fundamentals in js
git clone https://9o.is/git/jsos.git
commit 73e49beb3447b36a76c501b2e78116e19a99f33a parent b0354fa7a1147a450f0643042512f92b690b15a3 Author: Jul <jul@9o.is> Date: Tue, 11 Dec 2012 10:02:43 -0500 CPU monitors. Diffstat:
| M | globals.js | | | 1 | - |
| M | index.html | | | 59 | +++++++++++++++++++++++++++++------------------------------ |
| M | scripts/host/memory.js | | | 18 | ++++++++++++++++++ |
| M | scripts/os/deviceDriverFilesystem.js | | | 272 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------- |
| M | scripts/os/memoryManager.js | | | 121 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------- |
| M | scripts/os/pcb.js | | | 1 | + |
| M | scripts/os/scheduler.js | | | 149 | +++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------- |
| M | styles/julios.css | | | 4 | ++++ |
8 files changed, 454 insertions(+), 171 deletions(-)
diff --git a/globals.js b/globals.js @@ -83,7 +83,6 @@ var TOTAL_PAGES = 3; var SWAPPABLE = 1; var MAX_MEMORY_PROGRAM = 256; //bytes var TOTAL_MEMORY = TOTAL_PAGES * MAX_MEMORY_PROGRAM; //bytes -var TOTAL_PAGES_AND_SWAPS = TOTAL_PAGES + SWAPPABLE; // pcb states var PCB_STATE_RESIDENT = "resident"; diff --git a/index.html b/index.html @@ -91,36 +91,6 @@ <div class="tabscontent"> <div class="tabpage" id="tabpage_1"> - <div style="float:left"> - <b><span id="cpu_utilization">Utilization: 0%</span></b><br> - <canvas id="cpu_utilization_bar" width="160" - height="7"></canvas><br> - <canvas id="cpu_utilization_graph" width="160" - height="100"></canvas> - </div> - - <div style="float:right"> - <b><span id="cpu_throughput">Throughput: 0%</span></b><br> - <canvas id="cpu_throughput_bar" width="160" - height="7"></canvas><br> - <canvas id="cpu_throughput_graph" width="160" - height="100"></canvas> - </div> - - <div style="float:left"> - <b><div id="cpu_turnaround">Turn Around: 0%</div></b> - <canvas id="cpu_turnaround_graph" width="160" - height="100"></canvas> - </div> - - <div style="float:right"> - <b><div id="cpu_wait">Wait: 0%</div></b> - <canvas id="cpu_wait_graph" width="160" - height="100"></canvas> - </div> - - <div style="clear:both"></div> - <div> <h4>Registers</h4> <table> @@ -150,9 +120,38 @@ <div> <h4>Processes</h4> <table cellspacing="7" id="processesTable"> + <tr><td>No Processes Loaded</td></tr> </table> </div> + <div> + <b><span id="cpuUtilization">Utilization: 0%</span></b><br> + <canvas id="cpuUtilizationBar" class="monitor" width="300" + height="7"></canvas><br> + <canvas id="cpuUtilizationGraph" class="monitor" width="300" + height="200"></canvas> + </div> + + <div> + <b><span id="cpuThroughput">Throughput: 0%</span></b><br> + <canvas id="cpuThroughputBar" class="monitor" width="300" + height="7"></canvas><br> + <canvas id="cpuThroughputGraph" class="monitor" width="300" + height="200"></canvas> + </div> + + <div> + <b><div id="cpuTurnaround">Turn Around: 0</div></b> + <canvas id="cpuTurnaroundGraph" class="monitor" width="300" + height="200"></canvas> + </div> + + <div> + <b><div id="cpuWait">Wait: 0</div></b> + <canvas id="cpuWaitGraph" class="monitor" width="300" + height="200"></canvas> + </div> + </div> <div class="tabpage" id="tabpage_2"> diff --git a/scripts/host/memory.js b/scripts/host/memory.js @@ -52,6 +52,24 @@ function memory(maxBytes) { } /* + * Deallocates an array of bytes starting from base. + */ + this.deallocateBytes = function(base, limit) { + var result = []; + this.showOutput = false; + + for(var i=base; i<=limit; i++) { + result[i-base] = this.getByte(i) + this.setByte(0, i); + } + + this.showOutput = true; + this.output(); + + return result; + } + + /* * Gets byte value in a location. */ this.getByte = function(location) { diff --git a/scripts/os/deviceDriverFilesystem.js b/scripts/os/deviceDriverFilesystem.js @@ -4,22 +4,6 @@ Requires deviceDriver.js The Kernel Filesystem Device Driver. - - - Header format for each block: - status , track , sector , block (1 byte each) - - header: 4 bytes - payload: 60 bytes - - Status represents type and availability flag bits: - - ---------------------------------------- - |X|X|X|X|X| type | type | availability | - ---------------------------------------- - - file types: 0=text, 1=directory, 2=swap - availability: 0=available 1=unavailable ---------------------------------- */ @@ -48,10 +32,6 @@ function DeviceDriverFilesystem() { this.status = "loaded"; }; - this.isr = function() { - //TODO - }; - /* * Formats entire filesystem by setting it to intial use. */ @@ -72,35 +52,36 @@ function DeviceDriverFilesystem() { return true; }; - this.allDirectories = function(dir) { - var dirs = [dir]; - var directories = dir.directories(); - while(directories.length != 0) { - for(i=0; i<directories.length; i++) { - dirs.concat(this.allDirectories(directories[i])); - } - } - return dirs; - }; - + /* + * Initializes a block with type text & as unavailable + * with next block (0,0,0) & GS=1D + */ this.initBlockTextFile = function(ts) { - // type text & unavailable -- next block (0,0,0) & GS=1D var value = ["1","0","0","0","1d"]; _Disk.write(ts,value, true); }; + /* + * Initializes a block with type directory & as + * unavailable with next block (0,0,0) & GS=1D + */ this.initBlockDirectory = function(ts) { - // type dir & unavailable -- next block (0,0,0) & GS=1D var value = ["3","0","0","0","1d"]; _Disk.write(ts,value, true); }; - this.initBlockData = function(ts, type) { - // type set & unavailable -- next block (0,0,0) - var value = [type,"0","0","0"]; + /* + * Initializes a block with type swap & as unavailable + * with next block (0,0,0) + */ + this.initBlockSwap = function(ts) { + var value = ["5","0","0","0"]; _Disk.write(ts,value, true); }; + /* + * Finds an available block in disk. + */ this.getAvailableBlock = function() { for(t=1; t<=_Disk.TRACKS; t++) for(s=1; s<=_Disk.SECTORS; s++) @@ -113,6 +94,9 @@ function DeviceDriverFilesystem() { return undefined; }; + /* + * Creates a text file with a name. + */ this.createTextFile = function(fn) { fn = fn.trim(); fn = this.rename(fn); @@ -125,6 +109,9 @@ function DeviceDriverFilesystem() { return this.cd.addTextFile(textFile); }; + /* + * Creates a directory file with a name. + */ this.createDirectory = function(fn) { fn = fn.trim(); fn = this.rename(fn); @@ -137,6 +124,9 @@ function DeviceDriverFilesystem() { return this.cd.addDirectory(dir); }; + /* + * Writes text to a text file under a name. + */ this.writeTextFile = function(fn, text) { fn = fn.trim(); var file = this.cd.getTextFile(fn); @@ -144,6 +134,9 @@ function DeviceDriverFilesystem() { return file.setText(text); }; + /* + * Reads text to a text file under a name. + */ this.readTextFile = function(fn) { fn = fn.trim(); var file = this.cd.getTextFile(fn); @@ -152,15 +145,24 @@ function DeviceDriverFilesystem() { return file.text(); }; + /* + * Deletes a file with a name. + */ this.deleteFile = function(fn) { fn = fn.trim(); return this.cd.deleteFile(fn); }; + /* + * List working directory contents. + */ this.ls = function() { return this.cd.directories().concat(this.cd.textFiles()); }; + /* + * Changes working directory. + */ this.changeDirectory = function(fn) { fn = fn.trim(); @@ -183,7 +185,10 @@ function DeviceDriverFilesystem() { return false; }; - // rename if existing filename in this current directory + /* + * Rename file name if existing file name is in this + * working directory. Pads it with zero (exponentially). + */ this.rename = function(name,suffix) { if(suffix==undefined) suffix=0; @@ -204,6 +209,38 @@ function DeviceDriverFilesystem() { }; }; + +/*---------------------------------------------------------- + + Anything saved in disk is a file. + One file can take multiple blocks in disk. + + Header format for each block: + status , track , sector , block (1 byte each) + + header: 4 bytes + payload: 60 bytes + + Status represents type and availability flag bits: + + ---------------------------------------- + |X|X|X|X|X| type | type | availability | + ---------------------------------------- + + file types: 0=text, 1=directory, 2=swap + availability: 0=available 1=unavailable + + + Header(4 bytes) + ----------------------------------- + | Status | Track | Sector | Block | + ----------------------------------- + + Track, Sector, Block points to the next block in disk if + the payload is greater than 60 bytes. It's set to zero + if it's the last block in the file. + +----------------------------------------------------------*/ function File(TSB) { this.TYPE_TEXT = 0; @@ -242,6 +279,16 @@ function File(TSB) { for(i=1; i<this.all_tsb.length; i++) _Disk.write(this.all_tsb[i], [0], true); this.all_tsb = this.all_tsb.slice(0,1); + + // clear data in all tsb's + var header = this.data().slice(0, this.HEADER_SIZE); + while(this.next(header) != undefined) { + var tsb = this.next(header); + var extData = _Disk.read(tsb); + header = extData.slice(0, this.HEADER_SIZE); + _Disk.write(tsb, [0], clear); + } + } else { data = this.data().concat(data); } @@ -249,6 +296,9 @@ function File(TSB) { return this.writeData(data, clear); } + /* + * Called by this write function. + */ this.writeData = function(data,clear) { var ts = this.tsb; while(data.length > 0) { @@ -282,6 +332,10 @@ function File(TSB) { return new tsb(track, sector, block); }; + /* + * Sets the next, contuining block so data can grow over + * fixed block size. + */ this.setNext = function(tsb, tsbNext) { return _Disk.writeByte(tsb,2, tsbNext.track) && _Disk.writeByte(tsb,3, tsbNext.sector) && @@ -320,21 +374,38 @@ function File(TSB) { }; }; -/* - * A directory in a filesystem. - * Header format for each directory is the name of the - * directory. Name can be any length so header is not a - * fixed size. Header and payload is separated by a - * "group separator" (hex=1D). - * - * Payload format is a list of TSB's (3 bytes each) that - * point to other directories and files. - * The first TSB is the parent directory. - */ + + +/*---------------------------------------------------------- + + A directory is a type of file with a file header and payload. + + + Format of the payload: + ----------------------------- + | File Name | GS | Data.... | + ----------------------------- + + The first thing in the payload is the file name that can + be any length. The file name is separated by a + "Group Separator" (hex value: 0x1D). + + The rest of the payload is a listing of all files' + track-sector-block location. + --------------------------------------------------------- + | track | sector | block | track | sector | block | etc | + --------------------------------------------------------- + + The first TSB is the parent directory. + +----------------------------------------------------------*/ Directory.prototype = new File(); function Directory(TSB) { File.call(this, TSB); + /* + * Returns a directory of this directory's parent directory. + */ this.parentDirectory = function() { if(this.tsb.toString() != "111") { // not root directory var ts = this.data().slice(this.gs()+1, this.gs()+4); @@ -343,6 +414,10 @@ function Directory(TSB) { return undefined; }; + /* + * Returns the location of the group separator. + * @param Including only the payload? + */ this.gs = function(payload) { var data = payload ? this.payload() : this.data(); @@ -351,6 +426,9 @@ function Directory(TSB) { return i; }; + /* + * Returns the name of this file. + */ this.name = function() { var hex_name = this.data().slice(this.HEADER_SIZE, this.gs(false)); var name = ""; @@ -361,6 +439,10 @@ function Directory(TSB) { return name; }; + /* + * Returns all files in this directory, + * including text files and directories. + */ this.files = function() { var data = this.payload(); data = data.slice(this.gs(true)+1, data.length); @@ -375,6 +457,9 @@ function Directory(TSB) { return files; }; + /* + * Returns all directories in this directory. + */ this.directories = function() { var dirs = []; var files = this.files(); @@ -389,6 +474,9 @@ function Directory(TSB) { return dirs; }; + /* + * Returns the directory that matches the specified name. + */ this.getDirectory = function(fn) { var directories = this.directories(); for(var i=0; i<directories.length; i++) @@ -397,6 +485,9 @@ function Directory(TSB) { return undefined; }; + /* + * Returns all text files in this directory. + */ this.textFiles = function() { var textFiles = []; var files = this.files(); @@ -407,6 +498,9 @@ function Directory(TSB) { return textFiles; }; + /* + * Returns the text file that matches the specified name. + */ this.getTextFile = function(fn) { var textFiles = this.textFiles(); for(var i=0; i < textFiles.length; i++) @@ -415,6 +509,9 @@ function Directory(TSB) { return undefined; }; + /* + * Adds a directory in this directory. + */ this.addDirectory = function(dir) { dir.write(dir.data().concat([this.tsb.track,this.tsb.sector,this.tsb.block]), true); var tsb = dir.tsb; @@ -422,12 +519,18 @@ function Directory(TSB) { return this.write(data, true); }; + /* + * Adds a text file in this directory. + */ this.addTextFile = function(textFile) { var tsb = textFile.tsb; var data = this.data().concat([tsb.track, tsb.sector, tsb.block]); return this.write(data, true); }; + /* + * Deletes a file in this directory matching name. + */ this.deleteFile = function(name) { var file = undefined; var directories = this.directories(); @@ -457,6 +560,9 @@ function Directory(TSB) { } }; + /* + * Deletes a track-sector-block in this directory listing. + */ this.deleteTSB = function(tsb) { var data = this.data(); var header = data.slice(0, this.gs(false)+1); @@ -475,6 +581,9 @@ function Directory(TSB) { return false; }; + /* + * Sets the name of this file. + */ this.setName = function(name) { var data = this.data(); data = data.slice(0, this.HEADER_SIZE).concat( @@ -485,19 +594,33 @@ function Directory(TSB) { }; }; -/* - * A file in a filesystem. - * Header format for each file is the name of the - * file. Name can be any length so header is not a - * fixed size. Header and payload is separated by a - * "group separator" (hex=1D). - * - * Payload format is the ascii hex data of a file. - */ + + +/*---------------------------------------------------------- + + A text file is a type of file with a file header and payload. + + + Format of the payload: + ----------------------------- + | File Name | GS | Data.... | + ----------------------------- + + The first thing in the payload is the file name that can + be any length. The file name is separated by a + "Group Separator" (hex value: 0x1D). + + The rest of the payload is just ASCII bytes (in hex format). + +----------------------------------------------------------*/ TextFile.prototype = new File(); function TextFile(TSB) { File.call(this, TSB); + /* + * Returns the location of the group separator. + * @param Including only the payload? + */ this.gs = function(payload) { var data = payload ? this.payload() : this.data(); @@ -506,6 +629,9 @@ function TextFile(TSB) { return i; }; + /* + * Gets the name of this file. + */ this.name = function() { var hex_name = this.data().slice(this.HEADER_SIZE, this.gs(false)); var name = ""; @@ -516,6 +642,9 @@ function TextFile(TSB) { return name; }; + /* + * Gets the text of this file. + */ this.text = function() { var data = this.payload(); data = data.slice(this.gs(true)+1, data.length); @@ -527,6 +656,9 @@ function TextFile(TSB) { return text; }; + /* + * Sets the name of this file. + */ this.setName = function(name) { var data = this.data(); data = data.slice(0, this.HEADER_SIZE).concat( @@ -536,21 +668,29 @@ function TextFile(TSB) { return this.write(data, true); }; + /* + * Sets the text of this file. + */ this.setText = function(text) { var data = this.data().slice(0, this.gs(false)+1).concat(ascii2hex(text)); return this.write(data,true); }; }; -/* - * A file in a filesystem. - * Header format for each file is the name of the - * file. Name can be any length so header is not a - * fixed size. Header and payload is separated by a - * "group separator" (hex=1D). - * - * Payload format is the ascii hex data of a file. - */ + +/*---------------------------------------------------------- + + A swap is a type of file with a file header and payload. + + + Format of the payload: + ------------ + | Data.... | + ------------ + + Nothing special. + +----------------------------------------------------------*/ Swap.prototype = new File(); function Swap(TSB) { File.call(this, TSB); diff --git a/scripts/os/memoryManager.js b/scripts/os/memoryManager.js @@ -3,9 +3,6 @@ */ function MemoryManager() { this.processes = new Array(); // array of pcb's - - /* Points to the location of a swapped process. */ - this.swap = {}; /* * Loads a hex program into memory. @@ -13,26 +10,46 @@ function MemoryManager() { */ this.load = function(hex, priority) { var pid = this.getAvailablePage(); - if(pid < 0) { + var availableSwap = undefined; + + // if we get available page + if (pid > -1) { + var page = pid % TOTAL_PAGES; + var bytes = this.hex2Dec(hex); + var base = page * MAX_MEMORY_PROGRAM; + var limit = (page+1) * MAX_MEMORY_PROGRAM - 1; + var process = new pcb(pid, PCB_STATE_RESIDENT, base, limit, base, priority); + this.processes[page] = process; + _Memory.allocateBytes(bytes, base); + this.output(); return pid; + } else { + availableSwap = this.getAvailableSwap(); } - var page = pid % TOTAL_PAGES; - var bytes = this.hex2Dec(hex); - var base = page * MAX_MEMORY_PROGRAM; - var limit = (page+1) * MAX_MEMORY_PROGRAM - 1; - var process = new pcb(pid, PCB_STATE_RESIDENT, base, limit, base, priority); - this.processes[page] = process; - _Memory.allocateBytes(bytes, base); + // if we get available swap + if (availableSwap.pid > -1) { + pid = availableSwap.pid; + var block = availableSwap.tsb; - this.output(); -/* - if(this.processes.length <= TOTAL_PAGES_AND_SWAPS) { - this.swap.pid = pid; - this.swap.tsb = krnFilesystemDriver.getAvailableBlock(); - this.rollOut(); + if(block == undefined) { + block = krnFilesystemDriver.getAvailableBlock(); + krnFilesystemDriver.initBlockSwap(block); + } + + var page = pid - (((pid - TOTAL_PAGES) % (SWAPPABLE + 1)) + 1); + var bytes = this.hex2Dec(hex); + var base = page * MAX_MEMORY_PROGRAM; + var limit = (page+1) * MAX_MEMORY_PROGRAM - 1; + var process = new pcb(pid, PCB_STATE_RESIDENT, base, limit, base, priority); + process.tsb = block; + + this.processes[pid] = process; + var swap = new Swap(block); + swap.write(swap.data().slice(0, swap.HEADER_SIZE).concat(this.dec2Hex(hex)), true); + this.output(); } -*/ + return pid; } @@ -46,25 +63,57 @@ function MemoryManager() { if(p == undefined) return i; if(p.state == PCB_STATE_TERMINATED) - return p.PID+TOTAL_PAGES; + return p.PID; } return -1; } /* + * Gets the next available swap in disk. Returns -1 if + * there is no swap available. + */ + this.getAvailableSwap = function() { + for(var i=TOTAL_PAGES; i<TOTAL_PAGES+SWAPPABLE; i++) { + var p = this.processes[i]; + if(p == undefined) { + return {pid: i, tsb: undefined}; + } + if(p.state == PCB_STATE_TERMINATED) { + return {pid: p.PID, tsb: p.tsb}; + } + } + return {pid: -1, tsb: {}}; + } + + /* * Swaps an entire process by "rolling out" or transfering * a process to swap files in the disk drive. */ - this.rollOut = function() { - + this.rollOut = function(tsb, pid) { + var pid = TOTAL_PAGES-1 != pid ? TOTAL_PAGES-1 : TOTAL_PAGES; //TODO fixed + var process = this.processes[pid]; + process.tsb = tsb; + + var swap = new Swap(tsb); + var data = _Memory.deallocateBytes(process.base, process.limit); + var hex = this.dec2Hex(data); + + swap.write(swap.data().slice(0, swap.HEADER_SIZE).concat(hex), true); } /* * Swaps an entire process by "rolling in" or transfering * a process to memory from swap files in the disk drive. */ - this.rollIn = function() { + this.rollIn = function(process) { + var swap = new Swap(process.tsb); + var data = swap.payload(); + this.rollOut(process.tsb, process.PID); + process.tsb = undefined; + + var bytes = this.hex2Dec(data); + _Memory.allocateBytes(bytes, process.base); } /* @@ -77,6 +126,17 @@ function MemoryManager() { } /* + * Converts an array of decimals to an array of hexadecimals. + */ + this.dec2Hex = function(hex) { + for(var i=0; i<hex.length; i++) { + if(hex[i] != undefined) + hex[i] = hex[i].toString(16); + } + return hex; + } + + /* * Outputs pcb attributes of each process in control of this * OS's memory manager to the interface. */ @@ -86,14 +146,25 @@ function MemoryManager() { '<tr><th>pid</th><th>state</th><th>base</th>' + '<th>limit</th><th>PC</th><th>ACC</th><th>X</th>' + '<th>Y</th><th>Z</th><th>P</th></tr>'; + for(var i=0; i<this.processes.length; i++) { var p = this.processes[i]; + var base=p.base-((p.PID%TOTAL_PAGES)*MAX_MEMORY_PROGRAM); + var limit=p.limit-((p.PID%TOTAL_PAGES)*MAX_MEMORY_PROGRAM); + var pc=p.PC-((p.PID%TOTAL_PAGES)*MAX_MEMORY_PROGRAM); + + if(p.PID >= TOTAL_PAGES) { + base=p.base-((p.PID-(((p.PID - TOTAL_PAGES) % (SWAPPABLE + 1)) + 1))*MAX_MEMORY_PROGRAM); + limit=p.limit-((p.PID-(((p.PID - TOTAL_PAGES) % (SWAPPABLE + 1)) + 1))*MAX_MEMORY_PROGRAM); + pc=p.PC-((p.PID-(((p.PID - TOTAL_PAGES) % (SWAPPABLE + 1)) + 1))*MAX_MEMORY_PROGRAM); + } + html += '<tr>'; html += '<td>'+p.PID+'</td>'; html += '<td>'+p.state+'</td>'; - html += '<td>'+pad((p.base-((p.PID%TOTAL_PAGES)*MAX_MEMORY_PROGRAM)).toString(16),4).toUpperCase()+'</td>'; - html += '<td>'+pad((p.limit-((p.PID%TOTAL_PAGES)*MAX_MEMORY_PROGRAM)).toString(16),4).toUpperCase()+'</td>'; - html += '<td>'+pad((p.PC-((p.PID%TOTAL_PAGES)*MAX_MEMORY_PROGRAM)).toString(16),4).toUpperCase()+'</td>'; + html += '<td>'+pad((base).toString(16),4).toUpperCase()+'</td>'; + html += '<td>'+pad((limit).toString(16),4).toUpperCase()+'</td>'; + html += '<td>'+pad((pc).toString(16),4).toUpperCase()+'</td>'; html += '<td>'+pad(p.ACC.toString(16),2).toUpperCase()+'</td>'; html += '<td>'+pad(p.X.toString(16),2).toUpperCase()+'</td>'; html += '<td>'+pad(p.Y.toString(16),2).toUpperCase()+'</td>'; diff --git a/scripts/os/pcb.js b/scripts/os/pcb.js @@ -12,6 +12,7 @@ function pcb(pid, state, base, limit, pc, priority) { this.Y = 0; this.Z = 0; this.priority = priority; + this.tsb = undefined; this.arrival = undefined; this.end = undefined; this.bursts = 0; diff --git a/scripts/os/scheduler.js b/scripts/os/scheduler.js @@ -37,6 +37,13 @@ function scheduler() { this.addHistory(p); p = _KernelReadyQueue.pop(); } + + // is it in disk & not memory + if(p.tsb != undefined) { + krnTrace("Rolling in "+p.PID+" by swapping."); + _KernelMemoryManager.rollIn(p); + } + this.setRunningProcess(p); krnTrace("Adding PID "+p.PID+" by context switch."); } @@ -104,7 +111,9 @@ function scheduler() { * CPU Throughput */ this.throughput = function() { - var n = this.history.length / this.busyTime; + var n = 0; + if(this.busyTime > 0) + n = this.history.length / this.busyTime; return Math.round(n*100); } @@ -120,7 +129,9 @@ function scheduler() { total += (p.end - p.arrival); } - return total / length; + if(length > 0) + return Math.round(total / length); + return 0; } /* @@ -135,7 +146,9 @@ function scheduler() { total += (p.end - p.arrival - p.bursts); } - return total / length; + if(length > 0) + return Math.round(total / length); + return 0; } this.addHistory = function(p) { @@ -151,70 +164,108 @@ function scheduler() { // instead of the whole OSclock since the OS is mostly // always idle. this.output = function() { - document.getElementById("cpu_utilization").innerHTML = - "Utilization: "+this.utilization()+"%"; + var utilization = this.utilization(); + var throughput = this.throughput(); + var turnAround = this.turnAround(); + var wait = this.wait(); + + + /*--------------------------- + Display CPU Numbers + -------------------------*/ + document.getElementById("cpuUtilization").innerHTML = + "Utilization: "+utilization+"%"; - document.getElementById("cpu_throughput").innerHTML = - "Throughput: "+this.throughput()+"%"; + document.getElementById("cpuThroughput").innerHTML = + "Throughput: "+throughput+"%"; - document.getElementById("cpu_turnaround").innerHTML = - "Turn Around: "+this.turnAround(); + document.getElementById("cpuTurnaround").innerHTML = + "Turn Around: "+turnAround; - document.getElementById("cpu_wait").innerHTML = - "Wait: "+this.wait(); + document.getElementById("cpuWait").innerHTML = + "Wait: "+wait; + + + /* A live monitor graph.*/ + function graph(id, color, value, valueSign, highestValue) { + var canvas = document.getElementById(id); + var context = canvas.getContext('2d'); + + var beginX = 20; + var marginY = 12; + var height = canvas.height - marginY; + var width = canvas.width - beginX; + + // vertical axis line + context.beginPath(); + context.strokeStyle = "#000"; + context.moveTo(beginX, 0); + context.lineTo(beginX, height); + context.stroke(); + // horizontal axis line + context.moveTo(beginX, height); + context.lineTo(canvas.width, height); + context.stroke(); + + // draw x & y axis text + var fontSize = 12; + context.font= fontSize+"px Times"; + context.fillText(highestValue.toString(), 1, fontSize); + context.fillText(valueSign, 1, canvas.height/2); + context.fillText("0", 1, canvas.height - marginY); + context.fillText("0", beginX, canvas.height); + context.fillText("ticks", canvas.width/2, canvas.height); + + // highest tick is width (10 ticks per pixels) + context.fillText(width, canvas.width - beginX, canvas.height); + + // new line height for this tick + var h = (height * (highestValue-value))/highestValue; + + // shift graph to the right by a little + context.strokeStyle = color; + var saved_rect = context.getImageData(beginX+1, 0, width, height-1); + context.clearRect(beginX+1, 0, width, height-1); + context.putImageData(saved_rect, beginX+2, 0); + + // add the new line + context.moveTo(beginX+2, height-1); + context.lineTo(beginX+2, h); + context.stroke(); + } - var canvas = document.getElementById('cpu_utilization_bar'); - var context = canvas.getContext('2d'); - context.fillStyle = '#8ED6FF'; - context.fillRect(0, 0, canvas.width, canvas.height); - context.fillStyle = '#ffb78e'; - context.fillRect(0, 0, (canvas.width * this.utilization())/100, canvas.height); - canvas = document.getElementById('cpu_throughput_bar'); - context = canvas.getContext('2d'); + /*---------------------------- + CPU Utilization Bar + ----------------------------*/ + var canvas = document.getElementById('cpuUtilizationBar'); + var context = canvas.getContext('2d'); context.fillStyle = '#8ED6FF'; context.fillRect(0, 0, canvas.width, canvas.height); context.fillStyle = '#ffb78e'; - context.fillRect(0, 0, (canvas.width * this.throughput())/100, canvas.height); - - canvas = document.getElementById('cpu_turnaround_graph'); - context = canvas.getContext('2d'); - - context.fillStyle = '#eee'; - context.fillRect(0, 0, canvas.width, canvas.height); + context.fillRect(0, 0, (canvas.width * utilization)/100, canvas.height); - canvas = document.getElementById('cpu_utilization_graph'); - context = canvas.getContext('2d'); - - context.fillStyle = '#eee'; - context.fillRect(0, 0, canvas.width, canvas.height); - - canvas = document.getElementById('cpu_throughput_graph'); - context = canvas.getContext('2d'); - - context.fillStyle = '#eee'; - context.fillRect(0, 0, canvas.width, canvas.height); - - canvas = document.getElementById('cpu_wait_graph'); + + /*---------------------------- + CPU Throughput Bar + ----------------------------*/ + canvas = document.getElementById('cpuThroughputBar'); context = canvas.getContext('2d'); - context.fillStyle = '#eee'; + context.fillStyle = '#8ED6FF'; context.fillRect(0, 0, canvas.width, canvas.height); - canvas = document.getElementById('cpu_turnaround_graph'); - context = canvas.getContext('2d'); - - context.fillStyle = '#eee'; - context.fillRect(0, 0, canvas.width, canvas.height); + context.fillStyle = '#ffb78e'; + context.fillRect(0, 0, (canvas.width * throughput)/100, canvas.height); - canvas = document.getElementById('cpu_wait_graph'); - context = canvas.getContext('2d'); - context.fillStyle = '#eee'; - context.fillRect(0, 0, canvas.width, canvas.height); + graph("cpuUtilizationGraph", "red", utilization, "%", 100); + graph("cpuThroughputGraph", "green", throughput, "%", 100); + graph("cpuWaitGraph", "orange", wait, "", 300); + graph("cpuTurnaroundGraph", "blue", turnAround, "", 200); } } diff --git a/styles/julios.css b/styles/julios.css @@ -19,6 +19,10 @@ body { font-size: 10pt; } +.monitor { + background-color: #eee; +} + #tabContainer { margin-top: 20px; }