mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-29 19:13:49 +01:00
Merge pull request #2373 from MartinFournier/feature/mem-verbose
Add detailed ram cost to mem command
This commit is contained in:
commit
c722ff5982
@ -16,6 +16,17 @@ import { WorkerScript } from "../Netscript/WorkerScript";
|
|||||||
import { areImportsEquals } from "../Terminal/DirectoryHelpers";
|
import { areImportsEquals } from "../Terminal/DirectoryHelpers";
|
||||||
import { IPlayer } from "../PersonObjects/IPlayer";
|
import { IPlayer } from "../PersonObjects/IPlayer";
|
||||||
|
|
||||||
|
export interface RamUsageEntry {
|
||||||
|
type: 'ns' | 'dom' | 'fn' | 'misc';
|
||||||
|
name: string;
|
||||||
|
cost: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RamCalculation {
|
||||||
|
cost: number;
|
||||||
|
entries?: RamUsageEntry[];
|
||||||
|
}
|
||||||
|
|
||||||
// These special strings are used to reference the presence of a given logical
|
// These special strings are used to reference the presence of a given logical
|
||||||
// construct within a user script.
|
// construct within a user script.
|
||||||
const specialReferenceIF = "__SPECIAL_referenceIf";
|
const specialReferenceIF = "__SPECIAL_referenceIf";
|
||||||
@ -38,7 +49,7 @@ async function parseOnlyRamCalculate(
|
|||||||
otherScripts: Script[],
|
otherScripts: Script[],
|
||||||
code: string,
|
code: string,
|
||||||
workerScript: WorkerScript,
|
workerScript: WorkerScript,
|
||||||
): Promise<number | RamCalculationErrorCode> {
|
): Promise<RamCalculation> {
|
||||||
try {
|
try {
|
||||||
/**
|
/**
|
||||||
* Maps dependent identifiers to their dependencies.
|
* Maps dependent identifiers to their dependencies.
|
||||||
@ -98,12 +109,12 @@ async function parseOnlyRamCalculate(
|
|||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(`Error dynamically importing module from ${nextModule} for RAM calculations: ${e}`);
|
console.error(`Error dynamically importing module from ${nextModule} for RAM calculations: ${e}`);
|
||||||
return RamCalculationErrorCode.URLImportError;
|
return { cost: RamCalculationErrorCode.URLImportError };
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!Array.isArray(otherScripts)) {
|
if (!Array.isArray(otherScripts)) {
|
||||||
console.warn(`parseOnlyRamCalculate() not called with array of scripts`);
|
console.warn(`parseOnlyRamCalculate() not called with array of scripts`);
|
||||||
return RamCalculationErrorCode.ImportError;
|
return { cost: RamCalculationErrorCode.ImportError };
|
||||||
}
|
}
|
||||||
|
|
||||||
let script = null;
|
let script = null;
|
||||||
@ -116,7 +127,7 @@ async function parseOnlyRamCalculate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (script == null) {
|
if (script == null) {
|
||||||
return RamCalculationErrorCode.ImportError; // No such script on the server
|
return { cost: RamCalculationErrorCode.ImportError }; // No such script on the server
|
||||||
}
|
}
|
||||||
|
|
||||||
code = script.code;
|
code = script.code;
|
||||||
@ -128,6 +139,7 @@ async function parseOnlyRamCalculate(
|
|||||||
// Finally, walk the reference map and generate a ram cost. The initial set of keys to scan
|
// Finally, walk the reference map and generate a ram cost. The initial set of keys to scan
|
||||||
// are those that start with __SPECIAL_INITIAL_MODULE__.
|
// are those that start with __SPECIAL_INITIAL_MODULE__.
|
||||||
let ram = RamCostConstants.ScriptBaseRamCost;
|
let ram = RamCostConstants.ScriptBaseRamCost;
|
||||||
|
const detailedCosts: RamUsageEntry[] = [{ type: 'misc', name: 'baseCost', cost: RamCostConstants.ScriptBaseRamCost}];
|
||||||
const unresolvedRefs = Object.keys(dependencyMap).filter((s) => s.startsWith(initialModule));
|
const unresolvedRefs = Object.keys(dependencyMap).filter((s) => s.startsWith(initialModule));
|
||||||
const resolvedRefs = new Set();
|
const resolvedRefs = new Set();
|
||||||
while (unresolvedRefs.length > 0) {
|
while (unresolvedRefs.length > 0) {
|
||||||
@ -137,15 +149,19 @@ async function parseOnlyRamCalculate(
|
|||||||
// Check if this is one of the special keys, and add the appropriate ram cost if so.
|
// Check if this is one of the special keys, and add the appropriate ram cost if so.
|
||||||
if (ref === "hacknet" && !resolvedRefs.has("hacknet")) {
|
if (ref === "hacknet" && !resolvedRefs.has("hacknet")) {
|
||||||
ram += RamCostConstants.ScriptHacknetNodesRamCost;
|
ram += RamCostConstants.ScriptHacknetNodesRamCost;
|
||||||
|
detailedCosts.push({ type: 'ns', name: 'hacknet', cost: RamCostConstants.ScriptHacknetNodesRamCost});
|
||||||
}
|
}
|
||||||
if (ref === "document" && !resolvedRefs.has("document")) {
|
if (ref === "document" && !resolvedRefs.has("document")) {
|
||||||
ram += RamCostConstants.ScriptDomRamCost;
|
ram += RamCostConstants.ScriptDomRamCost;
|
||||||
|
detailedCosts.push({ type: 'dom', name: 'document', cost: RamCostConstants.ScriptDomRamCost});
|
||||||
}
|
}
|
||||||
if (ref === "window" && !resolvedRefs.has("window")) {
|
if (ref === "window" && !resolvedRefs.has("window")) {
|
||||||
ram += RamCostConstants.ScriptDomRamCost;
|
ram += RamCostConstants.ScriptDomRamCost;
|
||||||
|
detailedCosts.push({ type: 'dom', name: 'window', cost: RamCostConstants.ScriptDomRamCost});
|
||||||
}
|
}
|
||||||
if (ref === "corporation" && !resolvedRefs.has("corporation")) {
|
if (ref === "corporation" && !resolvedRefs.has("corporation")) {
|
||||||
ram += RamCostConstants.ScriptCorporationRamCost;
|
ram += RamCostConstants.ScriptCorporationRamCost;
|
||||||
|
detailedCosts.push({ type: 'ns', name: 'corporation', cost: RamCostConstants.ScriptCorporationRamCost});
|
||||||
}
|
}
|
||||||
|
|
||||||
resolvedRefs.add(ref);
|
resolvedRefs.add(ref);
|
||||||
@ -187,34 +203,45 @@ async function parseOnlyRamCalculate(
|
|||||||
|
|
||||||
// This accounts for namespaces (Bladeburner, CodingCpntract, etc.)
|
// This accounts for namespaces (Bladeburner, CodingCpntract, etc.)
|
||||||
let func;
|
let func;
|
||||||
|
let refDetail = 'n/a';
|
||||||
if (ref in workerScript.env.vars.bladeburner) {
|
if (ref in workerScript.env.vars.bladeburner) {
|
||||||
func = workerScript.env.vars.bladeburner[ref];
|
func = workerScript.env.vars.bladeburner[ref];
|
||||||
|
refDetail = `bladeburner.${ref}`;
|
||||||
} else if (ref in workerScript.env.vars.codingcontract) {
|
} else if (ref in workerScript.env.vars.codingcontract) {
|
||||||
func = workerScript.env.vars.codingcontract[ref];
|
func = workerScript.env.vars.codingcontract[ref];
|
||||||
|
refDetail = `codingcontract.${ref}`;
|
||||||
} else if (ref in workerScript.env.vars.stanek) {
|
} else if (ref in workerScript.env.vars.stanek) {
|
||||||
func = workerScript.env.vars.stanek[ref];
|
func = workerScript.env.vars.stanek[ref];
|
||||||
|
refDetail = `stanek.${ref}`;
|
||||||
} else if (ref in workerScript.env.vars.gang) {
|
} else if (ref in workerScript.env.vars.gang) {
|
||||||
func = workerScript.env.vars.gang[ref];
|
func = workerScript.env.vars.gang[ref];
|
||||||
|
refDetail = `gang.${ref}`;
|
||||||
} else if (ref in workerScript.env.vars.sleeve) {
|
} else if (ref in workerScript.env.vars.sleeve) {
|
||||||
func = workerScript.env.vars.sleeve[ref];
|
func = workerScript.env.vars.sleeve[ref];
|
||||||
|
refDetail = `sleeve.${ref}`;
|
||||||
} else if (ref in workerScript.env.vars.stock) {
|
} else if (ref in workerScript.env.vars.stock) {
|
||||||
func = workerScript.env.vars.stock[ref];
|
func = workerScript.env.vars.stock[ref];
|
||||||
|
refDetail = `stock.${ref}`;
|
||||||
} else if (ref in workerScript.env.vars.ui) {
|
} else if (ref in workerScript.env.vars.ui) {
|
||||||
func = workerScript.env.vars.ui[ref];
|
func = workerScript.env.vars.ui[ref];
|
||||||
|
refDetail = `ui.${ref}`;
|
||||||
} else {
|
} else {
|
||||||
func = workerScript.env.vars[ref];
|
func = workerScript.env.vars[ref];
|
||||||
|
refDetail = `${ref}`;
|
||||||
}
|
}
|
||||||
ram += applyFuncRam(func);
|
const fnRam = applyFuncRam(func);
|
||||||
|
ram += fnRam;
|
||||||
|
detailedCosts.push({ type: 'fn', name: refDetail, cost: fnRam});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ram;
|
return { cost: ram, entries: detailedCosts.filter(e => e.cost > 0) };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// console.info("parse or eval error: ", error);
|
// console.info("parse or eval error: ", error);
|
||||||
// This is not unexpected. The user may be editing a script, and it may be in
|
// This is not unexpected. The user may be editing a script, and it may be in
|
||||||
// a transitory invalid state.
|
// a transitory invalid state.
|
||||||
return RamCalculationErrorCode.SyntaxError;
|
return { cost: RamCalculationErrorCode.SyntaxError };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -382,7 +409,7 @@ export async function calculateRamUsage(
|
|||||||
player: IPlayer,
|
player: IPlayer,
|
||||||
codeCopy: string,
|
codeCopy: string,
|
||||||
otherScripts: Script[],
|
otherScripts: Script[],
|
||||||
): Promise<RamCalculationErrorCode | number> {
|
): Promise<RamCalculation> {
|
||||||
// We don't need a real WorkerScript for this. Just an object that keeps
|
// We don't need a real WorkerScript for this. Just an object that keeps
|
||||||
// track of whatever's needed for RAM calculations
|
// track of whatever's needed for RAM calculations
|
||||||
const workerScript = {
|
const workerScript = {
|
||||||
@ -397,8 +424,8 @@ export async function calculateRamUsage(
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(`Failed to parse script for RAM calculations:`);
|
console.error(`Failed to parse script for RAM calculations:`);
|
||||||
console.error(e);
|
console.error(e);
|
||||||
return RamCalculationErrorCode.SyntaxError;
|
return { cost: RamCalculationErrorCode.SyntaxError };
|
||||||
}
|
}
|
||||||
|
|
||||||
return RamCalculationErrorCode.SyntaxError;
|
return { cost: RamCalculationErrorCode.SyntaxError };
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* This does NOT represent a script that is actively running and
|
* This does NOT represent a script that is actively running and
|
||||||
* being evaluated. See RunningScript for that
|
* being evaluated. See RunningScript for that
|
||||||
*/
|
*/
|
||||||
import { calculateRamUsage } from "./RamCalculations";
|
import { calculateRamUsage, RamUsageEntry } from "./RamCalculations";
|
||||||
import { ScriptUrl } from "./ScriptUrl";
|
import { ScriptUrl } from "./ScriptUrl";
|
||||||
|
|
||||||
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver";
|
import { Generic_fromJSON, Generic_toJSON, Reviver } from "../utils/JSONReviver";
|
||||||
@ -38,6 +38,7 @@ export class Script {
|
|||||||
|
|
||||||
// Amount of RAM this Script requres to run
|
// Amount of RAM this Script requres to run
|
||||||
ramUsage = 0;
|
ramUsage = 0;
|
||||||
|
ramUsageEntries?: RamUsageEntry[];
|
||||||
|
|
||||||
// hostname of server that this script is on.
|
// hostname of server that this script is on.
|
||||||
server = "";
|
server = "";
|
||||||
@ -131,8 +132,9 @@ export class Script {
|
|||||||
*/
|
*/
|
||||||
async updateRamUsage(player: IPlayer, otherScripts: Script[]): Promise<void> {
|
async updateRamUsage(player: IPlayer, otherScripts: Script[]): Promise<void> {
|
||||||
const res = await calculateRamUsage(player, this.code, otherScripts);
|
const res = await calculateRamUsage(player, this.code, otherScripts);
|
||||||
if (res > 0) {
|
if (res.cost > 0) {
|
||||||
this.ramUsage = roundToTwo(res);
|
this.ramUsage = roundToTwo(res.cost);
|
||||||
|
this.ramUsageEntries = res.entries;
|
||||||
}
|
}
|
||||||
this.markUpdated();
|
this.markUpdated();
|
||||||
}
|
}
|
||||||
|
@ -227,11 +227,11 @@ export function Root(props: IProps): React.ReactElement {
|
|||||||
setUpdatingRam(true);
|
setUpdatingRam(true);
|
||||||
const codeCopy = newCode + "";
|
const codeCopy = newCode + "";
|
||||||
const ramUsage = await calculateRamUsage(props.player, codeCopy, props.player.getCurrentServer().scripts);
|
const ramUsage = await calculateRamUsage(props.player, codeCopy, props.player.getCurrentServer().scripts);
|
||||||
if (ramUsage > 0) {
|
if (ramUsage.cost > 0) {
|
||||||
debouncedSetRAM("RAM: " + numeralWrapper.formatRAM(ramUsage));
|
debouncedSetRAM("RAM: " + numeralWrapper.formatRAM(ramUsage.cost));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (ramUsage) {
|
switch (ramUsage.cost) {
|
||||||
case RamCalculationErrorCode.ImportError: {
|
case RamCalculationErrorCode.ImportError: {
|
||||||
debouncedSetRAM("RAM: Import Error");
|
debouncedSetRAM("RAM: Import Error");
|
||||||
break;
|
break;
|
||||||
|
@ -38,6 +38,11 @@ export function mem(
|
|||||||
terminal.print(
|
terminal.print(
|
||||||
`This script requires ${numeralWrapper.formatRAM(ramUsage)} of RAM to run for ${numThreads} thread(s)`,
|
`This script requires ${numeralWrapper.formatRAM(ramUsage)} of RAM to run for ${numThreads} thread(s)`,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const verboseEntries = script.ramUsageEntries?.sort((a, b) => b.cost - a.cost) ?? [];
|
||||||
|
for (const entry of verboseEntries) {
|
||||||
|
terminal.print(`${numeralWrapper.formatRAM(entry.cost * numThreads).padStart(8)} | ${entry.name} (${entry.type})`);
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
terminal.error(e + "");
|
terminal.error(e + "");
|
||||||
}
|
}
|
||||||
|
@ -36,11 +36,11 @@ describe("Netscript Static RAM Calculation/Generation Tests", function () {
|
|||||||
|
|
||||||
const code = fnDesc.join(".") + "(); ";
|
const code = fnDesc.join(".") + "(); ";
|
||||||
|
|
||||||
const calculated = await calculateRamUsage(Player, code, []);
|
const calculated = (await calculateRamUsage(Player, code, [])).cost;
|
||||||
testEquality(calculated, expected + ScriptBaseCost);
|
testEquality(calculated, expected + ScriptBaseCost);
|
||||||
|
|
||||||
const multipleCallsCode = code.repeat(3);
|
const multipleCallsCode = code.repeat(3);
|
||||||
const multipleCallsCalculated = await calculateRamUsage(Player, multipleCallsCode, []);
|
const multipleCallsCalculated = (await calculateRamUsage(Player, multipleCallsCode, [])).cost;
|
||||||
expect(multipleCallsCalculated).toEqual(calculated);
|
expect(multipleCallsCalculated).toEqual(calculated);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,11 +60,10 @@ describe("Netscript Static RAM Calculation/Generation Tests", function () {
|
|||||||
expect(expected).toEqual(0);
|
expect(expected).toEqual(0);
|
||||||
|
|
||||||
const code = fnDesc.join(".") + "(); ";
|
const code = fnDesc.join(".") + "(); ";
|
||||||
|
const calculated = (await calculateRamUsage(Player, code, [])).cost;
|
||||||
const calculated = await calculateRamUsage(Player, code, []);
|
|
||||||
testEquality(calculated, ScriptBaseCost);
|
testEquality(calculated, ScriptBaseCost);
|
||||||
|
|
||||||
const multipleCallsCalculated = await calculateRamUsage(Player, code, []);
|
const multipleCallsCalculated = (await calculateRamUsage(Player, code, [])).cost;
|
||||||
expect(multipleCallsCalculated).toEqual(ScriptBaseCost);
|
expect(multipleCallsCalculated).toEqual(ScriptBaseCost);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -511,7 +510,7 @@ describe("Netscript Static RAM Calculation/Generation Tests", function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const calculated = await calculateRamUsage(Player, code, []);
|
const calculated = await calculateRamUsage(Player, code, []);
|
||||||
testEquality(calculated, ScriptBaseCost + HacknetNamespaceCost);
|
testEquality(calculated.cost, ScriptBaseCost + HacknetNamespaceCost);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user