From 51a8a6fa4080ee9a2450d5387e316b05885a9dea Mon Sep 17 00:00:00 2001 From: Lucas Rayan Date: Thu, 19 Mar 2026 16:45:05 -0300 Subject: [PATCH] Implement Priority Round Robin Scheduling Algorithm with Tests - Added `priority_rr` algorithm to handle scheduling based on priority and round-robin principles. - Created unit tests for `select()`, `shouldPreempt()`, and `isQuantumExpired()` functions to ensure correct behavior. - Developed integration tests to validate the scheduling logic under various scenarios, including preemption and round-robin execution. - Introduced `useExport` hook for exporting process metrics to CSV format. - Added `useGanttScroll` hook to manage smooth scrolling of the Gantt chart during simulation. --- .dockerignore | 5 + Dockerfile | 13 + dist.tar.gz | Bin 0 -> 179771 bytes docker-compose.yml | 6 + nginx.conf | 22 + package-lock.json | 418 +++++++++- package.json | 2 + src/App.tsx | 2 + src/components/GanttChart/GanttCell.tsx | 53 ++ src/components/GanttChart/GanttChart.tsx | 113 +++ src/components/GanttChart/GanttLegend.tsx | 25 + src/components/GanttChart/GanttRow.tsx | 51 ++ src/components/GanttChart/GanttTooltip.tsx | 80 ++ .../GanttChart/__tests__/GanttCell.test.tsx | 79 ++ src/components/GanttChart/constants.ts | 5 + src/components/Layout/AppHeader.tsx | 150 ++++ src/components/Layout/AppLayout.tsx | 10 +- src/components/Layout/MainArea.tsx | 20 +- src/components/MetricsPanel/GlobalMetrics.tsx | 83 ++ src/components/MetricsPanel/MetricsChart.tsx | 82 ++ src/components/MetricsPanel/MetricsPanel.tsx | 98 +++ src/components/MetricsPanel/MetricsTable.tsx | 82 ++ src/components/ProcessPanel/ProcessForm.tsx | 2 +- .../SchedulerPanel/AlgorithmSelector.tsx | 7 +- .../SchedulerPanel/SchedulerConfig.tsx | 6 +- src/components/shared/processUtils.ts | 2 +- src/core/__tests__/integration.test.ts | 716 ++++++++++++++++++ src/core/__tests__/priority_rr.test.ts | 248 ++++++ src/core/algorithms/index.ts | 2 + src/core/algorithms/priority_rr.ts | 49 ++ src/core/presets.ts | 33 + src/core/types.ts | 1 + src/hooks/useExport.ts | 56 ++ src/hooks/useGanttScroll.ts | 22 + src/index.css | 24 + src/store/simulationStore.ts | 4 +- tsconfig.app.json | 3 +- vite.config.ts | 1 + 38 files changed, 2530 insertions(+), 45 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 dist.tar.gz create mode 100644 docker-compose.yml create mode 100644 nginx.conf create mode 100644 src/components/GanttChart/GanttCell.tsx create mode 100644 src/components/GanttChart/GanttChart.tsx create mode 100644 src/components/GanttChart/GanttLegend.tsx create mode 100644 src/components/GanttChart/GanttRow.tsx create mode 100644 src/components/GanttChart/GanttTooltip.tsx create mode 100644 src/components/GanttChart/__tests__/GanttCell.test.tsx create mode 100644 src/components/GanttChart/constants.ts create mode 100644 src/components/Layout/AppHeader.tsx create mode 100644 src/components/MetricsPanel/GlobalMetrics.tsx create mode 100644 src/components/MetricsPanel/MetricsChart.tsx create mode 100644 src/components/MetricsPanel/MetricsPanel.tsx create mode 100644 src/components/MetricsPanel/MetricsTable.tsx create mode 100644 src/core/__tests__/integration.test.ts create mode 100644 src/core/__tests__/priority_rr.test.ts create mode 100644 src/core/algorithms/priority_rr.ts create mode 100644 src/hooks/useExport.ts create mode 100644 src/hooks/useGanttScroll.ts diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..247b8e4 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +node_modules +dist/ +.git +.gitignore +*.md diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d38a19b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +# ── Production image ── +FROM nginx:alpine + +COPY nginx.conf /etc/nginx/conf.d/default.conf + +# Unpack pre-built Vite output +COPY dist.tar.gz /usr/share/nginx/html/ +RUN tar -xzf /usr/share/nginx/html/dist.tar.gz --strip-components=1 -C /usr/share/nginx/html \ + && rm /usr/share/nginx/html/dist.tar.gz + +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/dist.tar.gz b/dist.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..ef4c93b7a4ccd841d73715d5fe3de992ff9b07e3 GIT binary patch literal 179771 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 PPe}g)G!)al0AL9Kd7N;z literal 0 HcmV?d00001 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..15b12be --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,6 @@ +services: + pss: + build: . + ports: + - "${PORT:-80}:80" + restart: unless-stopped diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..ba3284d --- /dev/null +++ b/nginx.conf @@ -0,0 +1,22 @@ +server { + listen 80; + server_name _; + root /usr/share/nginx/html; + index index.html; + + # Gzip + gzip on; + gzip_types text/plain text/css application/javascript application/json image/svg+xml; + gzip_min_length 1024; + + # Cache para assets com hash no nome (gerados pelo Vite) + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # SPA: todas as rotas vão para index.html + location / { + try_files $uri $uri/ /index.html; + } +} diff --git a/package-lock.json b/package-lock.json index b1e5b33..0ecf887 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "lucide-react": "^0.577.0", "react": "^18.3.1", "react-dom": "^18.3.1", + "recharts": "^3.8.0", "tailwind-merge": "^3.5.0", "zustand": "^5.0.12" }, @@ -146,7 +147,6 @@ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -519,7 +519,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=20.19.0" }, @@ -568,7 +567,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=20.19.0" } @@ -1122,6 +1120,42 @@ "node": ">=14" } }, + "node_modules/@reduxjs/toolkit": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.11.2.tgz", + "integrity": "sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@standard-schema/utils": "^0.3.0", + "immer": "^11.0.0", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@reduxjs/toolkit/node_modules/immer": { + "version": "11.1.4", + "resolved": "https://registry.npmjs.org/immer/-/immer-11.1.4.tgz", + "integrity": "sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-beta.27", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", @@ -1479,6 +1513,18 @@ "win32" ] }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, + "node_modules/@standard-schema/utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz", + "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", + "license": "MIT" + }, "node_modules/@tailwindcss/node": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.2.tgz", @@ -1846,7 +1892,8 @@ "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@types/babel__core": { "version": "7.20.5", @@ -1904,6 +1951,69 @@ "assertion-error": "^2.0.1" } }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, "node_modules/@types/deep-eql": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", @@ -1924,7 +2034,6 @@ "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.18.0" } @@ -1942,7 +2051,6 @@ "integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.2.2" @@ -1954,11 +2062,16 @@ "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", "dev": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^18.0.0" } }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", + "license": "MIT" + }, "node_modules/@vitejs/plugin-react": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", @@ -2260,7 +2373,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -2412,6 +2524,127 @@ "devOptional": true, "license": "MIT" }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/data-urls": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", @@ -2451,6 +2684,12 @@ "dev": true, "license": "MIT" }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" + }, "node_modules/deep-eql": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", @@ -2486,7 +2725,8 @@ "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/eastasianwidth": { "version": "0.2.0", @@ -2543,6 +2783,16 @@ "dev": true, "license": "MIT" }, + "node_modules/es-toolkit": { + "version": "1.45.1", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.45.1.tgz", + "integrity": "sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, "node_modules/esbuild": { "version": "0.25.12", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", @@ -2605,6 +2855,12 @@ "@types/estree": "^1.0.0" } }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "license": "MIT" + }, "node_modules/expect-type": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", @@ -2767,6 +3023,16 @@ "dev": true, "license": "MIT" }, + "node_modules/immer": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz", + "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/indent-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", @@ -2777,6 +3043,15 @@ "node": ">=8" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -2893,7 +3168,6 @@ "integrity": "sha512-9FshNB6OepopZ08unmmGpsF7/qCjxGPbo3NbgfJAnPeHXnsODE9WWffXZtRFRFe0ntzaAOcSKNJFz8wiyvF1jQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@asamuzakjp/css-color": "^5.0.1", "@asamuzakjp/dom-selector": "^7.0.2", @@ -3270,6 +3544,7 @@ "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "dev": true, "license": "MIT", + "peer": true, "bin": { "lz-string": "bin/bin.js" } @@ -3485,7 +3760,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -3528,6 +3802,7 @@ "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -3543,6 +3818,7 @@ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=8" } @@ -3553,6 +3829,7 @@ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -3575,7 +3852,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -3588,7 +3864,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" @@ -3601,8 +3876,31 @@ "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true + }, + "node_modules/react-redux": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", + "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", + "license": "MIT", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25 || ^19", + "react": "^18.0 || ^19", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "redux": { + "optional": true + } + } }, "node_modules/react-refresh": { "version": "0.17.0", @@ -3614,6 +3912,36 @@ "node": ">=0.10.0" } }, + "node_modules/recharts": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-3.8.0.tgz", + "integrity": "sha512-Z/m38DX3L73ExO4Tpc9/iZWHmHnlzWG4njQbxsF5aSjwqmHNDDIm0rdEBArkwsBvR8U6EirlEHiQNYWCVh9sGQ==", + "license": "MIT", + "workspaces": [ + "www" + ], + "dependencies": { + "@reduxjs/toolkit": "^1.9.0 || 2.x.x", + "clsx": "^2.1.1", + "decimal.js-light": "^2.5.1", + "es-toolkit": "^1.39.3", + "eventemitter3": "^5.0.1", + "immer": "^10.1.1", + "react-redux": "8.x.x || 9.x.x", + "reselect": "5.1.1", + "tiny-invariant": "^1.3.3", + "use-sync-external-store": "^1.2.2", + "victory-vendor": "^37.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/redent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", @@ -3628,6 +3956,21 @@ "node": ">=8" } }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", + "license": "MIT" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "license": "MIT", + "peerDependencies": { + "redux": "^5.0.0" + } + }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -3638,6 +3981,12 @@ "node": ">=0.10.0" } }, + "node_modules/reselect": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", + "license": "MIT" + }, "node_modules/rollup": { "version": "4.59.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", @@ -3985,6 +4334,12 @@ "node": ">=18" } }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -4154,13 +4509,43 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/victory-vendor": { + "version": "37.3.6", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz", + "integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==", + "license": "MIT AND ISC", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, "node_modules/vite": { "version": "6.4.1", "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", @@ -4259,7 +4644,6 @@ "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", diff --git a/package.json b/package.json index 6786a1e..e710e95 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "scripts": { "dev": "vite", "build": "tsc -b && vite build", + "build:release": "tsc -b && vite build && tar --dereference -czf dist.tar.gz dist", "preview": "vite preview", "test": "vitest run", "test:watch": "vitest", @@ -16,6 +17,7 @@ "lucide-react": "^0.577.0", "react": "^18.3.1", "react-dom": "^18.3.1", + "recharts": "^3.8.0", "tailwind-merge": "^3.5.0", "zustand": "^5.0.12" }, diff --git a/src/App.tsx b/src/App.tsx index e2a1136..21cbe6b 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,6 +1,8 @@ import AppLayout from './components/Layout/AppLayout'; +import { useSimulation } from './hooks/useSimulation'; function App() { + useSimulation(); return ( ); diff --git a/src/components/GanttChart/GanttCell.tsx b/src/components/GanttChart/GanttCell.tsx new file mode 100644 index 0000000..f9ab05b --- /dev/null +++ b/src/components/GanttChart/GanttCell.tsx @@ -0,0 +1,53 @@ +import React from "react"; +import type { Process, SimTick, StateLabel } from "@core/types"; +import { CELL_H, CELL_W } from "./constants"; + +// ── colour map ────────────────────────────────────────────── +const STATE_CLASS: Record = { + New: "bg-[var(--color-state-new)]", + Ready: "bg-[var(--color-state-ready)]", + Running: "bg-[var(--color-state-running)]", + Waiting: "bg-[var(--color-state-waiting)]", + Terminated: "bg-[var(--color-state-terminated)]", +}; + +// ── props ──────────────────────────────────────────────────── +interface GanttCellProps { + tick: SimTick; + process: Process; + state: StateLabel; + isCtxSwitch: boolean; + onMouseEnter: (e: React.MouseEvent, tick: SimTick, process: Process, state: StateLabel, isCtxSwitch: boolean) => void; + onMouseLeave: () => void; +} + +// ── component ─────────────────────────────────────────────── +const GanttCell = React.memo(function GanttCell({ + tick, + process, + state, + isCtxSwitch, + onMouseEnter, + onMouseLeave, +}: GanttCellProps) { + const bg = isCtxSwitch + ? "bg-[var(--color-state-ctx)]" + : STATE_CLASS[state]; + + // Running cells get a coloured left border using the process colour + const borderStyle = + !isCtxSwitch && state === "Running" + ? { borderLeft: `3px solid ${process.color}` } + : undefined; + + return ( +
onMouseEnter(e, tick, process, state, isCtxSwitch)} + onMouseLeave={onMouseLeave} + /> + ); +}); + +export default GanttCell; diff --git a/src/components/GanttChart/GanttChart.tsx b/src/components/GanttChart/GanttChart.tsx new file mode 100644 index 0000000..b671f84 --- /dev/null +++ b/src/components/GanttChart/GanttChart.tsx @@ -0,0 +1,113 @@ +import { useCallback, useRef, useState } from "react"; +import { useSimulationStore } from "@store/simulationStore"; +import { useProcessStore } from "@store/processStore"; +import { useGanttScroll } from "@hooks/useGanttScroll"; +import GanttRow from "./GanttRow"; +import GanttLegend from "./GanttLegend"; +import GanttTooltip, { type TooltipData } from "./GanttTooltip"; +import { CELL_H, CELL_W } from "./constants"; + +// ── GanttChart ──────────────────────────────────────────────── +const GanttChart = () => { + const ticks = useSimulationStore((s) => s.ticks); + const status = useSimulationStore((s) => s.status); + const processes = useProcessStore((s) => s.processes); + + // Scrollable container ref for auto-scroll + const scrollRef = useRef(null); + const currentTickIndex = ticks.length - 1; + useGanttScroll(scrollRef, currentTickIndex, status === "running"); + + // Tooltip state + const [tooltip, setTooltip] = useState(null); + const handleMouseLeave = useCallback(() => setTooltip(null), []); + + // Empty state + if (ticks.length === 0) { + return ( +
+ Inicie a simulação para ver o diagrama de Gantt +
+ ); + } + + // ── ruler (tick numbers) ────────────────────────────────── + const tickNumbers = ticks.map((t) => t.tick); + const totalWidth = ticks.length * CELL_W; + + return ( +
+ + {/* ── scrollable grid + cursor ── */} +
+
+ + {/* Tick ruler */} +
+ {/* Spacer for sticky process labels column */} +
+ + {tickNumbers.map((t) => ( +
+ {t % 5 === 0 ? t : ""} +
+ ))} +
+ + {/* Process rows */} +
+ {processes.map((process) => ( +
+ {/* Process label (sticky on the left) */} +
+ + {process.name} + +
+ + +
+ ))} + + {/* Current-tick cursor line */} + {currentTickIndex >= 0 && ( +
+ )} +
+ +
+
+ + {/* ── process name labels (sticky left, overlay) ── */} + {/* Rendered OUTSIDE the scrollable div so they stay fixed on the left */} + {/* We achieve this with a separate absolute-positioned column */} + + {/* ── legend ── */} + + + {/* ── tooltip ── */} + {tooltip && } +
+ ); +}; + +export default GanttChart; diff --git a/src/components/GanttChart/GanttLegend.tsx b/src/components/GanttChart/GanttLegend.tsx new file mode 100644 index 0000000..7c8c858 --- /dev/null +++ b/src/components/GanttChart/GanttLegend.tsx @@ -0,0 +1,25 @@ +// Legend items ordered as they appear in a typical lifecycle +const ITEMS: { label: string; cssVar: string; textClass: string }[] = [ + { label: "New", cssVar: "var(--color-state-new)", textClass: "text-white" }, + { label: "Ready", cssVar: "var(--color-state-ready)", textClass: "text-slate-900" }, + { label: "Running", cssVar: "var(--color-state-running)", textClass: "text-slate-900" }, + { label: "Waiting (I/O)", cssVar: "var(--color-state-waiting)", textClass: "text-slate-900" }, + { label: "Terminated", cssVar: "var(--color-state-terminated)", textClass: "text-slate-900" }, + { label: "Context Switch",cssVar: "var(--color-state-ctx)", textClass: "text-white" }, +]; + +const GanttLegend = () => ( +
+ {ITEMS.map(({ label, cssVar, textClass }) => ( +
+ + {label} +
+ ))} +
+); + +export default GanttLegend; diff --git a/src/components/GanttChart/GanttRow.tsx b/src/components/GanttChart/GanttRow.tsx new file mode 100644 index 0000000..85a3098 --- /dev/null +++ b/src/components/GanttChart/GanttRow.tsx @@ -0,0 +1,51 @@ +import React from "react"; +import type { Process, SimTick, StateLabel } from "@core/types"; +import GanttCell from "./GanttCell"; +import { CELL_H, CELL_W } from "./constants"; +import type { TooltipData } from "./GanttTooltip"; + +interface GanttRowProps { + process: Process; + ticks: SimTick[]; + onCellMouseEnter: (data: TooltipData) => void; + onCellMouseLeave: () => void; +} + +const GanttRow = React.memo(function GanttRow({ + process, + ticks, + onCellMouseEnter, + onCellMouseLeave, +}: GanttRowProps) { + return ( +
+ {ticks.map((tick) => { + const state: StateLabel = tick.states[process.id] ?? "New"; + // A context-switch tick affects the process currently on CPU + const isCtxSwitch = + tick.contextSwitching && tick.cpuProcess === process.id; + + return ( + + onCellMouseEnter({ tick: t, process: p, state: s, isCtxSwitch: ctx, x: e.clientX, y: e.clientY }) + } + onMouseLeave={onCellMouseLeave} + /> + ); + })} + + {/* Empty filler so the row is always at least CELL_W wide */} + {ticks.length === 0 && ( +
+ )} +
+ ); +}); + +export default GanttRow; diff --git a/src/components/GanttChart/GanttTooltip.tsx b/src/components/GanttChart/GanttTooltip.tsx new file mode 100644 index 0000000..b699a98 --- /dev/null +++ b/src/components/GanttChart/GanttTooltip.tsx @@ -0,0 +1,80 @@ +import type { Process, SimTick, StateLabel } from "@core/types"; + +// ── colour labels ──────────────────────────────────────────── +const STATE_LABEL: Record = { + New: "New", + Ready: "Ready", + Running: "Running", + Waiting: "Waiting (I/O)", + Terminated: "Terminated", +}; + +const STATE_BADGE: Record = { + New: "bg-[var(--color-state-new)] text-white", + Ready: "bg-[var(--color-state-ready)] text-slate-900", + Running: "bg-[var(--color-state-running)] text-slate-900", + Waiting: "bg-[var(--color-state-waiting)] text-slate-900", + Terminated: "bg-[var(--color-state-terminated)] text-slate-900", +}; + +// ── types ──────────────────────────────────────────────────── +export interface TooltipData { + tick: SimTick; + process: Process; + state: StateLabel; + isCtxSwitch: boolean; + x: number; + y: number; +} + +interface GanttTooltipProps { + data: TooltipData; +} + +// ── component ──────────────────────────────────────────────── +const GanttTooltip = ({ data }: GanttTooltipProps) => { + const { tick, process, state, isCtxSwitch, x, y } = data; + + // Keep the tooltip fully inside the viewport + const left = Math.min(x + 12, window.innerWidth - 220); + const top = Math.min(y + 12, window.innerHeight - 140); + + return ( +
+ {/* Header */} +
+ + {process.name} + + tick {tick.tick} +
+ + {/* State badge */} +
+ {isCtxSwitch ? ( + + ⚠ Context Switch + + ) : ( + + {STATE_LABEL[state]} + + )} +
+ + {/* Queue context */} + {tick.readyQueue.length > 0 && ( +

+ Ready queue: {tick.readyQueue.length} process{tick.readyQueue.length !== 1 ? "es" : ""} +

+ )} +
+ ); +}; + +export default GanttTooltip; diff --git a/src/components/GanttChart/__tests__/GanttCell.test.tsx b/src/components/GanttChart/__tests__/GanttCell.test.tsx new file mode 100644 index 0000000..9eea9b5 --- /dev/null +++ b/src/components/GanttChart/__tests__/GanttCell.test.tsx @@ -0,0 +1,79 @@ +import { describe, it, expect, vi } from "vitest"; +import { render, fireEvent } from "@testing-library/react"; +import GanttCell from "../GanttCell"; +import type { Process, SimTick } from "@core/types"; + +describe("GanttCell", () => { + const mockProcess: Process = { + id: "p1", + name: "P1", + arrivalTime: 0, + priority: 5, + color: "#ff0000", + bursts: [{ type: "cpu", duration: 5 }], + }; + + const mockTick: SimTick = { + tick: 1, + cpuProcess: "p1", + ioProcesses: [], + readyQueue: [], + states: { p1: "Running" }, + contextSwitching: false, + }; + + const noop = () => {}; + + it("renders with the correct background color for Running state", () => { + const { container } = render( + + ); + const cell = container.firstChild as HTMLElement; + expect(cell.className).toContain("bg-[var(--color-state-running)]"); + }); + + it("renders with the context switch color when isCtxSwitch is true", () => { + const { container } = render( + + ); + const cell = container.firstChild as HTMLElement; + expect(cell.className).toContain("bg-[var(--color-state-ctx)]"); + }); + + it("calls onMouseEnter with correct arguments", () => { + const onMouseEnter = vi.fn(); + const { container } = render( + + ); + const cell = container.firstChild as HTMLElement; + fireEvent.mouseEnter(cell); + expect(onMouseEnter).toHaveBeenCalledWith( + expect.anything(), + mockTick, + mockProcess, + "Running", + false + ); + }); +}); diff --git a/src/components/GanttChart/constants.ts b/src/components/GanttChart/constants.ts new file mode 100644 index 0000000..ccf3a54 --- /dev/null +++ b/src/components/GanttChart/constants.ts @@ -0,0 +1,5 @@ +/** Width of a single tick cell (px) */ +export const CELL_W = 28; + +/** Height of a single process row (px) */ +export const CELL_H = 32; diff --git a/src/components/Layout/AppHeader.tsx b/src/components/Layout/AppHeader.tsx new file mode 100644 index 0000000..38b5a04 --- /dev/null +++ b/src/components/Layout/AppHeader.tsx @@ -0,0 +1,150 @@ +import { useState, useRef } from 'react'; +import { ChevronDown, Download, Upload, BookOpen } from 'lucide-react'; +import { presets } from '@core/presets'; +import { useProcessStore } from '../../store/processStore'; +import { useSimulationStore } from '../../store/simulationStore'; + +const AppHeader = () => { + const [presetsOpen, setPresetsOpen] = useState(false); + const fileInputRef = useRef(null); + + const loadPreset = useProcessStore(s => s.loadPreset); + const processes = useProcessStore(s => s.processes); + const config = useProcessStore(s => s.config); + const simStatus = useSimulationStore(s => s.status); + + const handleLoadPreset = (index: number) => { + const p = presets[index]; + if (!p) return; + loadPreset(p.processes, p.config); + setPresetsOpen(false); + }; + + const handleExportJSON = () => { + const data = JSON.stringify({ processes, config }, null, 2); + const blob = new Blob([data], { type: 'application/json' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = 'pss-config.json'; + a.click(); + URL.revokeObjectURL(url); + }; + + const handleImportJSON = (e: React.ChangeEvent) => { + const file = e.target.files?.[0]; + if (!file) return; + const reader = new FileReader(); + reader.onload = (ev) => { + try { + const parsed = JSON.parse(ev.target?.result as string); + if (parsed.processes && parsed.config) { + loadPreset(parsed.processes, parsed.config); + } + } catch { + // Silently ignore malformed JSON + } + }; + reader.readAsText(file); + // Reset so the same file can be imported again + e.target.value = ''; + }; + + const isSimulationActive = simStatus !== 'idle'; + + return ( +
+ {/* Title */} +

+ Process Scheduler Simulator +

+ +
+ + {/* Presets dropdown */} +
+ + + {presetsOpen && ( + <> + {/* Backdrop */} +
setPresetsOpen(false)} + /> + {/* Dropdown */} +
+
+ Cenários pré-definidos +
+ {presets.map((preset, i) => ( + + ))} +
+ + )} +
+ + {/* Import JSON */} + + + + {/* Export JSON */} + +
+ ); +}; + +export default AppHeader; diff --git a/src/components/Layout/AppLayout.tsx b/src/components/Layout/AppLayout.tsx index 20ec488..19ff2a6 100644 --- a/src/components/Layout/AppLayout.tsx +++ b/src/components/Layout/AppLayout.tsx @@ -1,11 +1,15 @@ +import AppHeader from './AppHeader'; import Sidebar from './Sidebar'; import MainArea from './MainArea'; const AppLayout = () => { return ( -
- - +
+ +
+ + +
); }; diff --git a/src/components/Layout/MainArea.tsx b/src/components/Layout/MainArea.tsx index 4b041f5..cd543f0 100644 --- a/src/components/Layout/MainArea.tsx +++ b/src/components/Layout/MainArea.tsx @@ -1,23 +1,13 @@ import ControlBar from '../ControlBar/ControlBar'; +import GanttChart from '../GanttChart/GanttChart'; +import MetricsPanel from '../MetricsPanel/MetricsPanel'; const MainArea = () => { return (
-
- - - {/* Placeholder for GanttChart — Phase 4 */} -
- [ Gantt Chart — Fase 4 ] -
- - {/* Placeholder for MetricsPanel — Phase 5 */} -
-
- [ Metrics Panel — Fase 5 ] -
-
-
+ + +
); }; diff --git a/src/components/MetricsPanel/GlobalMetrics.tsx b/src/components/MetricsPanel/GlobalMetrics.tsx new file mode 100644 index 0000000..7d39215 --- /dev/null +++ b/src/components/MetricsPanel/GlobalMetrics.tsx @@ -0,0 +1,83 @@ +import type { GlobalMetrics as GlobalMetricsType } from '@core/types'; + +interface GlobalMetricsProps { + metrics: GlobalMetricsType; +} + +interface MetricCardProps { + label: string; + value: string; + sub?: string; + accent?: string; +} + +const MetricCard = ({ label, value, sub, accent = 'text-blue-300' }: MetricCardProps) => ( +
+ {label} + {value} + {sub && {sub}} +
+); + +const GlobalMetrics = ({ metrics }: GlobalMetricsProps) => { + const { + avgResponseTime, + avgTurnaroundTime, + avgWaitingTime, + cpuThroughput, + cpuUtilization, + totalSimulationTime, + } = metrics; + + const utilizationPct = Math.min(100, cpuUtilization); + + return ( +
+
+ + + + + + {/* CPU Utilization card with progress bar */} +
+ CPU Utilization + {utilizationPct.toFixed(1)}% +
+
+
+
+
+
+ ); +}; + +export default GlobalMetrics; diff --git a/src/components/MetricsPanel/MetricsChart.tsx b/src/components/MetricsPanel/MetricsChart.tsx new file mode 100644 index 0000000..27bf118 --- /dev/null +++ b/src/components/MetricsPanel/MetricsChart.tsx @@ -0,0 +1,82 @@ +import { + BarChart, + Bar, + XAxis, + YAxis, + Tooltip, + Legend, + ResponsiveContainer, + CartesianGrid, +} from 'recharts'; +import type { ProcessMetrics, Process } from '@core/types'; + +interface MetricsChartProps { + metrics: ProcessMetrics[]; + processMap: Record; +} + +const MetricsChart = ({ metrics, processMap }: MetricsChartProps) => { + if (metrics.length === 0) { + return ( +
+ Nenhum dado disponível. +
+ ); + } + + const data = metrics.map((m) => ({ + name: processMap[m.processId]?.name ?? m.processId, + 'Waiting Time': m.waitingTime, + 'CPU Time': m.cpuTime, + 'I/O Time': m.ioTime, + })); + + return ( +
+ + + + + + + + + + + + +

+ Barras empilhadas = Turnaround Time (Waiting + CPU + I/O) +

+
+ ); +}; + +export default MetricsChart; diff --git a/src/components/MetricsPanel/MetricsPanel.tsx b/src/components/MetricsPanel/MetricsPanel.tsx new file mode 100644 index 0000000..8a6c7fb --- /dev/null +++ b/src/components/MetricsPanel/MetricsPanel.tsx @@ -0,0 +1,98 @@ +import { useState } from 'react'; +import { Download, BarChart2, Table, Globe } from 'lucide-react'; +import { computeProcessMetrics, computeGlobalMetrics } from '@core/metrics'; +import { useSimulationStore } from '../../store/simulationStore'; +import { useProcessStore } from '../../store/processStore'; +import { useExport } from '../../hooks/useExport'; +import MetricsTable from './MetricsTable'; +import GlobalMetrics from './GlobalMetrics'; +import MetricsChart from './MetricsChart'; + +type Tab = 'table' | 'global' | 'chart'; + +const TAB_CONFIG: { id: Tab; label: string; icon: React.ReactNode }[] = [ + { id: 'table', label: 'Por Processo', icon: }, + { id: 'global', label: 'Global', icon: }, + { id: 'chart', label: 'Gráfico', icon: }, +]; + +const MetricsPanel = () => { + const [activeTab, setActiveTab] = useState('table'); + + const engine = useSimulationStore(s => s.engine); + const ticks = useSimulationStore(s => s.ticks); + const status = useSimulationStore(s => s.status); + const processes = useProcessStore(s => s.processes); + + const { exportCSV } = useExport(); + + const hasData = ticks.length > 0; + + if (!hasData) { + return ( +
+ Execute a simulação para ver as métricas. +
+ ); + } + + // Derive metrics from engine runtime state + const runtimes = engine?.runtimeStates ?? []; + const completedRuntimes = runtimes.filter(rt => rt.finishTick !== null); + const processMetrics = completedRuntimes.map(rt => computeProcessMetrics(rt)); + const globalMetrics = computeGlobalMetrics(processMetrics, ticks.length); + const processMap = Object.fromEntries(processes.map(p => [p.id, p])); + + const canExportCSV = status === 'finished' && processMetrics.length > 0; + + return ( +
+ {/* Panel header with tabs + export button */} +
+ {TAB_CONFIG.map(tab => ( + + ))} + +
+ +
+
+ + {/* Tab content */} +
+ {activeTab === 'table' && ( + + )} + {activeTab === 'global' && ( + + )} + {activeTab === 'chart' && ( + + )} +
+
+ ); +}; + +export default MetricsPanel; diff --git a/src/components/MetricsPanel/MetricsTable.tsx b/src/components/MetricsPanel/MetricsTable.tsx new file mode 100644 index 0000000..7602d84 --- /dev/null +++ b/src/components/MetricsPanel/MetricsTable.tsx @@ -0,0 +1,82 @@ +import type { ProcessMetrics, Process } from '@core/types'; +import Badge from '../shared/Badge'; + +interface MetricsTableProps { + metrics: ProcessMetrics[]; + processMap: Record; +} + +function boundVariant(type: ProcessMetrics['boundType']) { + if (type === 'CPU Bound') return 'cpu'; + if (type === 'I/O Bound') return 'io'; + return 'balanced'; +} + +const MetricsTable = ({ metrics, processMap }: MetricsTableProps) => { + if (metrics.length === 0) { + return ( +
+ Nenhum processo concluído ainda. +
+ ); + } + + return ( +
+
+ + + + + + + + + + + + + + + + + {metrics.map((m, i) => { + const proc = processMap[m.processId]; + const name = proc?.name ?? m.processId; + const color = proc?.color ?? '#94a3b8'; + return ( + + + + + + + + + + + + + + ); + })} + +
ProcessoArrivalStartFinishResponseTurnaroundWaitingCPU TimeI/O TimeCPU%Bound
+
+ + {name} +
+
{m.arrivalTime}{m.startTick}{m.finishTick}{m.responseTime}{m.turnaroundTime}{m.waitingTime}{m.cpuTime}{m.ioTime}{m.cpuUtilization.toFixed(1)}% + {m.boundType} +
+
+ ); +}; + +export default MetricsTable; diff --git a/src/components/ProcessPanel/ProcessForm.tsx b/src/components/ProcessPanel/ProcessForm.tsx index a33ab59..ade9638 100644 --- a/src/components/ProcessPanel/ProcessForm.tsx +++ b/src/components/ProcessPanel/ProcessForm.tsx @@ -78,7 +78,7 @@ const ProcessForm = ({ editingProcess, onClose }: ProcessFormProps) => { if (bursts.at(-1)?.type !== 'cpu') errs.push('O último burst deve ser CPU'); bursts.forEach((b, i) => { if (b.duration < 1) errs.push(`Burst ${i + 1}: duração deve ser ≥ 1`); - if (i > 0 && bursts[i - 1].type === b.type) errs.push(`Bursts ${i} e ${i + 1} não podem ser do mesmo tipo (alternar CPU/IO)`); + if (i > 0 && bursts[i - 1]?.type === b.type) errs.push(`Bursts ${i} e ${i + 1} não podem ser do mesmo tipo (alternar CPU/IO)`); }); setErrors(errs); return errs.length === 0; diff --git a/src/components/SchedulerPanel/AlgorithmSelector.tsx b/src/components/SchedulerPanel/AlgorithmSelector.tsx index 3dbb718..a4c8d5a 100644 --- a/src/components/SchedulerPanel/AlgorithmSelector.tsx +++ b/src/components/SchedulerPanel/AlgorithmSelector.tsx @@ -1,15 +1,16 @@ import type { SchedulingAlgorithm } from '@core/types'; import { useProcessStore } from '../../store/processStore'; -const ALGORITHM_OPTIONS: { value: SchedulingAlgorithm; label: string }[] = [ +const ALGORITHM_OPTIONS: { value: SchedulingAlgorithm; label: string; disabled?: boolean }[] = [ { value: 'FCFS', label: 'FCFS — First Come First Served' }, { value: 'SJF_NP', label: 'SJF — Shortest Job First (NP)' }, { value: 'SJF_P', label: 'SRTF — Shortest Remaining Time (P)' }, { value: 'RR', label: 'RR — Round Robin' }, { value: 'PRIORITY_NP',label: 'Priority (Não-preemptivo)' }, { value: 'PRIORITY_P', label: 'Priority (Preemptivo)' }, + { value: 'PRIORITY_RR',label: 'Priority Round Robin (tempo real)' }, { value: 'HRRN', label: 'HRRN — Highest Response Ratio Next' }, - { value: 'MULTILEVEL', label: 'Multilevel Queue' }, + { value: 'MULTILEVEL', label: 'Multilevel Queue (em breve)', disabled: true }, ]; const AlgorithmSelector = () => { @@ -32,7 +33,7 @@ const AlgorithmSelector = () => { aria-label="Selecionar algoritmo de escalonamento" > {ALGORITHM_OPTIONS.map(opt => ( - ))} diff --git a/src/components/SchedulerPanel/SchedulerConfig.tsx b/src/components/SchedulerPanel/SchedulerConfig.tsx index 1e874a4..9515eb4 100644 --- a/src/components/SchedulerPanel/SchedulerConfig.tsx +++ b/src/components/SchedulerPanel/SchedulerConfig.tsx @@ -2,13 +2,13 @@ import { useProcessStore } from '../../store/processStore'; import type { SchedulingAlgorithm } from '@core/types'; // Algorithms that require a quantum parameter -const QUANTUM_ALGORITHMS = new Set(['RR', 'MULTILEVEL']); +const QUANTUM_ALGORITHMS = new Set(['RR', 'PRIORITY_RR', 'MULTILEVEL']); // Algorithms where aging (anti-starvation) is applicable -const AGING_ALGORITHMS = new Set(['PRIORITY_NP', 'PRIORITY_P']); +const AGING_ALGORITHMS = new Set(['PRIORITY_NP', 'PRIORITY_P', 'PRIORITY_RR']); // Algorithms that are preemptive by definition (used for read-only info only) -const PREEMPTIVE_BY_DESIGN = new Set(['SJF_P', 'RR', 'PRIORITY_P', 'MULTILEVEL']); +const PREEMPTIVE_BY_DESIGN = new Set(['SJF_P', 'RR', 'PRIORITY_P', 'PRIORITY_RR', 'MULTILEVEL']); const inputCls = 'w-full rounded-md bg-slate-700 border border-slate-600 text-slate-200 text-sm px-3 py-1.5 focus:outline-none focus:ring-1 focus:ring-blue-500'; const labelCls = 'block text-xs text-slate-400 mb-1'; diff --git a/src/components/shared/processUtils.ts b/src/components/shared/processUtils.ts index 24ec26d..b7e6ebd 100644 --- a/src/components/shared/processUtils.ts +++ b/src/components/shared/processUtils.ts @@ -28,5 +28,5 @@ const PALETTE = [ ]; let _paletteIndex = 0; export function nextColor(): string { - return PALETTE[_paletteIndex++ % PALETTE.length]; + return PALETTE[_paletteIndex++ % PALETTE.length]!; } diff --git a/src/core/__tests__/integration.test.ts b/src/core/__tests__/integration.test.ts new file mode 100644 index 0000000..ab00f85 --- /dev/null +++ b/src/core/__tests__/integration.test.ts @@ -0,0 +1,716 @@ +/** + * Integration Tests — Process Scheduler Simulator + * + * These tests validate end-to-end simulation correctness: processes go through + * the full lifecycle (New → Ready → Running → Waiting → Terminated), metrics + * are consistent, and each algorithm produces the expected scheduling behavior. + * + * Test IDs follow the spec (CT-05 onward, CT-01..CT-04 are in engine.test.ts). + */ + +import { describe, it, expect } from "vitest"; +import { SimulationEngine } from "../engine"; +import { computeProcessMetrics, computeGlobalMetrics } from "../metrics"; +import { presets } from "../presets"; +import type { Process, SchedulerConfig } from "../types"; + +// ─── Helpers ────────────────────────────────────────────────────────────────── + +const cfg = (overrides: Partial = {}): SchedulerConfig => ({ + algorithm: "FCFS", + quantum: 2, + contextSwitchTime: 0, + isPreemptive: false, + agingEnabled: false, + agingInterval: 5, + ...overrides, +}); + +const p = ( + id: string, + arrivalTime: number, + bursts: { type: "cpu" | "io"; duration: number }[], + priority = 5, +): Process => ({ + id, + name: id.toUpperCase(), + arrivalTime, + priority, + color: "#fff", + bursts, +}); + +/** Runs the engine and returns per-process metrics keyed by processId */ +function runAndGetMetrics(processes: Process[], config: SchedulerConfig) { + const engine = new SimulationEngine(processes, config); + engine.runAll(); + const rts = engine.runtimeStates; + const metricsMap = Object.fromEntries( + rts.map((rt) => [rt.processId, computeProcessMetrics(rt)]), + ); + const globalMetrics = computeGlobalMetrics( + Object.values(metricsMap), + engine.currentTick + 1, + ); + return { engine, metricsMap, globalMetrics }; +} + +// ─── CT-05: Convoy Effect (FCFS) ────────────────────────────────────────────── + +describe("CT-05: FCFS Convoy Effect", () => { + /** + * Large process P1 arrives first and blocks short processes P2, P3, P4. + * P1: arrival=0, CPU:12 + * P2: arrival=1, CPU:2 + * P3: arrival=2, CPU:1 + * P4: arrival=3, CPU:3 + * + * Expected Gantt: P1(0-11), P2(12-13), P3(14), P4(15-17) + */ + const processes = [ + p("p1", 0, [{ type: "cpu", duration: 12 }]), + p("p2", 1, [{ type: "cpu", duration: 2 }]), + p("p3", 2, [{ type: "cpu", duration: 1 }]), + p("p4", 3, [{ type: "cpu", duration: 3 }]), + ]; + + it("P1 (long process) runs uninterrupted for 12 ticks", () => { + const engine = new SimulationEngine(processes, cfg({ algorithm: "FCFS" })); + const ticks = engine.runAll(); + for (let i = 0; i <= 11; i++) { + expect(ticks[i]?.cpuProcess).toBe("p1"); + } + }); + + it("short processes execute in arrival order after P1 finishes", () => { + const engine = new SimulationEngine(processes, cfg({ algorithm: "FCFS" })); + const ticks = engine.runAll(); + expect(ticks[12]?.cpuProcess).toBe("p2"); + expect(ticks[13]?.cpuProcess).toBe("p2"); + expect(ticks[14]?.cpuProcess).toBe("p3"); + expect(ticks[15]?.cpuProcess).toBe("p4"); + }); + + it("P2, P3, P4 suffer high waiting times (convoy effect)", () => { + const { metricsMap } = runAndGetMetrics(processes, cfg({ algorithm: "FCFS" })); + // P2: waited ticks 1-11 = 11 ticks + expect(metricsMap["p2"]!.waitingTime).toBe(11); + // P3: waited ticks 2-13 = 12 ticks + expect(metricsMap["p3"]!.waitingTime).toBe(12); + // P4: waited ticks 3-14 = 12 ticks + expect(metricsMap["p4"]!.waitingTime).toBe(12); + }); + + it("SJF-NP dramatically reduces average waiting time for the same input", () => { + const { globalMetrics: fcfsGlobal } = runAndGetMetrics(processes, cfg({ algorithm: "FCFS" })); + const { globalMetrics: sjfGlobal } = runAndGetMetrics(processes, cfg({ algorithm: "SJF_NP" })); + + // SJF should yield much lower average waiting time than FCFS (convoy effect) + expect(sjfGlobal.avgWaitingTime).toBeLessThan(fcfsGlobal.avgWaitingTime); + }); +}); + +// ─── CT-06: SJF Non-Preemptive ordering ─────────────────────────────────────── + +describe("CT-06: SJF Non-Preemptive ordering", () => { + /** + * All processes arrive at tick 0. SJF picks shortest first. + * P1: CPU:5, P2: CPU:2, P3: CPU:1, P4: CPU:3 + * Expected order: P3(CPU:1) → P2(CPU:2) → P4(CPU:3) → P1(CPU:5) + * Gantt: P3(0-0), P2(1-2), P4(3-5), P1(6-10) + */ + const processes = [ + p("p1", 0, [{ type: "cpu", duration: 5 }]), + p("p2", 0, [{ type: "cpu", duration: 2 }]), + p("p3", 0, [{ type: "cpu", duration: 1 }]), + p("p4", 0, [{ type: "cpu", duration: 3 }]), + ]; + + it("selects processes in ascending burst duration order", () => { + const engine = new SimulationEngine(processes, cfg({ algorithm: "SJF_NP" })); + const ticks = engine.runAll(); + + // P3 (CPU:1) first + expect(ticks[0]?.cpuProcess).toBe("p3"); + // P2 (CPU:2) second + expect(ticks[1]?.cpuProcess).toBe("p2"); + expect(ticks[2]?.cpuProcess).toBe("p2"); + // P4 (CPU:3) third + expect(ticks[3]?.cpuProcess).toBe("p4"); + expect(ticks[4]?.cpuProcess).toBe("p4"); + expect(ticks[5]?.cpuProcess).toBe("p4"); + // P1 (CPU:5) last + expect(ticks[6]?.cpuProcess).toBe("p1"); + }); + + it("P3 has zero waiting time (runs first)", () => { + const { metricsMap } = runAndGetMetrics(processes, cfg({ algorithm: "SJF_NP" })); + expect(metricsMap["p3"]!.waitingTime).toBe(0); + expect(metricsMap["p3"]!.responseTime).toBe(0); + }); + + it("produces optimal average waiting time (SJF is optimal for non-preemptive)", () => { + const { globalMetrics } = runAndGetMetrics(processes, cfg({ algorithm: "SJF_NP" })); + // Avg waiting: (0 + 1 + 3 + 6) / 4 = 10/4 = 2.5 + expect(globalMetrics.avgWaitingTime).toBeCloseTo(2.5, 5); + }); +}); + +// ─── CT-07: Priority NP Starvation ─────────────────────────────────────────── + +describe("CT-07: Priority NP — P5 starves until all high-priority processes finish", () => { + /** + * P1-P4 have priority 1 (highest). P5 has priority 10 (lowest). + * P5 arrives first but never gets CPU until all P1-P4 finish. + */ + const processes = [ + p("p1", 0, [{ type: "cpu", duration: 3 }], 1), + p("p2", 1, [{ type: "cpu", duration: 3 }], 1), + p("p3", 2, [{ type: "cpu", duration: 3 }], 1), + p("p4", 3, [{ type: "cpu", duration: 3 }], 1), + p("p5", 0, [{ type: "cpu", duration: 5 }], 10), + ]; + + it("P5 does not run while any high-priority process is in the ready queue", () => { + const engine = new SimulationEngine(processes, cfg({ algorithm: "PRIORITY_NP" })); + const ticks = engine.runAll(); + // Ticks 0-11: only P1-P4 should be on CPU + for (let i = 0; i <= 11; i++) { + expect(ticks[i]?.cpuProcess).not.toBe("p5"); + } + }); + + it("P5 starts running only after all high-priority processes finish", () => { + const engine = new SimulationEngine(processes, cfg({ algorithm: "PRIORITY_NP" })); + const ticks = engine.runAll(); + // P4 finishes at tick 12 (runs 9-11); P5 starts at 12 + expect(ticks[12]?.cpuProcess).toBe("p5"); + }); + + it("P5 has the highest waiting time", () => { + const { metricsMap } = runAndGetMetrics(processes, cfg({ algorithm: "PRIORITY_NP" })); + const p5Waiting = metricsMap["p5"]!.waitingTime; + // P5 waited from tick 0 until tick 12 → waiting = 12 + expect(p5Waiting).toBe(12); + // P5 has more waiting time than all others combined + const others = ["p1", "p2", "p3", "p4"].map((id) => metricsMap[id]!.waitingTime); + expect(p5Waiting).toBeGreaterThan(Math.max(...others)); + }); +}); + +// ─── CT-08: Aging prevents starvation ──────────────────────────────────────── + +describe("CT-08: Priority Preemptive with aging — P5 eventually runs earlier", () => { + /** + * Same scenario as CT-07 but with aging enabled (agingInterval=3). + * P5 should have a lower waiting time than in CT-07 because aging + * eventually promotes it to run before all high-priority processes finish. + */ + const processes = [ + p("p1", 0, [{ type: "cpu", duration: 3 }], 1), + p("p2", 1, [{ type: "cpu", duration: 3 }], 1), + p("p3", 2, [{ type: "cpu", duration: 3 }], 1), + p("p4", 3, [{ type: "cpu", duration: 3 }], 1), + p("p5", 0, [{ type: "cpu", duration: 5 }], 10), + ]; + + const agingConfig = cfg({ + algorithm: "PRIORITY_P", + isPreemptive: true, + agingEnabled: true, + agingInterval: 3, + }); + + const noAgingConfig = cfg({ algorithm: "PRIORITY_NP" }); + + it("all processes eventually terminate with aging enabled", () => { + const engine = new SimulationEngine(processes, agingConfig); + engine.runAll(); + expect(engine.isFinished).toBe(true); + const rts = engine.runtimeStates; + for (const rt of rts) { + expect(rt.state).toBe("Terminated"); + } + }); + + it("P5 waiting time with aging is less than or equal to without aging", () => { + const { metricsMap: withAging } = runAndGetMetrics(processes, agingConfig); + const { metricsMap: withoutAging } = runAndGetMetrics(processes, noAgingConfig); + expect(withAging["p5"]!.waitingTime).toBeLessThanOrEqual(withoutAging["p5"]!.waitingTime); + }); +}); + +// ─── CT-09: Multiple I/O Cycles ────────────────────────────────────────────── + +describe("CT-09: Process with multiple CPU/I/O cycles", () => { + /** + * P1 alternates: CPU:2 → IO:3 → CPU:1 → IO:2 → CPU:3 + * This validates state machine across multiple burst transitions. + */ + const processes = [ + p("p1", 0, [ + { type: "cpu", duration: 2 }, + { type: "io", duration: 3 }, + { type: "cpu", duration: 1 }, + { type: "io", duration: 2 }, + { type: "cpu", duration: 3 }, + ]), + ]; + + it("traverses all states in correct order", () => { + const engine = new SimulationEngine(processes, cfg()); + const ticks = engine.runAll(); + const states = ticks.map((t) => t.states["p1"]); + + expect(states[0]).toBe("Running"); // CPU:2 ticks 0-1 + expect(states[1]).toBe("Running"); + expect(states[2]).toBe("Waiting"); // IO:3 ticks 2-4 + expect(states[3]).toBe("Waiting"); + expect(states[4]).toBe("Waiting"); + expect(states[5]).toBe("Running"); // CPU:1 tick 5 + expect(states[6]).toBe("Waiting"); // IO:2 ticks 6-7 + expect(states[7]).toBe("Waiting"); + expect(states[8]).toBe("Running"); // CPU:3 ticks 8-10 + expect(states[9]).toBe("Running"); + expect(states[10]).toBe("Running"); + }); + + it("finishes at the correct tick", () => { + const engine = new SimulationEngine(processes, cfg()); + engine.runAll(); + const rt = engine.runtimeStates[0]!; + // Total duration: 2+3+1+2+3 = 11 ticks → finishTick = 11 + expect(rt.finishTick).toBe(11); + }); + + it("accumulates correct cpu and io times", () => { + const engine = new SimulationEngine(processes, cfg()); + engine.runAll(); + const rt = engine.runtimeStates[0]!; + expect(rt.cpuTime).toBe(6); // 2+1+3 + expect(rt.ioTime).toBe(5); // 3+2 + }); + + it("metrics: turnaround = cpuTime + ioTime + waitingTime", () => { + const { metricsMap } = runAndGetMetrics(processes, cfg()); + const m = metricsMap["p1"]!; + // For a single process, waiting time should be 0 (never in Ready queue) + expect(m.waitingTime).toBe(0); + expect(m.turnaroundTime).toBe(m.cpuTime + m.ioTime + m.waitingTime); + }); +}); + +// ─── CT-10: Simultaneous arrivals — tie-breaking ────────────────────────────── + +describe("CT-10: Simultaneous arrivals — tie-breaking by ID", () => { + /** + * All 4 processes arrive at tick 0 with equal priority and burst duration. + * FCFS tie-break: by processId lexicographic order → p1, p2, p3, p4. + */ + const processes = [ + p("p4", 0, [{ type: "cpu", duration: 2 }]), + p("p2", 0, [{ type: "cpu", duration: 2 }]), + p("p1", 0, [{ type: "cpu", duration: 2 }]), + p("p3", 0, [{ type: "cpu", duration: 2 }]), + ]; + + it("executes processes in lexicographic ID order on tie", () => { + const engine = new SimulationEngine(processes, cfg({ algorithm: "FCFS" })); + const ticks = engine.runAll(); + + expect(ticks[0]?.cpuProcess).toBe("p1"); + expect(ticks[1]?.cpuProcess).toBe("p1"); + expect(ticks[2]?.cpuProcess).toBe("p2"); + expect(ticks[3]?.cpuProcess).toBe("p2"); + expect(ticks[4]?.cpuProcess).toBe("p3"); + expect(ticks[5]?.cpuProcess).toBe("p3"); + expect(ticks[6]?.cpuProcess).toBe("p4"); + expect(ticks[7]?.cpuProcess).toBe("p4"); + }); + + it("first process (p1) has response time 0 and zero waiting time", () => { + const { metricsMap } = runAndGetMetrics(processes, cfg({ algorithm: "FCFS" })); + expect(metricsMap["p1"]!.responseTime).toBe(0); + expect(metricsMap["p1"]!.waitingTime).toBe(0); + }); +}); + +// ─── CT-11: CPU idle gap between arrivals ───────────────────────────────────── + +describe("CT-11: CPU idle gap between process batches", () => { + /** + * P1 finishes early; CPU becomes idle until P2 arrives later. + * P1: arrival=0, CPU:2 + * P2: arrival=6, CPU:2 + * Gap: ticks 2-5 (CPU idle for 4 ticks) + */ + const processes = [ + p("p1", 0, [{ type: "cpu", duration: 2 }]), + p("p2", 6, [{ type: "cpu", duration: 2 }]), + ]; + + it("CPU is idle during the gap (no cpuProcess)", () => { + const engine = new SimulationEngine(processes, cfg()); + const ticks = engine.runAll(); + // ticks 2,3,4,5: CPU should be idle + for (let i = 2; i <= 5; i++) { + expect(ticks[i]?.cpuProcess).toBeNull(); + } + }); + + it("P2 starts immediately on arrival", () => { + const engine = new SimulationEngine(processes, cfg()); + const ticks = engine.runAll(); + expect(ticks[6]?.cpuProcess).toBe("p2"); + }); + + it("P2 has zero waiting time (no competition)", () => { + const { metricsMap } = runAndGetMetrics(processes, cfg()); + expect(metricsMap["p2"]!.waitingTime).toBe(0); + expect(metricsMap["p2"]!.responseTime).toBe(0); + }); + + it("global CPU utilization reflects idle period", () => { + const { globalMetrics } = runAndGetMetrics(processes, cfg()); + // Total CPU used: 4 ticks out of 8 ticks = 50% + expect(globalMetrics.cpuUtilization).toBeCloseTo(50, 5); + }); +}); + +// ─── CT-12: Round Robin with quantum=1 ─────────────────────────────────────── + +describe("CT-12: Round Robin quantum=1 — strict rotation", () => { + /** + * P1(CPU:3), P2(CPU:2), P3(CPU:1) all arrive at tick 0, quantum=1. + * Each tick a different process runs in round-robin order. + * Expected: P1(0), P2(1), P3(2), P1(3), P2(4), P1(5) + */ + const processes = [ + p("p1", 0, [{ type: "cpu", duration: 3 }]), + p("p2", 0, [{ type: "cpu", duration: 2 }]), + p("p3", 0, [{ type: "cpu", duration: 1 }]), + ]; + + it("rotates one tick per process", () => { + const engine = new SimulationEngine(processes, cfg({ algorithm: "RR", quantum: 1 })); + const ticks = engine.runAll(); + + expect(ticks[0]?.cpuProcess).toBe("p1"); + expect(ticks[1]?.cpuProcess).toBe("p2"); + expect(ticks[2]?.cpuProcess).toBe("p3"); + expect(ticks[3]?.cpuProcess).toBe("p1"); + expect(ticks[4]?.cpuProcess).toBe("p2"); + expect(ticks[5]?.cpuProcess).toBe("p1"); + }); + + it("all processes finish at expected ticks", () => { + const engine = new SimulationEngine(processes, cfg({ algorithm: "RR", quantum: 1 })); + engine.runAll(); + const rts = engine.runtimeStates; + const rt1 = rts.find((r) => r.processId === "p1")!; + const rt2 = rts.find((r) => r.processId === "p2")!; + const rt3 = rts.find((r) => r.processId === "p3")!; + + expect(rt3.finishTick).toBe(3); // P3 finishes after 1 run at tick 2 + expect(rt2.finishTick).toBe(5); // P2 finishes after 2 runs + expect(rt1.finishTick).toBe(6); // P1 finishes after 3 runs + }); +}); + +// ─── CT-13: Context switch overhead ────────────────────────────────────────── + +describe("CT-13: Context switch overhead with multiple algorithms", () => { + /** + * Each process switch incurs 1 idle tick (contextSwitchTime=1). + * Tests that context switch overhead is correctly accounted for + * in multiple algorithm contexts. + */ + const processes = [ + p("p1", 0, [{ type: "cpu", duration: 2 }]), + p("p2", 0, [{ type: "cpu", duration: 2 }]), + p("p3", 0, [{ type: "cpu", duration: 2 }]), + ]; + + it("FCFS: inserts 2 context switch ticks for 3 processes", () => { + const engine = new SimulationEngine( + processes, + cfg({ algorithm: "FCFS", contextSwitchTime: 1 }), + ); + const ticks = engine.runAll(); + + // P1: 0-1, ctx: 2, P2: 3-4, ctx: 5, P3: 6-7 + expect(ticks[2]?.contextSwitching).toBe(true); + expect(ticks[2]?.cpuProcess).toBeNull(); + expect(ticks[5]?.contextSwitching).toBe(true); + expect(ticks[5]?.cpuProcess).toBeNull(); + expect(ticks.length).toBe(8); + }); + + it("total simulation time is longer with context switch", () => { + const withCtx = new SimulationEngine(processes, cfg({ algorithm: "FCFS", contextSwitchTime: 1 })); + const withoutCtx = new SimulationEngine(processes, cfg({ algorithm: "FCFS", contextSwitchTime: 0 })); + withCtx.runAll(); + withoutCtx.runAll(); + + // With 2 context switches of 1 tick each: +2 ticks total + expect(withCtx.currentTick).toBe(withoutCtx.currentTick + 2); + }); + + it("context switch ticks are not counted as cpu time for any process", () => { + const engine = new SimulationEngine( + processes, + cfg({ algorithm: "FCFS", contextSwitchTime: 1 }), + ); + engine.runAll(); + const totalCpuTime = engine.runtimeStates.reduce((s, rt) => s + rt.cpuTime, 0); + // 3 processes × 2 cpu ticks each = 6 + expect(totalCpuTime).toBe(6); + }); +}); + +// ─── CT-14: HRRN fairness — waited process wins over fresh arrivals ─────────── + +describe("CT-14: HRRN — long wait compensates for longer burst", () => { + /** + * P1(CPU:1) runs first (only one ready at tick 0). + * When P1 finishes at tick 1, P2(CPU:6, waited=1) and P3(CPU:2, waited=0) are both ready. + * + * HRRN ratios at tick 1: + * P2: (1 + 6) / 6 = 1.167 + * P3: (0 + 2) / 2 = 1.0 + * + * P2 wins because it has been waiting. + */ + const processes = [ + p("p1", 0, [{ type: "cpu", duration: 1 }]), + p("p2", 0, [{ type: "cpu", duration: 6 }]), + p("p3", 1, [{ type: "cpu", duration: 2 }]), + ]; + + it("P2 wins over fresh P3 due to higher response ratio", () => { + const engine = new SimulationEngine(processes, cfg({ algorithm: "HRRN" })); + const ticks = engine.runAll(); + // tick 1: P2 starts (ratio 1.167 > P3 ratio 1.0) + expect(ticks[1]?.cpuProcess).toBe("p2"); + }); + + it("P3 runs only after P2 finishes", () => { + const engine = new SimulationEngine(processes, cfg({ algorithm: "HRRN" })); + const ticks = engine.runAll(); + // P2 runs ticks 1-6; P3 starts at tick 7 + expect(ticks[7]?.cpuProcess).toBe("p3"); + }); +}); + +// ─── CT-15: SRTF — preemption on arrival with complex I/O ──────────────────── + +describe("CT-15: SRTF preemption with I/O processes", () => { + /** + * P1(CPU:5,IO:2,CPU:2) starts at 0. + * P2(CPU:2) arrives at tick 2 — preempts P1 (remaining=3 > 2). + * While P2 runs, P1 goes to ready queue. + * P2 finishes at tick 4; P1 resumes its CPU burst. + */ + const processes = [ + p("p1", 0, [{ type: "cpu", duration: 5 }, { type: "io", duration: 2 }, { type: "cpu", duration: 2 }]), + p("p2", 2, [{ type: "cpu", duration: 2 }]), + ]; + + it("P2 preempts P1 at tick 2", () => { + const engine = new SimulationEngine( + processes, + cfg({ algorithm: "SJF_P", isPreemptive: true }), + ); + const ticks = engine.runAll(); + expect(ticks[0]?.cpuProcess).toBe("p1"); + expect(ticks[1]?.cpuProcess).toBe("p1"); + expect(ticks[2]?.cpuProcess).toBe("p2"); // preemption here + expect(ticks[3]?.cpuProcess).toBe("p2"); + }); + + it("P1 eventually completes all burst phases and terminates", () => { + const engine = new SimulationEngine( + processes, + cfg({ algorithm: "SJF_P", isPreemptive: true }), + ); + engine.runAll(); + expect(engine.isFinished).toBe(true); + const p1rt = engine.runtimeStates.find((r) => r.processId === "p1")!; + expect(p1rt.state).toBe("Terminated"); + expect(p1rt.ioTime).toBe(2); + }); +}); + +// ─── CT-16: Metrics invariant across all algorithms ────────────────────────── + +describe("CT-16: Metrics invariant — turnaround = cpuTime + ioTime + waitingTime", () => { + /** + * For any completed process: + * turnaround = cpuTime + ioTime + waitingTime + * + * This invariant must hold for every algorithm. + */ + const processes = [ + p("p1", 0, [{ type: "cpu", duration: 4 }, { type: "io", duration: 2 }, { type: "cpu", duration: 2 }]), + p("p2", 1, [{ type: "cpu", duration: 3 }]), + p("p3", 2, [{ type: "cpu", duration: 1 }, { type: "io", duration: 3 }, { type: "cpu", duration: 2 }]), + ]; + + const algorithms: SchedulerConfig["algorithm"][] = [ + "FCFS", "SJF_NP", "SJF_P", "RR", "PRIORITY_NP", "PRIORITY_P", "HRRN", + ]; + + for (const algorithm of algorithms) { + it(`holds for ${algorithm}`, () => { + const isPreemptive = algorithm === "SJF_P" || algorithm === "PRIORITY_P"; + const { metricsMap } = runAndGetMetrics( + processes, + cfg({ algorithm, isPreemptive, quantum: 2 }), + ); + for (const [id, m] of Object.entries(metricsMap)) { + expect(m.turnaroundTime, `${algorithm}: ${id} turnaround invariant`).toBeCloseTo( + m.cpuTime + m.ioTime + m.waitingTime, + 5, + ); + } + }); + } +}); + +// ─── CT-17: All processes always terminate ──────────────────────────────────── + +describe("CT-17: All processes eventually terminate (no infinite loops)", () => { + /** + * For every supported algorithm, a simulation must terminate. + * This validates the engine has no deadlocks or infinite scheduling loops. + */ + const processes = [ + p("p1", 0, [{ type: "cpu", duration: 3 }, { type: "io", duration: 2 }, { type: "cpu", duration: 2 }]), + p("p2", 0, [{ type: "cpu", duration: 5 }]), + p("p3", 2, [{ type: "cpu", duration: 1 }]), + p("p4", 3, [{ type: "cpu", duration: 4 }, { type: "io", duration: 1 }, { type: "cpu", duration: 1 }]), + ]; + + const algorithmsWithConfig: [string, SchedulerConfig][] = [ + ["FCFS", cfg({ algorithm: "FCFS" })], + ["SJF_NP", cfg({ algorithm: "SJF_NP" })], + ["SJF_P", cfg({ algorithm: "SJF_P", isPreemptive: true })], + ["RR q=2", cfg({ algorithm: "RR", quantum: 2 })], + ["RR q=1", cfg({ algorithm: "RR", quantum: 1 })], + ["PRIORITY_NP", cfg({ algorithm: "PRIORITY_NP" })], + ["PRIORITY_P", cfg({ algorithm: "PRIORITY_P", isPreemptive: true })], + ["PRIORITY_P+aging", cfg({ algorithm: "PRIORITY_P", isPreemptive: true, agingEnabled: true, agingInterval: 3 })], + ["HRRN", cfg({ algorithm: "HRRN" })], + ]; + + for (const [name, config] of algorithmsWithConfig) { + it(`${name}: all processes reach Terminated state`, () => { + const engine = new SimulationEngine(processes, config); + engine.runAll(); + expect(engine.isFinished).toBe(true); + for (const rt of engine.runtimeStates) { + expect(rt.state, `${name}: process ${rt.processId} should be Terminated`).toBe("Terminated"); + } + }); + } +}); + +// ─── CT-18: Preset validation ───────────────────────────────────────────────── + +describe("CT-18: All presets complete successfully", () => { + /** + * Each preset must run to completion with all processes terminated, + * and produce valid (non-negative) metrics. + */ + for (const preset of presets) { + it(`preset "${preset.name}" terminates and yields valid metrics`, () => { + const engine = new SimulationEngine(preset.processes, preset.config); + engine.runAll(); + + expect(engine.isFinished).toBe(true); + + for (const rt of engine.runtimeStates) { + expect(rt.state).toBe("Terminated"); + expect(rt.finishTick).not.toBeNull(); + expect(rt.startTick).not.toBeNull(); + + const m = computeProcessMetrics(rt); + expect(m.turnaroundTime).toBeGreaterThan(0); + expect(m.waitingTime).toBeGreaterThanOrEqual(0); + expect(m.responseTime).toBeGreaterThanOrEqual(0); + expect(m.cpuTime).toBeGreaterThan(0); + expect(m.ioTime).toBeGreaterThanOrEqual(0); + // Invariant: turnaround = cpuTime + ioTime + waitingTime + expect(m.turnaroundTime).toBeCloseTo(m.cpuTime + m.ioTime + m.waitingTime, 5); + } + }); + } +}); + +// ─── CT-19: RR with I/O — quantum resets correctly after I/O return ─────────── + +describe("CT-19: RR with I/O — process returning from I/O gets fresh quantum", () => { + /** + * P1(CPU:4, IO:2, CPU:2) with quantum=2. + * P2(CPU:6) with quantum=2. + * + * P1 uses 2 CPU ticks (quantum exhausted) → goes to ready. + * P2 uses 2 ticks → goes to ready. + * P1 uses last 2 CPU ticks → goes to I/O. + * While P1 does I/O, P2 runs. + * P1 returns from I/O and gets a fresh quantum for its final 2 CPU ticks. + */ + const processes = [ + p("p1", 0, [{ type: "cpu", duration: 4 }, { type: "io", duration: 2 }, { type: "cpu", duration: 2 }]), + p("p2", 0, [{ type: "cpu", duration: 6 }]), + ]; + + it("P1 and P2 both terminate", () => { + const engine = new SimulationEngine(processes, cfg({ algorithm: "RR", quantum: 2 })); + engine.runAll(); + expect(engine.isFinished).toBe(true); + for (const rt of engine.runtimeStates) { + expect(rt.state).toBe("Terminated"); + } + }); + + it("P1 accumulates correct cpu and io times", () => { + const engine = new SimulationEngine(processes, cfg({ algorithm: "RR", quantum: 2 })); + engine.runAll(); + const p1rt = engine.runtimeStates.find((r) => r.processId === "p1")!; + expect(p1rt.cpuTime).toBe(6); // 4 + 2 + expect(p1rt.ioTime).toBe(2); + }); + + it("metrics invariant holds for both processes", () => { + const { metricsMap } = runAndGetMetrics(processes, cfg({ algorithm: "RR", quantum: 2 })); + for (const m of Object.values(metricsMap)) { + expect(m.turnaroundTime).toBeCloseTo(m.cpuTime + m.ioTime + m.waitingTime, 5); + } + }); +}); + +// ─── CT-20: Single process — no competition edge case ──────────────────────── + +describe("CT-20: Single process — baseline edge case", () => { + /** + * With only one process, there is no scheduling decision to make. + * The process should run uninterrupted and have zero waiting time, + * regardless of algorithm. + */ + const process = p("p1", 0, [ + { type: "cpu", duration: 3 }, + { type: "io", duration: 2 }, + { type: "cpu", duration: 2 }, + ]); + + const algorithms: SchedulerConfig["algorithm"][] = ["FCFS", "SJF_NP", "RR", "PRIORITY_NP", "HRRN"]; + + for (const algorithm of algorithms) { + it(`${algorithm}: single process has zero waiting time`, () => { + const { metricsMap } = runAndGetMetrics([process], cfg({ algorithm, quantum: 2 })); + expect(metricsMap["p1"]!.waitingTime).toBe(0); + expect(metricsMap["p1"]!.responseTime).toBe(0); + }); + } +}); diff --git a/src/core/__tests__/priority_rr.test.ts b/src/core/__tests__/priority_rr.test.ts new file mode 100644 index 0000000..3f4f2fb --- /dev/null +++ b/src/core/__tests__/priority_rr.test.ts @@ -0,0 +1,248 @@ +import { describe, it, expect } from "vitest"; +import { priorityRr } from "../algorithms/priority_rr"; +import { SimulationEngine } from "../engine"; +import type { Process, ProcessRuntime, SchedulerConfig } from "../types"; + +// ---------------------------------------------------------------- +// Helpers +// ---------------------------------------------------------------- + +function makeRt( + id: string, + priority: number, + quantumRemaining = 2, +): ProcessRuntime { + return { + processId: id, + state: "Ready", + remainingBurst: 4, + burstIndex: 0, + arrivalTick: 0, + startTick: null, + finishTick: null, + waitingTime: 0, + cpuTime: 0, + ioTime: 0, + responseTime: null, + quantumRemaining, + currentPriority: priority, + }; +} + +const cfg = (quantum = 2): SchedulerConfig => ({ + algorithm: "PRIORITY_RR", + quantum, + contextSwitchTime: 0, + isPreemptive: true, + agingEnabled: false, + agingInterval: 5, +}); + +const p = ( + id: string, + arrival: number, + cpuDuration: number, + priority = 5, +): Process => ({ + id, + name: id, + arrivalTime: arrival, + priority, + color: "#fff", + bursts: [{ type: "cpu", duration: cpuDuration }], +}); + +// ---------------------------------------------------------------- +// Unit: select() +// ---------------------------------------------------------------- + +describe("PRIORITY_RR select()", () => { + it("returns null for empty queue", () => { + expect(priorityRr.select([], cfg())).toBeNull(); + }); + + it("picks the process with the lowest priority number (highest priority)", () => { + const high = makeRt("high", 1); + const low = makeRt("low", 5); + expect(priorityRr.select([low, high], cfg())?.processId).toBe("high"); + expect(priorityRr.select([high, low], cfg())?.processId).toBe("high"); + }); + + it("picks the FIRST in insertion order when priorities are equal (FIFO = RR)", () => { + const a = makeRt("a", 3); + const b = makeRt("b", 3); + const c = makeRt("c", 3); + expect(priorityRr.select([a, b, c], cfg())?.processId).toBe("a"); + expect(priorityRr.select([b, c, a], cfg())?.processId).toBe("b"); + }); + + it("ignores lower-priority processes when a higher-priority one is present", () => { + const critical = makeRt("critical", 1); + const normal1 = makeRt("n1", 5); + const normal2 = makeRt("n2", 5); + expect( + priorityRr.select([normal1, normal2, critical], cfg())?.processId, + ).toBe("critical"); + }); +}); + +// ---------------------------------------------------------------- +// Unit: shouldPreempt() +// ---------------------------------------------------------------- + +describe("PRIORITY_RR shouldPreempt()", () => { + it("preempts when candidate has strictly higher priority", () => { + const running = makeRt("current", 5); + const higher = makeRt("higher", 1); + expect(priorityRr.shouldPreempt(running, higher, cfg())).toBe(true); + }); + + it("does NOT preempt for same priority (quantum handles rotation)", () => { + const a = makeRt("a", 3); + const b = makeRt("b", 3); + expect(priorityRr.shouldPreempt(a, b, cfg())).toBe(false); + }); + + it("does NOT preempt when candidate has lower priority", () => { + const running = makeRt("current", 1); + const lower = makeRt("lower", 5); + expect(priorityRr.shouldPreempt(running, lower, cfg())).toBe(false); + }); +}); + +// ---------------------------------------------------------------- +// Unit: isQuantumExpired() +// ---------------------------------------------------------------- + +describe("PRIORITY_RR isQuantumExpired()", () => { + it("returns true when quantumRemaining <= 0", () => { + expect(priorityRr.isQuantumExpired(makeRt("p", 5, 0), cfg())).toBe(true); + expect(priorityRr.isQuantumExpired(makeRt("p", 5, -1), cfg())).toBe(true); + }); + + it("returns false when quantum is not exhausted", () => { + expect(priorityRr.isQuantumExpired(makeRt("p", 5, 1), cfg())).toBe(false); + expect(priorityRr.isQuantumExpired(makeRt("p", 5, 2), cfg())).toBe(false); + }); +}); + +// ---------------------------------------------------------------- +// Integration: Round-robin within the same priority band +// ---------------------------------------------------------------- + +describe("PRIORITY_RR integration — RR within same priority", () => { + it("two equal-priority processes rotate via quantum (CT-PRIORITY_RR-01)", () => { + // P1 and P2 both priority=2, CPU:4 each, quantum=2 + // Expected Gantt: P1(0-2), P2(2-4), P1(4-6), P2(6-8) + const processes = [p("p1", 0, 4, 2), p("p2", 0, 4, 2)]; + const engine = new SimulationEngine(processes, cfg(2)); + const ticks = engine.runAll(); + const cpu = ticks.map((t) => t.cpuProcess); + + expect(cpu).toHaveLength(8); + expect(cpu[0]).toBe("p1"); + expect(cpu[1]).toBe("p1"); + expect(cpu[2]).toBe("p2"); + expect(cpu[3]).toBe("p2"); + expect(cpu[4]).toBe("p1"); + expect(cpu[5]).toBe("p1"); + expect(cpu[6]).toBe("p2"); + expect(cpu[7]).toBe("p2"); + }); + + it("three equal-priority processes rotate in arrival order", () => { + // P1(CPU:2), P2(CPU:2), P3(CPU:2), quantum=2 — each finishes in first quantum + const processes = [p("p1", 0, 2, 3), p("p2", 0, 2, 3), p("p3", 0, 2, 3)]; + const engine = new SimulationEngine(processes, cfg(2)); + const ticks = engine.runAll(); + const cpu = ticks.map((t) => t.cpuProcess); + + expect(cpu).toHaveLength(6); + expect(cpu[0]).toBe("p1"); + expect(cpu[1]).toBe("p1"); + expect(cpu[2]).toBe("p2"); + expect(cpu[3]).toBe("p2"); + expect(cpu[4]).toBe("p3"); + expect(cpu[5]).toBe("p3"); + }); +}); + +// ---------------------------------------------------------------- +// Integration: Priority preemption +// ---------------------------------------------------------------- + +describe("PRIORITY_RR integration — priority preemption", () => { + it("high-priority process arriving mid-run immediately preempts (CT-PRIORITY_RR-02)", () => { + // P1: priority=3, arrival=0, CPU:6 (large quantum so it won't expire) + // P2: priority=1, arrival=2, CPU:2 + // Expected: P1(0-1), P2 preempts at tick 2, P2(2-3), P1 resumes(4-7) + const processes = [p("p1", 0, 6, 3), p("p2", 2, 2, 1)]; + const engine = new SimulationEngine(processes, cfg(10)); + const ticks = engine.runAll(); + const cpu = ticks.map((t) => t.cpuProcess); + + // P1 runs ticks 0, 1; P2 preempts at tick 2; P1 resumes after P2 finishes + expect(cpu[0]).toBe("p1"); + expect(cpu[1]).toBe("p1"); + expect(cpu[2]).toBe("p2"); // preempted here + expect(cpu[3]).toBe("p2"); + // After P2 terminates, P1 resumes + expect(cpu[4]).toBe("p1"); + expect(cpu[5]).toBe("p1"); + expect(cpu[6]).toBe("p1"); + expect(cpu[7]).toBe("p1"); + expect(cpu).toHaveLength(8); + }); + + it("lower-priority process cannot preempt a higher-priority running process", () => { + const processes = [p("p1", 0, 4, 1), p("p2", 1, 4, 5)]; + const engine = new SimulationEngine(processes, cfg(10)); + const ticks = engine.runAll(); + const cpu = ticks.map((t) => t.cpuProcess); + + // P1 (priority=1) runs entirely first; P2 waits + expect(cpu.slice(0, 4).every((id) => id === "p1")).toBe(true); + expect(cpu.slice(4).every((id) => id === "p2")).toBe(true); + }); +}); + +// ---------------------------------------------------------------- +// Integration: Combined — preemption + RR (preset scenario) +// ---------------------------------------------------------------- + +describe("PRIORITY_RR integration — combined preemption + RR", () => { + it("preset scenario: P1 & P2 (prio=2) RR, P3 (prio=1) preempts at arrival", () => { + // P1: prio=2, arrival=0, CPU:4 + // P2: prio=2, arrival=0, CPU:4 + // P3: prio=1, arrival=4, CPU:2 — arrives just as P2's first quantum ends + // quantum=2 + // Expected Gantt: P1(0-2), P2(2-4), P3(4-6), P1(6-8), P2(8-10) + const processes = [p("p1", 0, 4, 2), p("p2", 0, 4, 2), p("p3", 4, 2, 1)]; + const engine = new SimulationEngine(processes, cfg(2)); + const ticks = engine.runAll(); + const cpu = ticks.map((t) => t.cpuProcess); + + expect(cpu[0]).toBe("p1"); + expect(cpu[1]).toBe("p1"); + expect(cpu[2]).toBe("p2"); + expect(cpu[3]).toBe("p2"); + expect(cpu[4]).toBe("p3"); // P3 preempts (or takes CPU when it's free) + expect(cpu[5]).toBe("p3"); + expect(cpu[6]).toBe("p1"); + expect(cpu[7]).toBe("p1"); + expect(cpu[8]).toBe("p2"); + expect(cpu[9]).toBe("p2"); + expect(cpu).toHaveLength(10); + }); + + it("all processes terminate correctly", () => { + const processes = [p("p1", 0, 4, 2), p("p2", 0, 4, 2), p("p3", 4, 2, 1)]; + const engine = new SimulationEngine(processes, cfg(2)); + engine.runAll(); + const rts = engine.runtimeStates; + expect(rts.every((rt) => rt.state === "Terminated")).toBe(true); + expect(rts.find((r) => r.processId === "p1")!.cpuTime).toBe(4); + expect(rts.find((r) => r.processId === "p2")!.cpuTime).toBe(4); + expect(rts.find((r) => r.processId === "p3")!.cpuTime).toBe(2); + }); +}); diff --git a/src/core/algorithms/index.ts b/src/core/algorithms/index.ts index a596f29..ab7b801 100644 --- a/src/core/algorithms/index.ts +++ b/src/core/algorithms/index.ts @@ -3,6 +3,7 @@ import { fcfs } from "./fcfs"; import { sjfNp, srtf } from "./sjf"; import { rr } from "./rr"; import { priorityNp, priorityP } from "./priority"; +import { priorityRr } from "./priority_rr"; import { hrrn } from "./hrrn"; import { multilevel } from "./multilevel"; @@ -54,6 +55,7 @@ export const algorithms: Record = { RR: rr, PRIORITY_NP: priorityNp, PRIORITY_P: priorityP, + PRIORITY_RR: priorityRr, HRRN: hrrn, MULTILEVEL: multilevel, }; diff --git a/src/core/algorithms/priority_rr.ts b/src/core/algorithms/priority_rr.ts new file mode 100644 index 0000000..82b42a7 --- /dev/null +++ b/src/core/algorithms/priority_rr.ts @@ -0,0 +1,49 @@ +import type { SchedulerAlgorithm } from "./index"; + +/** + * Priority Round Robin (PRIORITY_RR) + * + * Mimics real-OS scheduling (Windows priority bands, POSIX SCHED_RR): + * + * - The ready queue is conceptually divided into priority bands. + * - The scheduler always dispatches from the highest-priority band + * (lowest numeric value), leaving lower-priority processes waiting. + * - Within the same priority band, processes share the CPU via round-robin + * with the configured quantum — fairness among equals. + * - A running process is preempted immediately when a STRICTLY higher-priority + * process becomes ready (arrival or I/O completion). + * - Quantum expiry only rotates within the same priority band; it does not + * allow a lower-priority process to run while a same-priority one is waiting. + * - Compatible with the aging mechanism: as low-priority processes age their + * currentPriority decreases, eventually entering a higher-priority band. + */ +export const priorityRr: SchedulerAlgorithm = { + select(readyQueue) { + if (readyQueue.length === 0) return null; + + // Find the highest priority level (smallest numeric value) present. + let bestPriority = Infinity; + for (const rt of readyQueue) { + if (rt.currentPriority < bestPriority) bestPriority = rt.currentPriority; + } + + // Within that band, return the first process (FIFO insertion order). + // The engine maintains insertion order, so this gives round-robin rotation + // after quantum expiry: the expired process goes to the tail, the next + // same-priority process is now at the head. + return readyQueue.find(rt => rt.currentPriority === bestPriority) ?? null; + }, + + // Preempt ONLY for strictly higher priority. + // Same-priority candidates are handled by quantum expiry — no unnecessary + // context switches within a priority band. + shouldPreempt(current, candidate) { + return candidate.currentPriority < current.currentPriority; + }, + + // Quantum expiry drives round-robin rotation within a priority band, + // exactly like plain Round Robin. + isQuantumExpired(runtime) { + return runtime.quantumRemaining <= 0; + }, +}; diff --git a/src/core/presets.ts b/src/core/presets.ts index 5e52c81..bb3df64 100644 --- a/src/core/presets.ts +++ b/src/core/presets.ts @@ -67,6 +67,16 @@ export const presets: Preset[] = [ ], config: defaultConfig({ algorithm: "PRIORITY_P", isPreemptive: true, agingEnabled: true, agingInterval: 3 }), }, + { + name: "priority_rr_demo", + description: "Priority RR: P3 (priority 1) preempts mid-run; P1 & P2 (priority 2) share CPU via RR", + processes: [ + { id: "p1", name: "P1", arrivalTime: 0, priority: 2, color: "#4FC3F7", bursts: [{ type: "cpu", duration: 4 }] }, + { id: "p2", name: "P2", arrivalTime: 0, priority: 2, color: "#81C784", bursts: [{ type: "cpu", duration: 4 }] }, + { id: "p3", name: "P3", arrivalTime: 4, priority: 1, color: "#F06292", bursts: [{ type: "cpu", duration: 2 }] }, + ], + config: defaultConfig({ algorithm: "PRIORITY_RR", quantum: 2 }), + }, { name: "io_heavy", description: "Mixed CPU-bound and I/O-bound processes", @@ -77,4 +87,27 @@ export const presets: Preset[] = [ ], config: defaultConfig({ algorithm: "SJF_P", isPreemptive: true }), }, + { + name: "convoy_effect", + description: "One long process blocks shorter ones — FCFS convoy vs SJF comparison", + processes: [ + { id: "p1", name: "P1", arrivalTime: 0, priority: 5, color: "#EF5350", bursts: [{ type: "cpu", duration: 12 }] }, + { id: "p2", name: "P2", arrivalTime: 1, priority: 5, color: "#81C784", bursts: [{ type: "cpu", duration: 2 }] }, + { id: "p3", name: "P3", arrivalTime: 2, priority: 5, color: "#FFB74D", bursts: [{ type: "cpu", duration: 1 }] }, + { id: "p4", name: "P4", arrivalTime: 3, priority: 5, color: "#CE93D8", bursts: [{ type: "cpu", duration: 3 }] }, + ], + config: defaultConfig({ algorithm: "FCFS" }), + }, + { + name: "multilevel_demo", + description: "Priority RR with 3 priority tiers — demonstrates multilevel scheduling", + processes: [ + { id: "p1", name: "P1", arrivalTime: 0, priority: 1, color: "#EF5350", bursts: [{ type: "cpu", duration: 4 }] }, + { id: "p2", name: "P2", arrivalTime: 0, priority: 1, color: "#FF8A65", bursts: [{ type: "cpu", duration: 3 }] }, + { id: "p3", name: "P3", arrivalTime: 2, priority: 2, color: "#81C784", bursts: [{ type: "cpu", duration: 5 }] }, + { id: "p4", name: "P4", arrivalTime: 2, priority: 2, color: "#4FC3F7", bursts: [{ type: "cpu", duration: 2 }] }, + { id: "p5", name: "P5", arrivalTime: 4, priority: 3, color: "#CE93D8", bursts: [{ type: "cpu", duration: 6 }] }, + ], + config: defaultConfig({ algorithm: "PRIORITY_RR", quantum: 2 }), + }, ]; diff --git a/src/core/types.ts b/src/core/types.ts index f948320..b42eb21 100644 --- a/src/core/types.ts +++ b/src/core/types.ts @@ -9,6 +9,7 @@ export type SchedulingAlgorithm = | "RR" | "PRIORITY_NP" | "PRIORITY_P" + | "PRIORITY_RR" | "MULTILEVEL" | "HRRN"; diff --git a/src/hooks/useExport.ts b/src/hooks/useExport.ts new file mode 100644 index 0000000..a795788 --- /dev/null +++ b/src/hooks/useExport.ts @@ -0,0 +1,56 @@ +import type { ProcessMetrics } from "@core/types"; +import type { Process } from "@core/types"; + +interface ProcessMap { + [id: string]: Process; +} + +function downloadBlob(content: string, filename: string, mimeType: string) { + const blob = new Blob([content], { type: mimeType }); + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = filename; + a.click(); + URL.revokeObjectURL(url); +} + +export function useExport() { + const exportCSV = (metrics: ProcessMetrics[], processMap: ProcessMap) => { + const headers = [ + "Processo", + "Arrival", + "Start", + "Finish", + "Response", + "Turnaround", + "Waiting", + "CPU Time", + "I/O Time", + "CPU%", + "Bound", + ]; + + const rows = metrics.map((m) => { + const name = processMap[m.processId]?.name ?? m.processId; + return [ + name, + m.arrivalTime, + m.startTick, + m.finishTick, + m.responseTime, + m.turnaroundTime, + m.waitingTime, + m.cpuTime, + m.ioTime, + m.cpuUtilization.toFixed(1), + m.boundType, + ].join(","); + }); + + const csv = [headers.join(","), ...rows].join("\n"); + downloadBlob(csv, "pss-metrics.csv", "text/csv;charset=utf-8;"); + }; + + return { exportCSV }; +} diff --git a/src/hooks/useGanttScroll.ts b/src/hooks/useGanttScroll.ts new file mode 100644 index 0000000..ecefb51 --- /dev/null +++ b/src/hooks/useGanttScroll.ts @@ -0,0 +1,22 @@ +import { useEffect, type RefObject } from "react"; +import { CELL_W } from "../components/GanttChart/constants"; + +/** + * Smoothly scrolls `containerRef` so the current tick stays horizontally + * centred in the viewport. Only triggers when the simulation is actively + * running (to avoid stealing the user's manual scroll while paused). + */ +export function useGanttScroll( + containerRef: RefObject, + currentTickIndex: number, + isRunning: boolean, +) { + useEffect(() => { + if (!isRunning) return; + const el = containerRef.current; + if (!el) return; + + const targetLeft = currentTickIndex * CELL_W - el.clientWidth / 2 + CELL_W / 2; + el.scrollTo({ left: Math.max(0, targetLeft), behavior: "smooth" }); + }, [containerRef, currentTickIndex, isRunning]); +} diff --git a/src/index.css b/src/index.css index c426e83..68161dd 100644 --- a/src/index.css +++ b/src/index.css @@ -17,4 +17,28 @@ -ms-overflow-style: none; scrollbar-width: none; } + + /* Custom scrollbar for Gantt */ + .gantt-scrollbar::-webkit-scrollbar { + height: 6px; + } + .gantt-scrollbar::-webkit-scrollbar-track { + background: #0f172a; /* slate-900 */ + } + .gantt-scrollbar::-webkit-scrollbar-thumb { + background: #334155; /* slate-700 */ + border-radius: 10px; + } + .gantt-scrollbar::-webkit-scrollbar-thumb:hover { + background: #475569; /* slate-600 */ + } + + @keyframes gantt-cursor-pulse { + 0%, 100% { opacity: 0.3; } + 50% { opacity: 1; } + } + + .gantt-cursor { + animation: gantt-cursor-pulse 2s ease-in-out infinite; + } } diff --git a/src/store/simulationStore.ts b/src/store/simulationStore.ts index 049336b..670b293 100644 --- a/src/store/simulationStore.ts +++ b/src/store/simulationStore.ts @@ -64,6 +64,8 @@ export const useSimulationStore = create()((set, get) => ({ const { _processes, _config } = get(); if (_processes.length === 0 || _config === null) return; const engine = new SimulationEngine(_processes, _config); - set({ engine, ticks: [], status: "paused" }); + // Return to "idle" so the next Play/Step re-runs init() with the + // current processStore config (picks up algorithm changes, etc.) + set({ engine, ticks: [], status: "idle" }); }, })); diff --git a/tsconfig.app.json b/tsconfig.app.json index ca97cdd..33c5528 100644 --- a/tsconfig.app.json +++ b/tsconfig.app.json @@ -19,7 +19,8 @@ "paths": { "@core/*": ["./src/core/*"], "@components/*": ["./src/components/*"], - "@store/*": ["./src/store/*"] + "@store/*": ["./src/store/*"], + "@hooks/*": ["./src/hooks/*"] } }, "include": ["src"] diff --git a/vite.config.ts b/vite.config.ts index 93bb192..7f8d7e8 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -20,6 +20,7 @@ export default defineConfig({ "@core": path.resolve(__dirname, "./src/core"), "@components": path.resolve(__dirname, "./src/components"), "@store": path.resolve(__dirname, "./src/store"), + "@hooks": path.resolve(__dirname, "./src/hooks"), }, }, });