diff --git a/.vscode/launch.json b/.vscode/launch.json
index fa9529bef36..d6d60dc0909 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -37,7 +37,7 @@
"request": "launch",
"mainClass": "org.rascalmpl.shell.RascalShell",
"projectName": "rascal",
- "vmArgs": "-Xss80m -Xmx2g -ea",
+ "vmArgs": "-Xss80m -Xmx2g -Dorg.rascalmpl.profiling.flameGraph.script=C:/Users/sung-/Desktop/FlameGraph-1.0/flamegraph.pl",
"console": "integratedTerminal"
},
{
diff --git a/pom.xml b/pom.xml
index af4336d8e52..7db059969d2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -455,7 +455,8 @@
org.rascalmpl
typepal
- 0.17.0-RC3
+
+ 0.17.0-RC4-SNAPSHOT
compile
diff --git a/src/org/rascalmpl/compiler/Scratch.rsc b/src/org/rascalmpl/compiler/Scratch.rsc
new file mode 100644
index 00000000000..5fe293fd548
--- /dev/null
+++ b/src/org/rascalmpl/compiler/Scratch.rsc
@@ -0,0 +1,137 @@
+module Scratch
+
+import Prelude;
+import lang::rascalcore::check::Checker;
+import lang::rascalcore::check::ModuleLocations;
+import util::FileSystem;
+import util::SystemAPI;
+import util::Benchmark;
+
+import analysis::typepal::Solver;
+
+loc rascalLib() {
+ loc rascalLib = resolveLocation(|std:///|);
+ if (/org.rascalmpl.library.?$/ := rascalLib.path) {
+ rascalLib = rascalLib.parent.parent.parent;
+ }
+ return rascalLib;
+}
+
+loc typepalLib() {
+ return |mvn://org.rascalmpl--typepal--0.17.0-RC4-SNAPSHOT/|;
+}
+
+int typecheckBirdCore(bool force = false) = realTimeOf(void() { typecheck(|home:///Desktop/bird/bird-core|, ["src/main/rascal"], force = force); });
+
+int typecheckRascalLibraryAnalysis(bool force = false) = realTimeOf(void() { typecheck(|home:///Desktop/usethesource2/rascal|, ["src/org/rascalmpl/library"], dir = "analysis", force = force); });
+
+int typecheckTypepal(bool force = false) = realTimeOf(void() { typecheck(|home:///Desktop/usethesource2/typepal|, ["src"], force = force); });
+// 1454032
+// 1207079 - remove check in Result constructor -- UNSOUND
+// 1149042 - add cache for getSimpleVariable
+
+bool typecheck(loc project, list[str] srcs, str dir = "", bool force = false) {
+
+ // Create path config
+
+ println();
+ println("## Create path config");
+ println();
+
+ PathConfig pcfg = pathConfig(
+ srcs = [project + src | str src <- srcs],
+ bin = project + "target/classes",
+ libs = [rascalLib()]
+ );
+
+ iprintln(pcfg);
+ println();
+
+ // Delete `bin`
+
+ if (force) {
+ println("## Delete `bin`");
+ println();
+
+ remove(pcfg.bin);
+
+ iprintln(sort([*find(pcfg.bin, "tpl")]));
+ println();
+ }
+
+ // Typecheck `srcs`
+
+ println("## Typecheck `srcs`");
+ println();
+
+ list[str] moduleNames = [getRascalModuleName(l, pcfg) | loc src <- pcfg.srcs, loc l <- find(src + dir, "rsc")];
+
+ iprintln(sort(moduleNames));
+ println();
+
+ calculatorFailureCount = 0;
+ calculatorFailureNanoTime = 0;
+ requirementFailureCount = 0;
+ requirementFailureNanoTime = 0;
+ ModuleStatus ms = rascalTModelForNames(moduleNames, rascalCompilerConfig(pcfg)[enableErrorFixes = false], dummy_compile1);
+
+ iprintln(sort([*find(pcfg.bin, "tpl")]));
+ println();
+
+ return (true | it && found | str moduleName <- moduleNames, := getTModelForModule(moduleName, ms));
+}
+
+void z1(int n = 10) {
+ set[loc] locs = {};
+ for (int i <- [0..n]) {
+ locs += |unknown:///| + "";
+ // if (i % 1000 == 0) {
+ // println(i);
+ // }
+ }
+}
+
+void z2(int n = 10) {
+ list[int] elems = [];
+ for (int i <- [0..n]) {
+ elems += i;
+ if (i % (10*1000) == 0) {
+ println(i);
+ }
+ }
+}
+
+void z3(int n = 10) {
+ set[value] elems = {};
+ for (int i <- [0..n]) {
+ elems += "";
+ }
+}
+
+/*
+
+6-tuples zijn duur, projectie is mogelijk goedkoper
+
+ - overloaded type zijn triples (bijv. alleen 3e element gebruikt)
+ - over het algemeen kort, sommige 100 overloads
+ - defines zijn 6-tuples
+
+
+Misschien vergelijkbaar met lange ADT constructors
+
+
+komen zowel in Rascal typechecker als in typepal voor
+
+
+
+
+binaire relaties geoptimaliseerd in Vallang. n-ary relaties niet zo erg.
+6-tuple vervangen door 6 binary relaties????
+
+
+
+Aanpak:
+
+ - hoog niveau gaan meten welke delen van de checker de meeste tijd kosten
+
+*/
\ No newline at end of file
diff --git a/src/org/rascalmpl/compiler/lang/rascalcore/check/Import.rsc b/src/org/rascalmpl/compiler/lang/rascalcore/check/Import.rsc
index 6b39268e7ef..6ac0523ccc7 100644
--- a/src/org/rascalmpl/compiler/lang/rascalcore/check/Import.rsc
+++ b/src/org/rascalmpl/compiler/lang/rascalcore/check/Import.rsc
@@ -425,14 +425,6 @@ ModuleStatus doSaveModule(set[MODID] component, map[MODID,set[MODID]] m_imports,
set[MODID] filteredModuleScopes = {};
loc2moduleName = invertUnique(ms.moduleLocs);
- bool isContainedInComponentScopes(loc inner, map[loc,loc] m){
- return any(cs <- component_scopes, isContainedIn(inner, cs, m));
- };
-
- bool isContainedInFilteredModuleScopes(loc inner, map[loc,loc] m){
- return any(cs <- filteredModuleScopes, isContainedIn(inner, cs, m));
- };
-
for(currentModule <- component){
start_save = cpuTime();
tm = transient_tms[currentModule];
@@ -447,15 +439,27 @@ ModuleStatus doSaveModule(set[MODID] component, map[MODID,set[MODID]] m_imports,
extendedModuleScopes += {*tm.paths[ems,importPath()] | MODID ems <- extendedModuleScopes}; // add imports of extended modules
filteredModuleScopes = {m | MODID m <- (currentModule + imports), hasProperty(m, ms, checked())} + extendedModuleScopes;
+ map[str,loc] componentScopesByUri = (s.uri: s | loc s <- component_scopes, loc s := tm.logical2physical[s] ? s);
+ map[str,loc] filteredModuleScopesByUri = (s.uri: s | loc s <- filteredModuleScopes, loc s := tm.logical2physical[s] ? s);
+
+ bool isContainedInComponentScopes(loc key) {
+ key = tm.logical2physical[key] ? key;
+ return key.uri in componentScopesByUri ? isContainedIn(key, componentScopesByUri[key.uri]) : false;
+ }
+ bool isContainedInFilteredModuleScopes(loc key) {
+ key = tm.logical2physical[key] ? key;
+ return key.uri in filteredModuleScopesByUri ? isContainedIn(key, filteredModuleScopesByUri[key.uri]) : false;
+ }
+
TModel m1 = tmodel();
m1.version = getCurrentTplVersion();
m1.rascalTplVersion = compilerConfig.rascalTplVersion;
m1.modelName = moduleId2moduleName(currentModule);
m1.moduleLocs = (m1.modelName : currentModule);
- m1.facts = (key : tm.facts[key] | key <- tm.facts, isContainedInFilteredModuleScopes(key, tm.logical2physical));
+ m1.facts = (key : tm.facts[key] | key <- tm.facts, isContainedInFilteredModuleScopes(key));
- m1.specializedFacts = (key : tm.specializedFacts[key] | key <- tm.specializedFacts, isContainedInComponentScopes(key, tm.logical2physical), any(fms <- filteredModuleScopes, isContainedIn(key, fms)));
+ m1.specializedFacts = (key : tm.specializedFacts[key] | key <- tm.specializedFacts, isContainedInComponentScopes(key), isContainedInFilteredModuleScopes(key));
m1.facts += m1.specializedFacts;
m1.messages = [msg | msg <- tm.messages, isContainedIn(msg.at, currentModule, tm.logical2physical)];
@@ -492,11 +496,11 @@ ModuleStatus doSaveModule(set[MODID] component, map[MODID,set[MODID]] m_imports,
// Filter model for current module and replace functions in defType by their defined type
defs = for(tup: <- tm.defines){
- if( ( idRole in variableRoles ? ( isContainedInComponentScopes(defined, tm.logical2physical)
+ if( ( idRole in variableRoles ? ( isContainedInComponentScopes(defined)
)
: ( idRole in keepInTModelRoles
- && ( isContainedInComponentScopes(defined, tm.logical2physical)
- || isContainedInFilteredModuleScopes(defined, tm.logical2physical)
+ && ( isContainedInComponentScopes(defined)
+ || isContainedInFilteredModuleScopes(defined)
)
)
)
diff --git a/src/org/rascalmpl/interpreter/IEvaluator.java b/src/org/rascalmpl/interpreter/IEvaluator.java
index 529ff5b66ef..20219c6fdba 100644
--- a/src/org/rascalmpl/interpreter/IEvaluator.java
+++ b/src/org/rascalmpl/interpreter/IEvaluator.java
@@ -53,6 +53,7 @@
* Interface needs to be properly split up in different compoments.
*/
public interface IEvaluator extends IEvaluatorContext {
+ public static final boolean UNSAFE_MODE = true;
public static final String LOADING_JOB_CONSTANT = "loading modules";
/**
diff --git a/src/org/rascalmpl/interpreter/env/ModuleEnvironment.java b/src/org/rascalmpl/interpreter/env/ModuleEnvironment.java
index 1cbca8745ae..3c61a028175 100644
--- a/src/org/rascalmpl/interpreter/env/ModuleEnvironment.java
+++ b/src/org/rascalmpl/interpreter/env/ModuleEnvironment.java
@@ -133,6 +133,7 @@ public void clearLookupCaches() {
importedModules.replaceAll((k, v) -> Optional.empty());
cachedGeneralKeywordParameters = null;
cachedPublicFunctions = null;
+ cachedImportedModulesResolved = null;
}
/**
@@ -382,12 +383,14 @@ public void addImport(String name, ModuleEnvironment env) {
typeStore.importStore(env.typeStore);
this.cachedGeneralKeywordParameters = null;
this.cachedPublicFunctions = null;
+ this.cachedImportedModulesResolved = null;
}
void removeModule(String name) {
importedModules.computeIfPresent(name, (k, v) -> Optional.empty());
this.cachedGeneralKeywordParameters = null;
this.cachedPublicFunctions = null;
+ this.cachedImportedModulesResolved = null;
}
public void addExtend(String name) {
@@ -397,6 +400,7 @@ public void addExtend(String name) {
extended.add(name);
this.cachedGeneralKeywordParameters = null;
this.cachedPublicFunctions = null;
+ this.cachedImportedModulesResolved = null;
}
public List getTests() {
@@ -453,6 +457,7 @@ public void unImport(String moduleName) {
}
cachedGeneralKeywordParameters = null;
cachedPublicFunctions = null;
+ cachedImportedModulesResolved = null;
}
public void unExtend(String moduleName) {
@@ -884,24 +889,44 @@ public ModuleEnvironment getImport(String moduleName) {
return result.get();
}
+ private List cachedImportedModulesResolved = null;
+
private Iterable importedModulesResolved =
- () -> new Iterator() {
- Iterator>> iterator = importedModules.entrySet().iterator();
- @Override
- public boolean hasNext() {
- return iterator.hasNext();
- }
- @Override
- public ModuleEnvironment next() {
- var entry = iterator.next();
+ () -> getCachedImportedModulesResolved().iterator();
+ // () -> new Iterator() {
+ // Iterator>> iterator = importedModules.entrySet().iterator();
+ // @Override
+ // public boolean hasNext() {
+ // return iterator.hasNext();
+ // }
+ // @Override
+ // public ModuleEnvironment next() {
+ // var entry = iterator.next();
+ // var result = entry.getValue();
+ // if (result.isEmpty()) {
+ // result = Optional.ofNullable(heap.getModule(entry.getKey()));
+ // entry.setValue(result);
+ // }
+ // return result.orElse(null);
+ // }
+ // };
+
+ private List getCachedImportedModulesResolved() {
+ if (cachedImportedModulesResolved == null) {
+ cachedImportedModulesResolved = new ArrayList<>();
+ for (Entry> entry : importedModules.entrySet()) {
var result = entry.getValue();
if (result.isEmpty()) {
result = Optional.ofNullable(heap.getModule(entry.getKey()));
entry.setValue(result);
}
- return result.orElse(null);
+ if (result.isPresent()) {
+ cachedImportedModulesResolved.add(result.get());
+ }
}
- };
+ }
+ return cachedImportedModulesResolved;
+ }
@Override
public void storeVariable(QualifiedName name, Result result) {
diff --git a/src/org/rascalmpl/interpreter/result/Result.java b/src/org/rascalmpl/interpreter/result/Result.java
index a6847f9ecb8..b8c15d30f60 100644
--- a/src/org/rascalmpl/interpreter/result/Result.java
+++ b/src/org/rascalmpl/interpreter/result/Result.java
@@ -27,6 +27,7 @@
import org.rascalmpl.ast.Field;
import org.rascalmpl.ast.Name;
import org.rascalmpl.exceptions.ImplementationError;
+import org.rascalmpl.interpreter.IEvaluator;
import org.rascalmpl.interpreter.IEvaluatorContext;
import org.rascalmpl.interpreter.control_exceptions.MatchFailed;
import org.rascalmpl.interpreter.env.Environment;
@@ -86,7 +87,7 @@ public abstract class Result implements Iterator> iter, IEvaluatorContext ctx) {
// Check for null in case of void result or uninit.
- if (value != null && !value.getType().isSubtypeOf(type)) {
+ if (!IEvaluator.UNSAFE_MODE && value != null && !value.getType().isSubtypeOf(type)) {
throw new UnexpectedType(type, value.getType(), ctx.getCurrentAST());
}
diff --git a/src/org/rascalmpl/interpreter/utils/Profiler.java b/src/org/rascalmpl/interpreter/utils/Profiler.java
index f7671310dfe..15badd74cf7 100644
--- a/src/org/rascalmpl/interpreter/utils/Profiler.java
+++ b/src/org/rascalmpl/interpreter/utils/Profiler.java
@@ -13,22 +13,29 @@
*******************************************************************************/
package org.rascalmpl.interpreter.utils;
+import java.io.IOException;
import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Vector;
+import java.util.stream.Collectors;
import org.rascalmpl.ast.AbstractAST;
+import org.rascalmpl.debug.IRascalFrame;
import org.rascalmpl.interpreter.Evaluator;
import org.rascalmpl.interpreter.env.Environment;
+import org.rascalmpl.values.ValueFactoryFactory;
+
import io.usethesource.vallang.IList;
import io.usethesource.vallang.IListWriter;
import io.usethesource.vallang.ISourceLocation;
import io.usethesource.vallang.IValueFactory;
-import org.rascalmpl.values.ValueFactoryFactory;
class Count {
int ticks;
@@ -72,6 +79,64 @@ public boolean equals(Object obj) {
}
}
+class FlameGraph {
+ private final Map counts = new HashMap<>();
+
+ void sample(Evaluator eval) {
+ var frames = eval.getCallStack().stream();
+ var folded = frames.map(FlameGraph::getFrameTitle).collect(Collectors.joining(";"));
+ var count = counts.computeIfAbsent(folded, k -> new Count());
+ count.increment();
+ }
+
+ private static String getFrameTitle(IRascalFrame frame) {
+ var title = frame.getName();
+ var callerLocation = frame.getCallerLocation();
+ if (callerLocation != null) {
+ title += " at " + callerLocation;
+ }
+ return title;
+ }
+
+ void write() {
+ var name = "flameGraph";
+ var out = Path.of(name + ".out");
+ var err = Path.of(name + ".err");
+ var svg = Path.of(name + ".svg");
+
+ try {
+ Files.writeString(out, "");
+ for (var e : counts.entrySet()) {
+ // Newlines must be `\n` for `flamegraph.pl` to work
+ var csq = String.format("%s %d\n", e.getKey(), e.getValue().getTicks());
+ Files.writeString(out, csq, StandardOpenOption.APPEND);
+ }
+
+ var scriptKey = "org.rascalmpl.profiling.flameGraph.script";
+ var scriptValue = System.getProperty(scriptKey);
+ if (scriptValue != null) {
+ var script = Path.of(scriptValue);
+ if (Files.exists(script)) {
+
+ ProcessBuilder processBuilder = new ProcessBuilder("perl", script.toString(), out.toString());
+ processBuilder.redirectOutput(svg.toFile());
+ processBuilder.redirectError(err.toFile());
+
+ Process process = processBuilder.start();
+ try {
+ process.waitFor();
+ } catch (InterruptedException e) {
+ // Ignore; doesn't matter
+ }
+ }
+ }
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
+
public class Profiler extends Thread {
private Evaluator eval;
private volatile boolean running;
@@ -79,6 +144,7 @@ public class Profiler extends Thread {
private final Map ast;
private final Map frame;
private final Map names;
+ private final FlameGraph flameGraph = new FlameGraph();
public Profiler(Evaluator ev){
super("Rascal-Sampling-Profiler");
@@ -95,6 +161,8 @@ public void run(){
AbstractAST current = eval.getCurrentAST();
Environment env = eval.getCurrentEnvt();
String name = env.getName();
+
+ flameGraph.sample(eval);
if (current != null) {
ISourceLocation stat = current.getLocation();
@@ -162,6 +230,7 @@ public void report() {
report("FRAMES", frame);
eval.getOutPrinter().println();
report("ASTS", ast);
+ flameGraph.write();
}
private void report(String title, Map data) {