UI: Fix (most) perf issues in Active Scripts (#498)

This commit is contained in:
David Walker 2023-04-30 16:31:29 -07:00 committed by GitHub
parent 2f46831ad1
commit 8b7166e4ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 11 additions and 38 deletions

@ -1,4 +0,0 @@
import { EventEmitter } from "../utils/EventEmitter";
/** Event emitter that triggers when scripts are started/stopped */
export const WorkerScriptStartStopEventEmitter = new EventEmitter<[]>();

@ -5,7 +5,6 @@
import { ScriptDeath } from "./ScriptDeath"; import { ScriptDeath } from "./ScriptDeath";
import { WorkerScript } from "./WorkerScript"; import { WorkerScript } from "./WorkerScript";
import { workerScripts } from "./WorkerScripts"; import { workerScripts } from "./WorkerScripts";
import { WorkerScriptStartStopEventEmitter } from "./WorkerScriptStartStopEventEmitter";
import { GetServer } from "../Server/AllServers"; import { GetServer } from "../Server/AllServers";
import { AddRecentScript } from "./RecentScripts"; import { AddRecentScript } from "./RecentScripts";
@ -91,5 +90,4 @@ function removeWorkerScript(workerScript: WorkerScript): void {
workerScripts.delete(workerScript.pid); workerScripts.delete(workerScript.pid);
AddRecentScript(workerScript); AddRecentScript(workerScript);
WorkerScriptStartStopEventEmitter.emit();
} }

@ -6,7 +6,6 @@ import { killWorkerScript } from "./Netscript/killWorkerScript";
import { ScriptDeath } from "./Netscript/ScriptDeath"; import { ScriptDeath } from "./Netscript/ScriptDeath";
import { WorkerScript } from "./Netscript/WorkerScript"; import { WorkerScript } from "./Netscript/WorkerScript";
import { workerScripts } from "./Netscript/WorkerScripts"; import { workerScripts } from "./Netscript/WorkerScripts";
import { WorkerScriptStartStopEventEmitter } from "./Netscript/WorkerScriptStartStopEventEmitter";
import { generateNextPid } from "./Netscript/Pid"; import { generateNextPid } from "./Netscript/Pid";
import { CONSTANTS } from "./Constants"; import { CONSTANTS } from "./Constants";
@ -311,7 +310,6 @@ function createAndAddWorkerScript(runningScriptObj: RunningScript, server: BaseS
// Add the WorkerScript to the global pool // Add the WorkerScript to the global pool
workerScripts.set(pid, workerScript); workerScripts.set(pid, workerScript);
WorkerScriptStartStopEventEmitter.emit();
// Start the script's execution using the correct function for file type // Start the script's execution using the correct function for file type
(workerScript.name.endsWith(".js") ? startNetscript2Script : startNetscript1Script)(workerScript) (workerScript.name.endsWith(".js") ? startNetscript2Script : startNetscript1Script)(workerScript)

@ -17,7 +17,7 @@ interface IProps {
export function ActiveScriptsRoot(props: IProps): React.ReactElement { export function ActiveScriptsRoot(props: IProps): React.ReactElement {
const [tab, setTab] = useState<"active" | "recent">("active"); const [tab, setTab] = useState<"active" | "recent">("active");
useRerender(200); useRerender(400);
function handleChange(event: React.SyntheticEvent, tab: "active" | "recent"): void { function handleChange(event: React.SyntheticEvent, tab: "active" | "recent"): void {
setTab(tab); setTab(tab);

@ -2,7 +2,7 @@
* React Component for rendering the Accordion elements for all servers * React Component for rendering the Accordion elements for all servers
* on which scripts are running * on which scripts are running
*/ */
import React, { useState, useEffect } from "react"; import React, { useState } from "react";
import { ServerAccordion } from "./ServerAccordion"; import { ServerAccordion } from "./ServerAccordion";
@ -10,13 +10,11 @@ import TextField from "@mui/material/TextField";
import List from "@mui/material/List"; import List from "@mui/material/List";
import TablePagination from "@mui/material/TablePagination"; import TablePagination from "@mui/material/TablePagination";
import { WorkerScript } from "../../Netscript/WorkerScript"; import { WorkerScript } from "../../Netscript/WorkerScript";
import { WorkerScriptStartStopEventEmitter } from "../../Netscript/WorkerScriptStartStopEventEmitter";
import { GetServer } from "../../Server/AllServers"; import { GetServer } from "../../Server/AllServers";
import { BaseServer } from "../../Server/BaseServer"; import { BaseServer } from "../../Server/BaseServer";
import { Settings } from "../../Settings/Settings"; import { Settings } from "../../Settings/Settings";
import { TablePaginationActionsAll } from "../React/TablePaginationActionsAll"; import { TablePaginationActionsAll } from "../React/TablePaginationActionsAll";
import SearchIcon from "@mui/icons-material/Search"; import SearchIcon from "@mui/icons-material/Search";
import { useRerender } from "../React/hooks";
import { matchScriptPathUnanchored } from "../../utils/helpers/scriptKey"; import { matchScriptPathUnanchored } from "../../utils/helpers/scriptKey";
import lodash from "lodash"; import lodash from "lodash";
@ -38,13 +36,6 @@ export function ServerAccordions(props: IProps): React.ReactElement {
const [filter, setFilter] = useState(""); const [filter, setFilter] = useState("");
const [page, setPage] = useState(0); const [page, setPage] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(Settings.ActiveScriptsServerPageSize); const [rowsPerPage, setRowsPerPage] = useState(Settings.ActiveScriptsServerPageSize);
const rerenderHook = useRerender();
let scheduledRerender = false;
const rerender = () => {
if (scheduledRerender) return;
scheduledRerender = true;
requestAnimationFrame(rerenderHook);
};
const handleChangePage = (event: unknown, newPage: number): void => { const handleChangePage = (event: unknown, newPage: number): void => {
setPage(newPage); setPage(newPage);
@ -92,8 +83,6 @@ export function ServerAccordions(props: IProps): React.ReactElement {
return false; return false;
}); });
useEffect(() => WorkerScriptStartStopEventEmitter.subscribe(rerender));
return ( return (
<> <>
<TextField <TextField

@ -1,9 +1,9 @@
import { startWorkerScript } from "../../../src/NetscriptWorker"; import { startWorkerScript } from "../../../src/NetscriptWorker";
import { workerScripts } from "../../../src/Netscript/WorkerScripts";
import { config as EvaluatorConfig } from "../../../src/NetscriptJSEvaluator"; import { config as EvaluatorConfig } from "../../../src/NetscriptJSEvaluator";
import { Server } from "../../../src/Server/Server"; import { Server } from "../../../src/Server/Server";
import { RunningScript } from "../../../src/Script/RunningScript"; import { RunningScript } from "../../../src/Script/RunningScript";
import { AddToAllServers, DeleteServer } from "../../../src/Server/AllServers"; import { AddToAllServers, DeleteServer } from "../../../src/Server/AllServers";
import { WorkerScriptStartStopEventEmitter } from "../../../src/Netscript/WorkerScriptStartStopEventEmitter";
import { AlertEvents } from "../../../src/ui/React/AlertManager"; import { AlertEvents } from "../../../src/ui/React/AlertManager";
import type { Script } from "src/Script/Script"; import type { Script } from "src/Script/Script";
import { ScriptFilePath } from "src/Paths/ScriptFilePath"; import { ScriptFilePath } from "src/Paths/ScriptFilePath";
@ -97,23 +97,15 @@ test.each([
const ramUsage = script.getRamUsage(server.scripts); const ramUsage = script.getRamUsage(server.scripts);
if (!ramUsage) throw new Error(`ramUsage calculated to be ${ramUsage}`); if (!ramUsage) throw new Error(`ramUsage calculated to be ${ramUsage}`);
const runningScript = new RunningScript(script, ramUsage as number); const runningScript = new RunningScript(script, ramUsage as number);
expect(startWorkerScript(runningScript, server)).toBeGreaterThan(0); const pid = startWorkerScript(runningScript, server);
// We don't care about start, so subscribe after that. Await script death. expect(pid).toBeGreaterThan(0);
const result = await Promise.race([ // Manually attach an atExit to the now-created WorkerScript, so we can
alerted, // await script death.
new Promise((resolve) => { const ws = workerScripts.get(pid);
eventDelete = WorkerScriptStartStopEventEmitter.subscribe(() => { expect(ws).toBeDefined();
for (const byPid of server.runningScriptMap.values()) { const result = await Promise.race([alerted, new Promise((resolve) => (ws.atExit = resolve))]);
for (const rs of byPid.values()) {
if (rs === runningScript) return;
}
}
resolve(null);
});
}),
]);
// If an error alert was thrown, we catch it here. // If an error alert was thrown, we catch it here.
expect(result).toBeNull(); expect(result).not.toBeDefined();
expect(runningScript.logs).toEqual(expectedLog); expect(runningScript.logs).toEqual(expectedLog);
} finally { } finally {
eventDelete(); eventDelete();