feat: enhance context switch handling in Gantt chart and add related tests
This commit is contained in:
1 parent
9f0a05db62
commit
64bbc4ca27
10 files changed
+135
-14
No files matched your search
BIN
Binary file not shown.
Generated
+17
-9
@@ -147,6 +147,7 @@
|
|||||||
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
|
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.29.0",
|
"@babel/code-frame": "^7.29.0",
|
||||||
"@babel/generator": "^7.29.0",
|
"@babel/generator": "^7.29.0",
|
||||||
@@ -519,6 +520,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20.19.0"
|
"node": ">=20.19.0"
|
||||||
},
|
},
|
||||||
@@ -567,6 +569,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20.19.0"
|
"node": ">=20.19.0"
|
||||||
}
|
}
|
||||||
@@ -1892,8 +1895,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz",
|
||||||
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
|
"integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@types/babel__core": {
|
"node_modules/@types/babel__core": {
|
||||||
"version": "7.20.5",
|
"version": "7.20.5",
|
||||||
@@ -2034,6 +2036,7 @@
|
|||||||
"integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==",
|
"integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~7.18.0"
|
"undici-types": "~7.18.0"
|
||||||
}
|
}
|
||||||
@@ -2051,6 +2054,7 @@
|
|||||||
"integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==",
|
"integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/prop-types": "*",
|
"@types/prop-types": "*",
|
||||||
"csstype": "^3.2.2"
|
"csstype": "^3.2.2"
|
||||||
@@ -2062,6 +2066,7 @@
|
|||||||
"integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
|
"integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "^18.0.0"
|
"@types/react": "^18.0.0"
|
||||||
}
|
}
|
||||||
@@ -2373,6 +2378,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.9.0",
|
"baseline-browser-mapping": "^2.9.0",
|
||||||
"caniuse-lite": "^1.0.30001759",
|
"caniuse-lite": "^1.0.30001759",
|
||||||
@@ -2725,8 +2731,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
|
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz",
|
||||||
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
|
"integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/eastasianwidth": {
|
"node_modules/eastasianwidth": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
@@ -3544,7 +3549,6 @@
|
|||||||
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
|
"integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"lz-string": "bin/bin.js"
|
"lz-string": "bin/bin.js"
|
||||||
}
|
}
|
||||||
@@ -3760,6 +3764,7 @@
|
|||||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@@ -3802,7 +3807,6 @@
|
|||||||
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
|
"integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-regex": "^5.0.1",
|
"ansi-regex": "^5.0.1",
|
||||||
"ansi-styles": "^5.0.0",
|
"ansi-styles": "^5.0.0",
|
||||||
@@ -3818,7 +3822,6 @@
|
|||||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
@@ -3829,7 +3832,6 @@
|
|||||||
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
|
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
},
|
},
|
||||||
@@ -3852,6 +3854,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
||||||
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"loose-envify": "^1.1.0"
|
"loose-envify": "^1.1.0"
|
||||||
},
|
},
|
||||||
@@ -3864,6 +3867,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||||
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"loose-envify": "^1.1.0",
|
"loose-envify": "^1.1.0",
|
||||||
"scheduler": "^0.23.2"
|
"scheduler": "^0.23.2"
|
||||||
@@ -3884,6 +3888,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
|
||||||
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
|
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/use-sync-external-store": "^0.0.6",
|
"@types/use-sync-external-store": "^0.0.6",
|
||||||
"use-sync-external-store": "^1.4.0"
|
"use-sync-external-store": "^1.4.0"
|
||||||
@@ -3960,7 +3965,8 @@
|
|||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
|
||||||
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
|
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"node_modules/redux-thunk": {
|
"node_modules/redux-thunk": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
@@ -4546,6 +4552,7 @@
|
|||||||
"integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
|
"integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.25.0",
|
"esbuild": "^0.25.0",
|
||||||
"fdir": "^6.4.4",
|
"fdir": "^6.4.4",
|
||||||
@@ -4644,6 +4651,7 @@
|
|||||||
"integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==",
|
"integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/chai": "^5.2.2",
|
"@types/chai": "^5.2.2",
|
||||||
"@vitest/expect": "3.2.4",
|
"@vitest/expect": "3.2.4",
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ const GanttRow = React.memo(function GanttRow({
|
|||||||
<div className="flex" style={{ height: CELL_H }}>
|
<div className="flex" style={{ height: CELL_H }}>
|
||||||
{ticks.map((tick) => {
|
{ticks.map((tick) => {
|
||||||
const state: StateLabel = tick.states[process.id] ?? "New";
|
const state: StateLabel = tick.states[process.id] ?? "New";
|
||||||
// A context-switch tick affects the process currently on CPU
|
// A context-switch tick is shown on the incoming (next-to-run) process
|
||||||
const isCtxSwitch =
|
const isCtxSwitch =
|
||||||
tick.contextSwitching && tick.cpuProcess === process.id;
|
tick.contextSwitching && tick.ctxSwitchForProcess === process.id;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GanttCell
|
<GanttCell
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ describe("GanttCell", () => {
|
|||||||
readyQueue: [],
|
readyQueue: [],
|
||||||
states: { p1: "Running" },
|
states: { p1: "Running" },
|
||||||
contextSwitching: false,
|
contextSwitching: false,
|
||||||
|
ctxSwitchForProcess: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
const noop = () => {};
|
const noop = () => {};
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import { describe, it, expect, vi } from "vitest";
|
||||||
|
import { render } from "@testing-library/react";
|
||||||
|
import GanttRow from "../GanttRow";
|
||||||
|
import type { Process, SimTick } from "@core/types";
|
||||||
|
|
||||||
|
describe("GanttRow – isCtxSwitch propagation", () => {
|
||||||
|
const p1: Process = {
|
||||||
|
id: "p1", name: "P1", arrivalTime: 0, priority: 5,
|
||||||
|
color: "#4FC3F7", bursts: [{ type: "cpu", duration: 2 }],
|
||||||
|
};
|
||||||
|
const p2: Process = {
|
||||||
|
id: "p2", name: "P2", arrivalTime: 0, priority: 5,
|
||||||
|
color: "#FF7043", bursts: [{ type: "cpu", duration: 2 }],
|
||||||
|
};
|
||||||
|
|
||||||
|
const ctxTick: SimTick = {
|
||||||
|
tick: 2,
|
||||||
|
cpuProcess: null,
|
||||||
|
ioProcesses: [],
|
||||||
|
readyQueue: ["p2"],
|
||||||
|
states: { p1: "Ready", p2: "Ready" },
|
||||||
|
contextSwitching: true,
|
||||||
|
ctxSwitchForProcess: "p2",
|
||||||
|
};
|
||||||
|
|
||||||
|
const noop = vi.fn();
|
||||||
|
|
||||||
|
it("renders the context-switch color on the incoming process (p2)", () => {
|
||||||
|
const { container } = render(
|
||||||
|
<GanttRow
|
||||||
|
process={p2}
|
||||||
|
ticks={[ctxTick]}
|
||||||
|
onCellMouseEnter={noop}
|
||||||
|
onCellMouseLeave={noop}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
// The outer div is the row; its first child is the GanttCell div
|
||||||
|
const cell = container.firstChild?.firstChild as HTMLElement;
|
||||||
|
expect(cell.className).toContain("bg-[var(--color-state-ctx)]");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does NOT render context-switch color on the outgoing process (p1)", () => {
|
||||||
|
const { container } = render(
|
||||||
|
<GanttRow
|
||||||
|
process={p1}
|
||||||
|
ticks={[ctxTick]}
|
||||||
|
onCellMouseEnter={noop}
|
||||||
|
onCellMouseLeave={noop}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
const cell = container.firstChild?.firstChild as HTMLElement;
|
||||||
|
expect(cell.className).not.toContain("bg-[var(--color-state-ctx)]");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not mark ctx-switch when contextSwitching is false", () => {
|
||||||
|
const normalTick: SimTick = {
|
||||||
|
tick: 0,
|
||||||
|
cpuProcess: "p1",
|
||||||
|
ioProcesses: [],
|
||||||
|
readyQueue: [],
|
||||||
|
states: { p1: "Running", p2: "Ready" },
|
||||||
|
contextSwitching: false,
|
||||||
|
ctxSwitchForProcess: null,
|
||||||
|
};
|
||||||
|
const { container } = render(
|
||||||
|
<GanttRow
|
||||||
|
process={p1}
|
||||||
|
ticks={[normalTick]}
|
||||||
|
onCellMouseEnter={noop}
|
||||||
|
onCellMouseLeave={noop}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
const cell = container.firstChild?.firstChild as HTMLElement;
|
||||||
|
expect(cell.className).not.toContain("bg-[var(--color-state-ctx)]");
|
||||||
|
expect(cell.className).toContain("bg-[var(--color-state-running)]");
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -55,7 +55,7 @@ const AppHeader = () => {
|
|||||||
return (
|
return (
|
||||||
<header className="h-12 flex items-center px-5 gap-4 bg-slate-900 border-b border-slate-700/60 shrink-0 z-30">
|
<header className="h-12 flex items-center px-5 gap-4 bg-slate-900 border-b border-slate-700/60 shrink-0 z-30">
|
||||||
{/* Title */}
|
{/* Title */}
|
||||||
<h1 className="text-sm font-semibold bg-gradient-to-r from-blue-400 to-indigo-400 bg-clip-text text-transparent whitespace-nowrap">
|
<h1 className="text-sm font-semibold bg-linear-to-r from-blue-400 to-indigo-400 bg-clip-text text-transparent whitespace-nowrap">
|
||||||
Process Scheduler Simulator
|
Process Scheduler Simulator
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
@@ -81,10 +81,11 @@ const AppHeader = () => {
|
|||||||
onClick={() => setPresetsOpen(false)}
|
onClick={() => setPresetsOpen(false)}
|
||||||
/>
|
/>
|
||||||
{/* Dropdown */}
|
{/* Dropdown */}
|
||||||
<div className="absolute right-0 top-full mt-1 w-72 bg-slate-800 border border-slate-600 rounded-lg shadow-xl z-50 overflow-hidden">
|
<div className="absolute right-0 top-full mt-1 w-72 bg-slate-800 border border-slate-600 rounded-lg shadow-xl z-50 overflow-hidden flex flex-col max-h-[min(32rem,calc(100vh-4rem))]">
|
||||||
<div className="px-3 py-2 border-b border-slate-700 text-[10px] text-slate-400 uppercase tracking-wider font-medium">
|
<div className="px-3 py-2 border-b border-slate-700 text-[10px] text-slate-400 uppercase tracking-wider font-medium shrink-0">
|
||||||
Cenários pré-definidos
|
Cenários pré-definidos
|
||||||
</div>
|
</div>
|
||||||
|
<div className="overflow-y-auto">
|
||||||
{presets.map((preset, i) => (
|
{presets.map((preset, i) => (
|
||||||
<button
|
<button
|
||||||
key={preset.name}
|
key={preset.name}
|
||||||
@@ -103,6 +104,7 @@ const AppHeader = () => {
|
|||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -276,6 +276,25 @@ describe("SimulationEngine general", () => {
|
|||||||
expect(ticks[1]?.cpuProcess).toBe("p1");
|
expect(ticks[1]?.cpuProcess).toBe("p1");
|
||||||
expect(ticks[2]?.contextSwitching).toBe(true);
|
expect(ticks[2]?.contextSwitching).toBe(true);
|
||||||
expect(ticks[2]?.cpuProcess).toBeNull();
|
expect(ticks[2]?.cpuProcess).toBeNull();
|
||||||
|
expect(ticks[2]?.ctxSwitchForProcess).toBe("p2");
|
||||||
expect(ticks[3]?.cpuProcess).toBe("p2");
|
expect(ticks[3]?.cpuProcess).toBe("p2");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("ctxSwitchForProcess identifies incoming process across all overhead ticks", () => {
|
||||||
|
const engine = new SimulationEngine(
|
||||||
|
[
|
||||||
|
p("p1", 0, [{ type: "cpu", duration: 2 }]),
|
||||||
|
p("p2", 0, [{ type: "cpu", duration: 2 }]),
|
||||||
|
],
|
||||||
|
cfg({ algorithm: "FCFS", contextSwitchTime: 2 }),
|
||||||
|
);
|
||||||
|
const ticks = engine.runAll();
|
||||||
|
// P1 runs ticks 0-1, ctx-switch ticks 2-3, P2 runs ticks 4-5
|
||||||
|
expect(ticks[2]?.contextSwitching).toBe(true);
|
||||||
|
expect(ticks[2]?.ctxSwitchForProcess).toBe("p2");
|
||||||
|
expect(ticks[3]?.contextSwitching).toBe(true);
|
||||||
|
expect(ticks[3]?.ctxSwitchForProcess).toBe("p2");
|
||||||
|
expect(ticks[4]?.contextSwitching).toBe(false);
|
||||||
|
expect(ticks[4]?.ctxSwitchForProcess).toBeNull();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
@@ -239,6 +239,9 @@ export class SimulationEngine {
|
|||||||
readyQueue: this._readyQueue.map((rt) => rt.processId),
|
readyQueue: this._readyQueue.map((rt) => rt.processId),
|
||||||
states,
|
states,
|
||||||
contextSwitching,
|
contextSwitching,
|
||||||
|
ctxSwitchForProcess: contextSwitching
|
||||||
|
? (this._readyQueue[0]?.processId ?? null)
|
||||||
|
: null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,6 +98,16 @@ export const presets: Preset[] = [
|
|||||||
],
|
],
|
||||||
config: defaultConfig({ algorithm: "FCFS" }),
|
config: defaultConfig({ algorithm: "FCFS" }),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "context_switch_demo",
|
||||||
|
description: "3 processos FCFS com 2 ticks de overhead — veja as células vermelhas de Context Switch",
|
||||||
|
processes: [
|
||||||
|
{ id: "p1", name: "P1", arrivalTime: 0, priority: 5, color: "#4FC3F7", bursts: [{ type: "cpu", duration: 3 }] },
|
||||||
|
{ id: "p2", name: "P2", arrivalTime: 0, priority: 5, color: "#81C784", bursts: [{ type: "cpu", duration: 3 }] },
|
||||||
|
{ id: "p3", name: "P3", arrivalTime: 0, priority: 5, color: "#FFB74D", bursts: [{ type: "cpu", duration: 3 }] },
|
||||||
|
],
|
||||||
|
config: defaultConfig({ algorithm: "FCFS", contextSwitchTime: 2 }),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "multilevel_demo",
|
name: "multilevel_demo",
|
||||||
description: "Priority RR with 3 priority tiers — demonstrates multilevel scheduling",
|
description: "Priority RR with 3 priority tiers — demonstrates multilevel scheduling",
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ export interface SimTick {
|
|||||||
readyQueue: string[]; // processIds in ready queue (in queue order)
|
readyQueue: string[]; // processIds in ready queue (in queue order)
|
||||||
states: Record<string, StateLabel>; // all processId → state
|
states: Record<string, StateLabel>; // all processId → state
|
||||||
contextSwitching: boolean; // true during context-switch overhead
|
contextSwitching: boolean; // true during context-switch overhead
|
||||||
|
ctxSwitchForProcess: string | null; // incoming processId during ctx-switch overhead (null otherwise)
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------- Metrics ------------------------------------
|
// --------------- Metrics ------------------------------------
|
||||||
|
|||||||
Reference in new issue
Block a user