"use strict"; /* * Copyright (C) 2025 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ const defaultEmptyMap = Object.freeze({}); class Params { // Enable a detailed developer menu to change the current Params. developerMode = false; startAutomatically = false; report = false; startDelay = undefined; testList = []; testIterationCount = undefined; testWorstCaseCount = undefined; prefetchResources = true; // Display group details. groupDetails = false RAMification = false; dumpJSONResults = false; dumpTestList = false; // Override iteration and worst-case counts per workload. // Example: // testIterationCountMap = { "acorn-wtb": 5 }; testIterationCountMap = defaultEmptyMap; testWorstCaseCountMap = defaultEmptyMap; customPreIterationCode = undefined; customPostIterationCode = undefined; constructor(sourceParams = undefined) { if (sourceParams) this._copyFromSearchParams(sourceParams); if (!this.developerMode) Object.freeze(this); } _copyFromSearchParams(sourceParams) { this.startAutomatically = this._parseBooleanParam(sourceParams, "startAutomatically"); this.developerMode = this._parseBooleanParam(sourceParams, "developerMode"); this.report = this._parseBooleanParam(sourceParams, "report"); this.prefetchResources = this._parseBooleanParam(sourceParams, "prefetchResources"); this.RAMification = this._parseBooleanParam(sourceParams, "RAMification"); this.dumpJSONResults = this._parseBooleanParam(sourceParams, "dumpJSONResults"); this.groupDetails = this._parseBooleanParam(sourceParams, "groupDetails"); this.dumpTestList = this._parseBooleanParam(sourceParams, "dumpTestList"); this.customPreIterationCode = this._parseStringParam(sourceParams, "customPreIterationCode"); this.customPostIterationCode = this._parseStringParam(sourceParams, "customPostIterationCode"); this.startDelay = this._parseIntParam(sourceParams, "startDelay", 0); if (!this.startDelay) { if (this.report) this.startDelay = 4000; if (this.startAutomatically) this.startDelay = 100; } this.testList = this._parseOneOf(sourceParams, ["testList", "tag", "tags", "test", "tests"], this._parseTestListParam); this.testIterationCount = this._parseOneOf(sourceParams, ["testIterationCount", "iterationCount", "iterations" ], this._parseIntParam, 1); this.testWorstCaseCount = this._parseOneOf(sourceParams, ["testWorstCaseCount", "worstCaseCount", "worst"], this._parseIntParam, 1); const unused = Array.from(sourceParams.keys()); if (unused.length > 0) console.error("Got unused source params", unused); } _parseOneOf(sourceParams, paramKeys, parseFunction, ...args) { const defaultParamKey = paramKeys[0] let result = undefined; let parsedParamKey = undefined; for (const paramKey of paramKeys) { if (!sourceParams.has(paramKey)) { continue; } const parseResult = parseFunction.call(this, sourceParams, paramKey, ...args); if (parsedParamKey) { throw new Error(`Cannot parse ${paramKey}, overriding previous "${parsedParamKey}" value ${JSON.stringify(result)} with ${JSON.stringify(parseResult)}`) } parsedParamKey = paramKey; result = parseResult; } if (!parsedParamKey) { return DefaultJetStreamParams[defaultParamKey]; } return result; } _parseTestListParam(sourceParams, key) { if (!sourceParams.has(key)) return this.testList; let testList = []; if (sourceParams?.getAll) { for (const param of sourceParams?.getAll(key)) { testList.push(...param.split(",")); } } else { // fallback for cli sourceParams which is just a Map; testList = sourceParams.get(key).split(","); } testList = testList.map(each => each.trim()); sourceParams.delete(key); return testList; } _parseStringParam(sourceParams, paramKey) { if (!sourceParams.has(paramKey)) return DefaultJetStreamParams[paramKey]; const value = sourceParams.get(paramKey); sourceParams.delete(paramKey); return value; } _parseBooleanParam(sourceParams, paramKey) { if (!sourceParams.has(paramKey)) return DefaultJetStreamParams[paramKey]; const rawValue = sourceParams.get(paramKey);; sourceParams.delete(paramKey); const value = rawValue.toLowerCase(); return !(value === "false" || value === "0"); } _parseIntParam(sourceParams, paramKey, minValue) { if (!sourceParams.has(paramKey)) return DefaultJetStreamParams[paramKey]; const parsedValue = this._parseInt(sourceParams.get(paramKey), paramKey); if (parsedValue < minValue) throw new Error(`Invalid ${paramKey} param: '${parsedValue}', value must be >= ${minValue}.`); sourceParams.delete(paramKey); return parsedValue; } _parseInt(value, errorMessage) { const number = Number(value); if (!Number.isInteger(number) && errorMessage) throw new Error(`Invalid ${errorMessage} param: '${value}', expected int.`); return parseInt(number); } get isDefault() { return this === DefaultJetStreamParams; } get nonDefaultParams() { const diff = Object.create(null); for (const [key, value] of Object.entries(this)) { const defaultValue = DefaultJetStreamParams[key] if (value == defaultValue) continue; if (value?.length == 0 && defaultValue?.length == 0) continue; diff[key] = value; } return diff; } } const DefaultJetStreamParams = new Params(); let maybeCustomParams = DefaultJetStreamParams; if (globalThis?.JetStreamParamsSource) { try { maybeCustomParams = new Params(globalThis?.JetStreamParamsSource); // We might have parsed the same values again, do a poor-mans deep-equals: if (JSON.stringify(maybeCustomParams) === JSON.stringify(DefaultJetStreamParams)) { maybeCustomParams = DefaultJetStreamParams } } catch (e) { console.error("Invalid Params", e, "\nUsing defaults as fallback:", maybeCustomParams); } } const JetStreamParams = maybeCustomParams;