From b221486b6c41c604be44d5da0005a5a982b6add1 Mon Sep 17 00:00:00 2001 From: Sung-Shik Jongmans Date: Wed, 29 Jul 2026 10:27:20 +0200 Subject: [PATCH 1/2] Prepare separate main branch for performance improvements --- .github/workflows/build.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 291fb64..089e89b 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -9,6 +9,7 @@ on: pull_request: branches: - main + - performance-improvements-main env: MAVEN_OPTS: "-Xmx6G -Dhttps.protocols=TLSv1.2 -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN -Dorg.slf4j.simpleLogger.showDateTime=true -Djava.awt.headless=true" From 97568cb1793e9efe3bad0b50c254b24e9db30d03 Mon Sep 17 00:00:00 2001 From: Sung-Shik Jongmans Date: Mon, 10 Aug 2026 17:22:49 +0200 Subject: [PATCH 2/2] Add `newDefInfo` function to make creation of `defInfo` values faster (using an auxiliary map of "prototypes") --- src/analysis/typepal/Solver.rsc | 38 ++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/src/analysis/typepal/Solver.rsc b/src/analysis/typepal/Solver.rsc index 2a118e9..a4f7e7e 100644 --- a/src/analysis/typepal/Solver.rsc +++ b/src/analysis/typepal/Solver.rsc @@ -1645,14 +1645,29 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ /****************** end of main solve loop *****************************/ + // Creating new `defType` values using the `defType` constructor takes + // significant interpreter time. To make it faster, the following map + // stores "prototypes" from which new `defType` values can be created. + map[AType, DefInfo] defInfoPrototypes = (); + + DefInfo newDefInfo(AType t, map[str, value] keywordParameters) { + DefInfo proto; + if (t in defInfoPrototypes) { + proto = defInfoPrototypes[t]; + } else { + proto = defType(t); + defInfoPrototypes[t] = proto; + } + return setKeywordParameters(proto, keywordParameters); // Create new value (i.e., leave `proto` unchanged) + } + // Eliminate all defTypeCalls before handing control to the postSolver for(loc l <- definitions){ Define def = definitions[l]; if(defTypeCall(_, AType(Solver s) getAType) := def.defInfo){ kwparams = getKeywordParameters(def.defInfo); try { - di = defType(getAType(thisSolver)); - def.defInfo = setKeywordParameters(di, kwparams); + def.defInfo = newDefInfo(getAType(thisSolver), kwparams); definitions[l] = def; } catch _: { // Guard against type incorrect defines, but record for now ; //println("Skipping (type-incorrect) def: \n"); @@ -1663,11 +1678,16 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ newDefines = for(def <- defines){ + // All `defTypeCall` values have already been eliminated from + // `definitions`, so this is a fast(er) way out. + if (def.defined in definitions) { + append definitions[def.defined]; + continue; + } if(defTypeCall(_, AType(Solver s) getAType) := def.defInfo){ kwparams = getKeywordParameters(def.defInfo); try { - di = defType(getAType(thisSolver)); - def.defInfo = setKeywordParameters(di, kwparams); + def.defInfo = newDefInfo(getAType(thisSolver), kwparams); } catch _: { // Guard against type incorrect defines, but record for now ; //println("Skipping (type-incorrect) def: \n"); } @@ -1805,16 +1825,14 @@ Solver newSolver(map[str,Tree] namedTrees, TModel tm){ ldefines = for(tup: <- tm.defines){ if(defInfo has tree){ l = getLogicalLoc(defInfo.tree); - if(l in tm.facts){ - dt = defType(tm.facts[l]); - tup.defInfo = setKeywordParameters(dt, getKeywordParameters(defInfo)); + if(l in facts){ + tup.defInfo = newDefInfo(facts[l], getKeywordParameters(defInfo)); } else { continue; } } else { - if(defined in tm.facts){ - dt = defType(tm.facts[defined]); - tup.defInfo = setKeywordParameters(dt, getKeywordParameters(defInfo)); + if(defined in facts){ + tup.defInfo = newDefInfo(facts[defined], getKeywordParameters(defInfo)); } else { continue; }