From 63bb6d595c37b3a2fb55e07fb810779cae3b4d03 Mon Sep 17 00:00:00 2001 From: Antti Villberg Date: Wed, 8 Jan 2020 17:12:00 +0200 Subject: [PATCH] Simupedia tuning Change-Id: Ic18f95c59eb4c3d02e211f181bed57b68b152045 --- .../src/org/simantics/acorn/MainProgram.java | 6 +- .../org/simantics/acorn/OperationQueue.java | 23 +- .../db/impl/graph/ReadGraphImpl.java | 18 +- .../db/impl/query/QueryListening.java | 819 ++++++++++-------- .../db/impl/query/QueryProcessor.java | 6 +- bundles/org.simantics.db.layer0/adapters.xml | 3 +- .../db/layer0/request/PropertyInfo.java | 92 ++ .../layer0/util/SessionGarbageCollection.java | 8 +- .../variable/StandardVariableBuilder.java | 11 + .../server/request/DocumentRequest.java | 56 +- .../document/server/request/NodeRequest.java | 14 +- .../document/server/request/NodesRequest.java | 81 +- .../server/request/NodesRequest2.java | 99 ++- .../scl/compiler/module/ConcreteModule.java | 5 + .../scl/compiler/runtime/RuntimeModule.java | 134 ++- .../scl/compiler/top/ExpressionEvaluator.java | 2 +- .../src/org/simantics/scl/osgi/SCLOsgi.java | 56 +- .../threads/logger/ThreadLogVisualizer.java | 2 +- .../utils/threads/logger/ThreadLogger.java | 2 +- 19 files changed, 957 insertions(+), 480 deletions(-) diff --git a/bundles/org.simantics.acorn/src/org/simantics/acorn/MainProgram.java b/bundles/org.simantics.acorn/src/org/simantics/acorn/MainProgram.java index ec4d56c21..1e4b5cbac 100644 --- a/bundles/org.simantics.acorn/src/org/simantics/acorn/MainProgram.java +++ b/bundles/org.simantics.acorn/src/org/simantics/acorn/MainProgram.java @@ -102,17 +102,15 @@ public class MainProgram implements Runnable, Closeable { if(updates.isEmpty()) { - long start = System.nanoTime(); - - operationQueue.waitFor(); + long duration = operationQueue.waitFor(); if (!alive) break main; - long duration = System.nanoTime()-start; if(duration > 4000000000L) { checkIdle(); } + } // long sss = System.nanoTime(); diff --git a/bundles/org.simantics.acorn/src/org/simantics/acorn/OperationQueue.java b/bundles/org.simantics.acorn/src/org/simantics/acorn/OperationQueue.java index 7a9d8aba2..48b891f0e 100644 --- a/bundles/org.simantics.acorn/src/org/simantics/acorn/OperationQueue.java +++ b/bundles/org.simantics.acorn/src/org/simantics/acorn/OperationQueue.java @@ -157,18 +157,23 @@ class OperationQueue { * Wake up when new operations are scheduled or the last operation is committed * Called by MainProgram thread */ - synchronized void waitFor() { + synchronized long waitFor() { - mainProgram.assertMainProgramThread(); + mainProgram.assertMainProgramThread(); - // One last check within the monitor - if(!operations.isEmpty() || !tasks.isEmpty()) return; + // One last check within the monitor + if(!operations.isEmpty() || !tasks.isEmpty()) return 0; - try { - wait(5000); - } catch (InterruptedException e) { - LOGGER.error("Unexpected interruption", e); - } + long start = System.nanoTime(); + System.err.println("start =" + start); + + try { + wait(5000); + } catch (InterruptedException e) { + LOGGER.error("Unexpected interruption", e); + } + + return System.nanoTime() - start; } diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/ReadGraphImpl.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/ReadGraphImpl.java index 2e5411d39..ba39c57df 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/ReadGraphImpl.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/ReadGraphImpl.java @@ -1926,9 +1926,9 @@ public class ReadGraphImpl implements AsyncReadGraph { public T syncRequest(final Read request) throws DatabaseException { assert (request != null); - ITask task = ThreadLogger.task(request); + //ITask task = ThreadLogger.task(request); T result = (T)QueryCache.runnerReadEntry(this, request, parent, null, null, true); - task.finish(); + //task.finish(); return result; } @@ -1950,10 +1950,10 @@ public class ReadGraphImpl implements AsyncReadGraph { assert (request != null); - ITask task = ThreadLogger.task(request); + //ITask task = ThreadLogger.task(request); ListenerBase listener = procedure != null ? getListenerBase(procedure) : null; T result = QueryCache.resultReadEntry(this, request, parent, listener, procedure); - task.finish(); + //task.finish(); return result; } @@ -2038,10 +2038,10 @@ public class ReadGraphImpl implements AsyncReadGraph { assert (request != null); - ITask task = ThreadLogger.task(request); + //ITask task = ThreadLogger.task(request); ListenerBase listener = getListenerBase(procedure); T result = (T)QueryCache.runnerAsyncReadEntry(this, request, parent, listener, procedure, true); - task.finish(); + //task.finish(); return result; } @@ -5248,7 +5248,7 @@ public class ReadGraphImpl implements AsyncReadGraph { assert (request != null); assert (procedure != null); - ITask task = ThreadLogger.task(request); + //ITask task = ThreadLogger.task(request); AsyncBarrierImpl barrier = asyncBarrier; if(barrier != null) @@ -5268,7 +5268,7 @@ public class ReadGraphImpl implements AsyncReadGraph { @Override public void execute(AsyncReadGraph graph, T result) { - task.finish(); + //task.finish(); procedure.execute(graph, result); if(barrier != null) barrier.dec(); @@ -5276,7 +5276,7 @@ public class ReadGraphImpl implements AsyncReadGraph { @Override public void exception(AsyncReadGraph graph, Throwable throwable) { - task.finish(); + //task.finish(); procedure.exception(graph, throwable); if(barrier != null) barrier.dec(); diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryListening.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryListening.java index 9daab950e..b873bfd73 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryListening.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryListening.java @@ -14,9 +14,10 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; import java.util.concurrent.Semaphore; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; import org.simantics.databoard.Bindings; import org.simantics.db.DevelopmentKeys; @@ -37,372 +38,462 @@ public class QueryListening { private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(QueryListening.class); - final private QueryProcessor processor; - private THashSet scheduledListeners = new THashSet(); - private boolean firingListeners = false; - final THashMap> listeners = new THashMap>(10, 0.75f); - private BlockingQueue tasks = new ArrayBlockingQueue(2048); - private Map addedEntries = new HashMap<>(); - - QueryListening(QueryProcessor processor) { - this.processor = processor; - new DependencyManagementThread(processor, tasks).start(); - } - - public void sync() { - Semaphore s = new Semaphore(0); - try { - tasks.put(() -> { - s.release(); - }); - s.acquire(); - } catch (Throwable t) { - LOGGER.error("Error while waiting for query dependency management", t); - } - } - - static class DependencyManagementThread extends Thread { - - final private QueryProcessor processor; - final BlockingQueue tasks; - - DependencyManagementThread(QueryProcessor processor, BlockingQueue tasks) { - setName("Query Dependency Manager"); - this.processor = processor; - this.tasks = tasks; - } - - @Override - public void run() { - while(processor.isAlive()) { - try { - Runnable r = tasks.take(); - r.run(); - } catch (Throwable t) { - // Spurious problems? - LOGGER.error("Error while waiting for query dependency management tasks", t); - } - } - } - - } - - public boolean hasScheduledUpdates() { - return !scheduledListeners.isEmpty(); - } - - void registerDependencies(ReadGraphImpl graph, CacheEntry child, CacheEntry parent, ListenerBase listener, Object procedure, boolean inferred) { - - try { - tasks.put(() -> { - - if (parent != null && !inferred) { - try { - if(!child.isImmutable(graph)) - child.addParent(parent); - } catch (DatabaseException e) { - LOGGER.error("Error while registering query dependencies", e); - } - if (Development.DEVELOPMENT) { - if(Development.getProperty(DevelopmentKeys.QUERYPROCESSOR_DEPENDENCIES, Bindings.BOOLEAN)) { - System.out.println(child + " -> " + parent); - } - } - } - - if (listener != null) - registerListener(child, listener, procedure); - - }); - } catch (InterruptedException e) { - LOGGER.error("Error while registering dependencies", e); - } - - } - - void registerFirstKnown(ListenerBase base, Object result) { - - tasks.offer(() -> { - - ListenerEntry entry = addedEntries.get(base); - if(entry != null) entry.setLastKnown(result); - - }); - - } - - public ListenerEntry registerListener(final CacheEntry entry, final ListenerBase base, final Object procedure) { - - assert (entry != null); - - if (base.isDisposed()) - return null; - - return addListener(entry, base, procedure); - - } - - /* - * Registers a listener and returns an entry iff the entry was added - */ - private ListenerEntry addListener(CacheEntry entry, ListenerBase base, Object procedure) { - - assert (entry != null); - assert (procedure != null); - - ArrayList list = listeners.get(entry); - if (list == null) { - list = new ArrayList<>(1); - listeners.put(entry, list); - } - - ListenerEntry result = new ListenerEntry(entry, base, procedure); - // Equals is here based on base - int currentIndex = list.indexOf(result); - // There was already a listener - if(currentIndex > -1) { - ListenerEntry current = list.get(currentIndex); - if(!current.base.isDisposed()) return null; - list.set(currentIndex, result); - } else { - list.add(result); - } - - if (Development.DEVELOPMENT) { - if(Development.getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) { - new Exception().printStackTrace(); - System.err.println("addListener -> " + list.size() + " " + entry + " " + base + " " + procedure); - } - } - - addedEntries.put(base, result); - - return result; - - } - - void scheduleListener(ListenerEntry entry) { - assert (entry != null); - if (Development.DEVELOPMENT) { - if(Development.getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) { - System.err.println("Scheduled " + entry.procedure); - } - } - scheduledListeners.add(entry); - } - - private void removeListener(ListenerEntry entry) { - assert (entry != null); - ArrayList list = listeners.get(entry.entry); - if(list == null) return; - boolean success = list.remove(entry); - assert (success); - if (list.isEmpty()) - listeners.remove(entry.entry); - } - - boolean hasListener(CacheEntry entry) { - if(listeners.get(entry) != null) return true; - return false; - } - - boolean hasListenerAfterDisposing(CacheEntry entry) { - if(listeners.get(entry) != null) { - ArrayList entries = listeners.get(entry); - ArrayList list = null; - for (ListenerEntry e : entries) { - if (e.base.isDisposed()) { - if(list == null) list = new ArrayList(); - list.add(e); - } - } - if(list != null) { - for (ListenerEntry e : list) { - entries.remove(e); - } - } - if (entries.isEmpty()) { - listeners.remove(entry); - return false; - } - return true; - } - return false; - } - - List getListenerEntries(CacheEntry entry) { - hasListenerAfterDisposing(entry); - if(listeners.get(entry) != null) - return listeners.get(entry); - else - return Collections.emptyList(); - } - - void processListenerReport(CacheEntry entry, Map> workarea) { - - if(!workarea.containsKey(entry)) { - - HashSet ls = new HashSet(); - for(ListenerEntry e : getListenerEntries(entry)) - ls.add(e.base); - - workarea.put(entry, ls); - - for(CacheEntry parent : entry.getParents(processor)) { - processListenerReport(parent, workarea); - ls.addAll(workarea.get(parent)); - } - - } - - } - - public synchronized ListenerReport getListenerReport() throws IOException { - - class ListenerReportImpl implements ListenerReport { - - Map> workarea = new HashMap>(); - - @Override - public void print(PrintStream b) { - Map hist = new HashMap(); - for(Map.Entry> e : workarea.entrySet()) { - for(ListenerBase l : e.getValue()) { - Integer i = hist.get(l); - hist.put(l, i != null ? i-1 : -1); - } - } - - for(Pair p : CollectionUtils.valueSortedEntries(hist)) { - b.print("" + -p.second + " " + p.first + "\n"); - } - - b.flush(); - } - - } - - ListenerReportImpl result = new ListenerReportImpl(); - - Collection all = processor.allCaches(new CacheCollectionResult()).toCollection(); - for(CacheEntryBase entry : all) { - hasListenerAfterDisposing(entry); - } - for(CacheEntryBase entry : all) { - processListenerReport(entry, result.workarea); - } - - return result; - - } - - public synchronized String reportListeners(File file) throws IOException { - - if (!processor.isAlive()) - return "Disposed!"; - - PrintStream b = new PrintStream(new BufferedOutputStream(new FileOutputStream(file))); - ListenerReport report = getListenerReport(); - report.print(b); - - return "Done reporting listeners."; - - } - - public void fireListeners(WriteGraphImpl graph) { - - assert (!processor.updating); - assert (!processor.cache.collecting); - assert (!firingListeners); - - firingListeners = true; - - try { - - // Performing may cause further events to be scheduled. - while (!scheduledListeners.isEmpty()) { - - // Clone current events to make new entries possible during - // firing. - THashSet entries = scheduledListeners; - scheduledListeners = new THashSet(); + final private QueryProcessor processor; + private THashSet scheduledListeners = new THashSet(); + private boolean firingListeners = false; + final THashMap> listeners = new THashMap>(10, 0.75f); + private EventBusImpl eventBus; + private Consumer consumer; + private Map addedEntries = new HashMap<>(); + + int execCount=0; + int queueCount = 0; + + static class TL extends ThreadLocal> { + + Map> allQueues = new HashMap<>(); + ArrayList> dispatchedQueues = new ArrayList<>(); + + @Override + protected synchronized ArrayList initialValue() { + ArrayList result = new ArrayList<>(); + allQueues.put(Thread.currentThread(), result); + return result; + } + + synchronized void sendToExecution() { + ArrayList rs = allQueues.remove(Thread.currentThread()); + dispatchedQueues.add(rs); + notify(); + } + + synchronized ArrayList> getDispatchedQueues() { + ArrayList> result = dispatchedQueues; + dispatchedQueues = new ArrayList<>(); + return result; + } + + } + + static class EventBusImpl { + + private static final int BUFFER_SIZE = 100; + + TL queues = new TL(); + Semaphore flush = null; + + public boolean isTerminated() { + return false; + } + + public Consumer newConsumer() { + return new Consumer() { + + @Override + public void accept(Runnable arg0) { + ArrayList l = queues.get(); + l.add(arg0); + if(l.size() == BUFFER_SIZE) { + queues.remove(); + queues.sendToExecution(); + } + } + }; + } + + public void shutdown() { + } + + public void start(ThreadFactory arg1) { + arg1.newThread(new Runnable() { + + @Override + public void run() { + synchronized(queues) { + while(!isTerminated()) { + try { + ArrayList> qs = queues.getDispatchedQueues(); + for(ArrayList queue : qs) { + for(Runnable r : queue) + r.run(); + } + if(flush != null) { + for(ArrayList queue : queues.allQueues.values()) { + for(Runnable r : queue) { + r.run(); + } + queue.clear(); + } + Semaphore s = flush; + flush = null; + s.release(); + } + queues.wait(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + + }).start(); + } + + void flush() { + synchronized(queues) { + flush = new Semaphore(0); + queues.notify(); + } + try { + flush.acquire(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + } + + QueryListening(QueryProcessor processor) { + this.processor = processor; + eventBus = new EventBusImpl(); + consumer = eventBus.newConsumer(); + eventBus.start(new ThreadFactory() + { + @Override + public Thread newThread(Runnable r) { + System.err.println("new Thread " + r); + return new Thread(r, "QueryDependencyManager"); + } + }); + } + + public void sync() { + try { + eventBus.flush(); + } catch (Throwable t) { + LOGGER.error("Error while waiting for query dependency management", t); + } + } + + public boolean hasScheduledUpdates() { + return !scheduledListeners.isEmpty(); + } + + public synchronized void dispatch(Runnable r) { + queueCount++; + consumer.accept(r); + } + + void registerDependencies(ReadGraphImpl graph, CacheEntry child, CacheEntry parent, ListenerBase listener, Object procedure, boolean inferred) { + + dispatch(() -> { + + if (parent != null && !inferred) { + try { + if(!child.isImmutable(graph)) + child.addParent(parent); + } catch (DatabaseException e) { + LOGGER.error("Error while registering query dependencies", e); + } + if (Development.DEVELOPMENT) { + if(Development.getProperty(DevelopmentKeys.QUERYPROCESSOR_DEPENDENCIES, Bindings.BOOLEAN)) { + System.out.println(child + " -> " + parent); + } + } + } + + if (listener != null) + registerListener(child, listener, procedure); + + }); + + } + + void registerFirstKnown(ListenerBase base, Object result) { + + if(base == null) return; + + dispatch(() -> { + + ListenerEntry entry = addedEntries.get(base); + if(entry != null) entry.setLastKnown(result); + + }); + + } + + public ListenerEntry registerListener(final CacheEntry entry, final ListenerBase base, final Object procedure) { + + assert (entry != null); + + if (base.isDisposed()) + return null; + + return addListener(entry, base, procedure); + + } + + /* + * Registers a listener and returns an entry iff the entry was added + */ + private ListenerEntry addListener(CacheEntry entry, ListenerBase base, Object procedure) { + + assert (entry != null); + assert (procedure != null); + + ArrayList list = listeners.get(entry); + if (list == null) { + list = new ArrayList<>(1); + listeners.put(entry, list); + } + + ListenerEntry result = new ListenerEntry(entry, base, procedure); + // Equals is here based on base + int currentIndex = list.indexOf(result); + // There was already a listener + if(currentIndex > -1) { + ListenerEntry current = list.get(currentIndex); + if(!current.base.isDisposed()) return null; + list.set(currentIndex, result); + } else { + list.add(result); + } + + if (Development.DEVELOPMENT) { + if(Development.getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) { + new Exception().printStackTrace(); + System.err.println("addListener -> " + list.size() + " " + entry + " " + base + " " + procedure); + } + } + + addedEntries.put(base, result); + + return result; + + } + + void scheduleListener(ListenerEntry entry) { + assert (entry != null); + if (Development.DEVELOPMENT) { + if(Development.getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) { + System.err.println("Scheduled " + entry.procedure); + } + } + scheduledListeners.add(entry); + } + + private void removeListener(ListenerEntry entry) { + assert (entry != null); + ArrayList list = listeners.get(entry.entry); + if(list == null) return; + boolean success = list.remove(entry); + assert (success); + if (list.isEmpty()) + listeners.remove(entry.entry); + } + + boolean hasListener(CacheEntry entry) { + if(listeners.get(entry) != null) return true; + return false; + } + + boolean hasListenerAfterDisposing(CacheEntry entry) { + if(listeners.get(entry) != null) { + ArrayList entries = listeners.get(entry); + ArrayList list = null; + for (ListenerEntry e : entries) { + if (e.base.isDisposed()) { + if(list == null) list = new ArrayList(); + list.add(e); + } + } + if(list != null) { + for (ListenerEntry e : list) { + entries.remove(e); + } + } + if (entries.isEmpty()) { + listeners.remove(entry); + return false; + } + return true; + } + return false; + } + + List getListenerEntries(CacheEntry entry) { + hasListenerAfterDisposing(entry); + if(listeners.get(entry) != null) + return listeners.get(entry); + else + return Collections.emptyList(); + } + + void processListenerReport(CacheEntry entry, Map> workarea) { + + if(!workarea.containsKey(entry)) { + + HashSet ls = new HashSet(); + for(ListenerEntry e : getListenerEntries(entry)) + ls.add(e.base); + + workarea.put(entry, ls); + + for(CacheEntry parent : entry.getParents(processor)) { + processListenerReport(parent, workarea); + ls.addAll(workarea.get(parent)); + } + + } + + } + + public synchronized ListenerReport getListenerReport() throws IOException { + + class ListenerReportImpl implements ListenerReport { + + Map> workarea = new HashMap>(); + + @Override + public void print(PrintStream b) { + Map hist = new HashMap(); + for(Map.Entry> e : workarea.entrySet()) { + for(ListenerBase l : e.getValue()) { + Integer i = hist.get(l); + hist.put(l, i != null ? i-1 : -1); + } + } + + for(Pair p : CollectionUtils.valueSortedEntries(hist)) { + b.print("" + -p.second + " " + p.first + "\n"); + } + + b.flush(); + } + + } + + ListenerReportImpl result = new ListenerReportImpl(); + + Collection all = processor.allCaches(new CacheCollectionResult()).toCollection(); + for(CacheEntryBase entry : all) { + hasListenerAfterDisposing(entry); + } + for(CacheEntryBase entry : all) { + processListenerReport(entry, result.workarea); + } + + return result; + + } + + public synchronized String reportListeners(File file) throws IOException { + + if (!processor.isAlive()) + return "Disposed!"; + + PrintStream b = new PrintStream(new BufferedOutputStream(new FileOutputStream(file))); + ListenerReport report = getListenerReport(); + report.print(b); + + return "Done reporting listeners."; + + } + + public void fireListeners(WriteGraphImpl graph) { + + assert (!processor.updating); + assert (!processor.cache.collecting); + assert (!firingListeners); + + firingListeners = true; + + try { - ArrayList schedule = new ArrayList(); + // Performing may cause further events to be scheduled. + while (!scheduledListeners.isEmpty()) { - for (ListenerEntry listenerEntry : entries) { + // Clone current events to make new entries possible during + // firing. + THashSet entries = scheduledListeners; + scheduledListeners = new THashSet(); - if (pruneListener(listenerEntry)) { - if (Development.DEVELOPMENT) { - if(Development.getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) { - new Exception().printStackTrace(); - System.err.println("Pruned " + listenerEntry.procedure); - } - } - continue; - } + ArrayList schedule = new ArrayList(); - final CacheEntry entry = listenerEntry.entry; - assert (entry != null); + for (ListenerEntry listenerEntry : entries) { - Object newValue = processor.compareTo(graph, entry, listenerEntry.getLastKnown()); + if (pruneListener(listenerEntry)) { + if (Development.DEVELOPMENT) { + if(Development.getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) { + new Exception().printStackTrace(); + System.err.println("Pruned " + listenerEntry.procedure); + } + } + continue; + } + + final CacheEntry entry = listenerEntry.entry; + assert (entry != null); + + Object newValue = processor.compareTo(graph, entry, listenerEntry.getLastKnown()); + + if (newValue != ListenerEntry.NOT_CHANGED) { + if (Development.DEVELOPMENT) { + if(Development.getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) { + new Exception().printStackTrace(); + System.err.println("Add to schedule " + listenerEntry.procedure + " with " + newValue); + } + } + schedule.add(listenerEntry); + listenerEntry.setLastKnown(entry.getResult()); + } + + } + + for(ListenerEntry listenerEntry : schedule) { + final CacheEntry entry = listenerEntry.entry; + if (Development.DEVELOPMENT) { + if(Development.getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) { + System.err.println("Firing " + listenerEntry.procedure); + } + } + try { + if (Development.DEVELOPMENT) { + if(Development.getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) { + System.err.println("Firing " + listenerEntry.procedure + " for " + listenerEntry.entry); + } + } + entry.performFromCache(graph, listenerEntry.procedure); + } catch (Throwable t) { + t.printStackTrace(); + } + } + + } + + } finally { + firingListeners = false; + } + + } + + void updateParents(int indent, CacheEntry entry, LinkedList todo) { + + Iterable oldParents = entry.getParents(processor); + for (CacheEntry parent : oldParents) { + if(!parent.isDiscarded()) + todo.push(new UpdateEntry(entry, parent, indent + 2)); + } + + } + + private boolean pruneListener(ListenerEntry entry) { + if (entry.base.isDisposed()) { + removeListener(entry); + return true; + } else { + return false; + } + } - if (newValue != ListenerEntry.NOT_CHANGED) { - if (Development.DEVELOPMENT) { - if(Development.getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) { - new Exception().printStackTrace(); - System.err.println("Add to schedule " + listenerEntry.procedure + " with " + newValue); - } - } - schedule.add(listenerEntry); - listenerEntry.setLastKnown(entry.getResult()); - } - - } - - for(ListenerEntry listenerEntry : schedule) { - final CacheEntry entry = listenerEntry.entry; - if (Development.DEVELOPMENT) { - if(Development.getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) { - System.err.println("Firing " + listenerEntry.procedure); - } - } - try { - if (Development.DEVELOPMENT) { - if(Development.getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) { - System.err.println("Firing " + listenerEntry.procedure + " for " + listenerEntry.entry); - } - } - entry.performFromCache(graph, listenerEntry.procedure); - } catch (Throwable t) { - t.printStackTrace(); - } - } - - } - - } finally { - firingListeners = false; - } - - } - - void updateParents(int indent, CacheEntry entry, LinkedList todo) { - - Iterable oldParents = entry.getParents(processor); - for (CacheEntry parent : oldParents) { - if(!parent.isDiscarded()) - todo.push(new UpdateEntry(entry, parent, indent + 2)); - } - - } - - private boolean pruneListener(ListenerEntry entry) { - if (entry.base.isDisposed()) { - removeListener(entry); - return true; - } else { - return false; - } - } - } diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryProcessor.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryProcessor.java index 46c857794..50a9a827a 100644 --- a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryProcessor.java +++ b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryProcessor.java @@ -268,10 +268,10 @@ final public class QueryProcessor extends AbstractDisposable implements ReadGrap @Override public String toString() { -// if(graph == null) + if(rootGraph == null) return "SessionTask[no graph]"; -// else -// return "SessionTask[" + graph.parent + "]"; + else + return "SessionTask[" + rootGraph.parent + "]"; } // public int getLevel() { diff --git a/bundles/org.simantics.db.layer0/adapters.xml b/bundles/org.simantics.db.layer0/adapters.xml index 11a3ff235..bdf1f1435 100644 --- a/bundles/org.simantics.db.layer0/adapters.xml +++ b/bundles/org.simantics.db.layer0/adapters.xml @@ -35,7 +35,8 @@ + class="org.simantics.db.layer0.variable.StandardVariableBuilder" + constructor="get" > diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/request/PropertyInfo.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/request/PropertyInfo.java index 4d208b457..150c760aa 100644 --- a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/request/PropertyInfo.java +++ b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/request/PropertyInfo.java @@ -103,4 +103,96 @@ public class PropertyInfo { .append("]"); return sb.toString(); } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((builder == null) ? 0 : builder.hashCode()); + result = prime * result + ((classifications == null) ? 0 : classifications.hashCode()); + result = prime * result + ((defaultBinding == null) ? 0 : defaultBinding.hashCode()); + result = prime * result + ((definedUnit == null) ? 0 : definedUnit.hashCode()); + result = prime * result + (hasEnumerationRange ? 1231 : 1237); + result = prime * result + (isFunctional ? 1231 : 1237); + result = prime * result + (isHasProperty ? 1231 : 1237); + result = prime * result + ((literalRange == null) ? 0 : literalRange.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((predicate == null) ? 0 : predicate.hashCode()); + result = prime * result + ((requiredDatatype == null) ? 0 : requiredDatatype.hashCode()); + result = prime * result + ((requiredValueType == null) ? 0 : requiredValueType.hashCode()); + result = prime * result + ((subliteralPredicates == null) ? 0 : subliteralPredicates.hashCode()); + result = prime * result + ((valueAccessor == null) ? 0 : valueAccessor.hashCode()); + return result; + } + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + PropertyInfo other = (PropertyInfo) obj; + if (builder == null) { + if (other.builder != null) + return false; + } else if (!builder.equals(other.builder)) + return false; + if (classifications == null) { + if (other.classifications != null) + return false; + } else if (!classifications.equals(other.classifications)) + return false; + if (defaultBinding == null) { + if (other.defaultBinding != null) + return false; + } else if (!defaultBinding.equals(other.defaultBinding)) + return false; + if (definedUnit == null) { + if (other.definedUnit != null) + return false; + } else if (!definedUnit.equals(other.definedUnit)) + return false; + if (hasEnumerationRange != other.hasEnumerationRange) + return false; + if (isFunctional != other.isFunctional) + return false; + if (isHasProperty != other.isHasProperty) + return false; + if (literalRange == null) { + if (other.literalRange != null) + return false; + } else if (!literalRange.equals(other.literalRange)) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (predicate == null) { + if (other.predicate != null) + return false; + } else if (!predicate.equals(other.predicate)) + return false; + if (requiredDatatype == null) { + if (other.requiredDatatype != null) + return false; + } else if (!requiredDatatype.equals(other.requiredDatatype)) + return false; + if (requiredValueType == null) { + if (other.requiredValueType != null) + return false; + } else if (!requiredValueType.equals(other.requiredValueType)) + return false; + if (subliteralPredicates == null) { + if (other.subliteralPredicates != null) + return false; + } else if (!subliteralPredicates.equals(other.subliteralPredicates)) + return false; + if (valueAccessor == null) { + if (other.valueAccessor != null) + return false; + } else if (!valueAccessor.equals(other.valueAccessor)) + return false; + return true; + } } diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/util/SessionGarbageCollection.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/util/SessionGarbageCollection.java index c168e2286..c58ced3d8 100644 --- a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/util/SessionGarbageCollection.java +++ b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/util/SessionGarbageCollection.java @@ -75,10 +75,10 @@ public class SessionGarbageCollection { if(_monitor == null) _monitor = new NullProgressMonitor(); QueryControl qc = graph.getService(QueryControl.class); ClusterControl cc = graph.getService(ClusterControl.class); - _monitor.beginTask("Collect clusters", IProgressMonitor.UNKNOWN); - cc.gc(graph, clusterTarget); - _monitor.beginTask("Collect queries", IProgressMonitor.UNKNOWN); - qc.gc(graph, allowedTimeInMs); +// _monitor.beginTask("Collect clusters", IProgressMonitor.UNKNOWN); +// cc.gc(graph, clusterTarget); +// _monitor.beginTask("Collect queries", IProgressMonitor.UNKNOWN); +// qc.gc(graph, allowedTimeInMs); } /** diff --git a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/StandardVariableBuilder.java b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/StandardVariableBuilder.java index b1af87f98..6e83fe139 100644 --- a/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/StandardVariableBuilder.java +++ b/bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/StandardVariableBuilder.java @@ -6,6 +6,17 @@ import org.simantics.db.exception.DatabaseException; public class StandardVariableBuilder implements VariableBuilder { + private static StandardVariableBuilder INSTANCE = null; + + private StandardVariableBuilder() {} + + public static synchronized StandardVariableBuilder get() { + if(INSTANCE == null) { + INSTANCE = new StandardVariableBuilder<>(); + } + return INSTANCE; + } + @Override public Variable buildChild(ReadGraph graph, Variable parent, VariableNode node, Resource child) { return new StandardGraphChildVariable(parent, node, child); diff --git a/bundles/org.simantics.document.server/src/org/simantics/document/server/request/DocumentRequest.java b/bundles/org.simantics.document.server/src/org/simantics/document/server/request/DocumentRequest.java index 9a53060be..f057b98b6 100644 --- a/bundles/org.simantics.document.server/src/org/simantics/document/server/request/DocumentRequest.java +++ b/bundles/org.simantics.document.server/src/org/simantics/document/server/request/DocumentRequest.java @@ -7,16 +7,19 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import org.simantics.db.AsyncReadGraph; import org.simantics.db.ReadGraph; import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener; +import org.simantics.db.common.request.AsyncReadRequest; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.request.VariableRead; import org.simantics.db.layer0.variable.Variable; +import org.simantics.db.procedure.AsyncProcedure; import org.simantics.document.server.JSONObject; public class DocumentRequest extends VariableRead> { - public static boolean PROFILE = false; + public static boolean PROFILE = true; // Thresholds in microseconds public static int PROFILE_THRESHOLD_NODEREQUEST = 2000; public static int PROFILE_THRESHOLD_VALUEREQUEST = 500; @@ -35,20 +38,43 @@ public class DocumentRequest extends VariableRead> { if(nodes.isEmpty()) { return Collections.emptyList(); } - - - /*TreeMap nodeMap = new TreeMap(); - - for (Variable node : nodes) { - nodeMap.put(node.getURI(graph), node); + + if(PROFILE) { + long dura = System.nanoTime()-s; + System.err.println("DocumentRequest1 " + System.identityHashCode(this) + " in " + 1e-6*dura + "ms. " + variable.getURI(graph)); } - System.out.println("*************************************************************************"); - for (Variable node : nodeMap.values()) { - System.out.println(" " + node.getURI(graph)); - }*/ - - for(Variable node : nodes) { - rs.add(graph.syncRequest(new NodeRequest(node), TransientCacheAsyncListener.instance())); + + graph.syncRequest(new AsyncReadRequest() { + + @Override + public void run(AsyncReadGraph graph) throws DatabaseException { + + for(Variable node : nodes) { + graph.asyncRequest(new NodeRequest(node), new AsyncProcedure () { + + @Override + public void execute(AsyncReadGraph graph, JSONObject result) { + synchronized (rs) { + rs.add(result); + } + } + + @Override + public void exception(AsyncReadGraph graph, Throwable throwable) { + } + + }); + + } + + } + + }); + + + if(PROFILE) { + long dura = System.nanoTime()-s; + System.err.println("DocumentRequest2 " + System.identityHashCode(this) + " in " + 1e-6*dura + "ms. " + variable.getURI(graph)); } ArrayList result = new ArrayList(rs); @@ -63,7 +89,7 @@ public class DocumentRequest extends VariableRead> { if(PROFILE) { long dura = System.nanoTime()-s; - System.err.println("DocumentRequest " + System.identityHashCode(this) + " in " + 1e-6*dura + "ms. " + variable.getURI(graph)); + System.err.println("DocumentRequest3 " + System.identityHashCode(this) + " in " + 1e-6*dura + "ms. " + variable.getURI(graph)); } return result; diff --git a/bundles/org.simantics.document.server/src/org/simantics/document/server/request/NodeRequest.java b/bundles/org.simantics.document.server/src/org/simantics/document/server/request/NodeRequest.java index 8d96c4798..82b190544 100644 --- a/bundles/org.simantics.document.server/src/org/simantics/document/server/request/NodeRequest.java +++ b/bundles/org.simantics.document.server/src/org/simantics/document/server/request/NodeRequest.java @@ -5,6 +5,8 @@ import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.request.VariableRead; import org.simantics.db.layer0.variable.Variable; import org.simantics.document.server.DocumentServerUtils.AttributesRequest; +import org.simantics.utils.threads.logger.ITask; +import org.simantics.utils.threads.logger.ThreadLogger; import org.simantics.document.server.JSONObject; public class NodeRequest extends VariableRead { @@ -18,17 +20,13 @@ public class NodeRequest extends VariableRead { @Override public JSONObject perform(ReadGraph graph) throws DatabaseException { - long s = DocumentRequest.PROFILE ? System.nanoTime() : 0L; - JSONObject staticContent = graph.syncRequest(new AttributesRequest(variable)); + ITask task = DocumentRequest.PROFILE ? ThreadLogger.task(this) : null; - if (DocumentRequest.PROFILE) { - long dura = System.nanoTime()-s; - if (dura > DocumentRequest.PROFILE_THRESHOLD_NODEREQUEST * 1e3) { - System.err.println("NodeRequest " + System.identityHashCode(this) + " in " + 1e-6*dura + "ms. " + variable.getURI(graph)); - } - } + JSONObject staticContent = graph.syncRequest(new AttributesRequest(variable)); + if(DocumentRequest.PROFILE) task.finish(); + return staticContent; } diff --git a/bundles/org.simantics.document.server/src/org/simantics/document/server/request/NodesRequest.java b/bundles/org.simantics.document.server/src/org/simantics/document/server/request/NodesRequest.java index f3f1177fc..99526368e 100644 --- a/bundles/org.simantics.document.server/src/org/simantics/document/server/request/NodesRequest.java +++ b/bundles/org.simantics.document.server/src/org/simantics/document/server/request/NodesRequest.java @@ -1,47 +1,72 @@ package org.simantics.document.server.request; -import gnu.trove.set.hash.THashSet; - import java.util.Collection; import java.util.Collections; import java.util.Set; +import org.simantics.db.AsyncReadGraph; import org.simantics.db.ReadGraph; +import org.simantics.db.common.request.AsyncReadRequest; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.request.VariableChildren; import org.simantics.db.layer0.request.VariableRead; import org.simantics.db.layer0.variable.Variable; +import org.simantics.db.procedure.AsyncProcedure; import org.simantics.structural.stubs.StructuralResource2; +import org.simantics.utils.threads.logger.ITask; +import org.simantics.utils.threads.logger.ThreadLogger; + +import gnu.trove.set.hash.THashSet; public class NodesRequest extends VariableRead> { public NodesRequest(Variable var) { super(var); - } - - @Override - public Set perform(ReadGraph graph) throws DatabaseException { - - long s = System.nanoTime(); - - StructuralResource2.getInstance(graph); - if(variable == null) - return Collections.emptySet(); - - Set nodes = new THashSet(); - Collection children = graph.syncRequest(new VariableChildren(variable)); - for(Variable child : children) { - Set childNodes = graph.syncRequest(new NodesRequest2(child)); - nodes.addAll(childNodes); - } - - if(DocumentRequest.PROFILE) { - long dura = System.nanoTime()-s; - System.err.println("NodesRequest " + System.identityHashCode(this) + " in " + 1e-6*dura + "ms. " + variable.getURI(graph)); - } - - return nodes; - - } + } + + @Override + public Set perform(ReadGraph graph) throws DatabaseException { + + ITask task = DocumentRequest.PROFILE ? ThreadLogger.task(this) : null; + + StructuralResource2.getInstance(graph); + if(variable == null) + return Collections.emptySet(); + + Set nodes = new THashSet(); + + Collection children = graph.syncRequest(new VariableChildren(variable)); + + graph.syncRequest(new AsyncReadRequest() { + + @Override + public void run(AsyncReadGraph graph) throws DatabaseException { + + for(Variable child : children) { + graph.asyncRequest(new NodesRequest2(child), new AsyncProcedure>() { + + @Override + public void execute(AsyncReadGraph graph, Set result) { + synchronized(nodes) { + nodes.addAll(result); + } + } + + @Override + public void exception(AsyncReadGraph graph, Throwable throwable) { + } + + }); + } + + } + + }); + + if(DocumentRequest.PROFILE) task.finish(); + + return nodes; + + } } \ No newline at end of file diff --git a/bundles/org.simantics.document.server/src/org/simantics/document/server/request/NodesRequest2.java b/bundles/org.simantics.document.server/src/org/simantics/document/server/request/NodesRequest2.java index 0f57a01c0..6251fb6ec 100644 --- a/bundles/org.simantics.document.server/src/org/simantics/document/server/request/NodesRequest2.java +++ b/bundles/org.simantics.document.server/src/org/simantics/document/server/request/NodesRequest2.java @@ -2,48 +2,91 @@ package org.simantics.document.server.request; import gnu.trove.set.hash.THashSet; +import java.util.Collection; import java.util.Collections; import java.util.Set; import org.simantics.databoard.Bindings; +import org.simantics.db.AsyncReadGraph; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; +import org.simantics.db.common.request.AsyncReadRequest; import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.request.VariableChildren; import org.simantics.db.layer0.request.VariableRead; import org.simantics.db.layer0.variable.Variable; +import org.simantics.db.procedure.AsyncProcedure; import org.simantics.document.base.ontology.DocumentationResource; +import org.simantics.utils.threads.logger.ITask; +import org.simantics.utils.threads.logger.ThreadLogger; public class NodesRequest2 extends VariableRead> { public NodesRequest2(Variable var) { super(var); - } - - @Override - public Set perform(ReadGraph graph) throws DatabaseException { - - DocumentationResource DOC = DocumentationResource.getInstance(graph); - - Resource type = variable.getPossibleType(graph); - if(type == null) return Collections.emptySet(); - - if(!graph.isInheritedFrom(type, DOC.Components_Component)) return Collections.emptySet(); - - Boolean pathExists = variable.getPossiblePropertyValue(graph, DOC.Properties_pathExists, Bindings.BOOLEAN); - if(pathExists != null && !pathExists) return Collections.emptySet(); - - if(graph.isInheritedFrom(type, DOC.Components_PrimitiveComponent)) { - return Collections.singleton(variable); - } else { - Set result = new THashSet(); - for(Variable child : variable.getChildren(graph)) { - Set nodes = graph.syncRequest(new NodesRequest2(child)); - result.addAll(nodes); - } - - return result; - } - - } + } + + @Override + public Set perform(ReadGraph graph) throws DatabaseException { + + ITask task = DocumentRequest.PROFILE ? ThreadLogger.task(this) : null; + + DocumentationResource DOC = DocumentationResource.getInstance(graph); + + Resource type = variable.getPossibleType(graph); + if(type == null) { + if(DocumentRequest.PROFILE) task.finish(); + return Collections.emptySet(); + } + + if(!graph.isInheritedFrom(type, DOC.Components_Component)) { + if(DocumentRequest.PROFILE) task.finish(); + return Collections.emptySet(); + } + + Boolean pathExists = variable.getPossiblePropertyValue(graph, DOC.Properties_pathExists, Bindings.BOOLEAN); + if(pathExists != null && !pathExists) { + if(DocumentRequest.PROFILE) task.finish(); + return Collections.emptySet(); + } + + if(graph.isInheritedFrom(type, DOC.Components_PrimitiveComponent)) { + if(DocumentRequest.PROFILE) task.finish(); + return Collections.singleton(variable); + } else { + Set result = new THashSet(); + Collection children = graph.syncRequest(new VariableChildren(variable)); + graph.syncRequest(new AsyncReadRequest() { + + @Override + public void run(AsyncReadGraph graph) throws DatabaseException { + + for(Variable child : children) { + graph.asyncRequest(new NodesRequest2(child), new AsyncProcedure>() { + + @Override + public void execute(AsyncReadGraph graph, Set vars) { + synchronized(result) { + result.addAll(vars); + } + } + + @Override + public void exception(AsyncReadGraph graph, Throwable throwable) { + } + + }); + } + + } + + }); + + if(DocumentRequest.PROFILE) task.finish(); + return result; + + } + + } } \ No newline at end of file diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/module/ConcreteModule.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/module/ConcreteModule.java index 31ef0dc5a..23704156c 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/module/ConcreteModule.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/module/ConcreteModule.java @@ -357,4 +357,9 @@ public class ConcreteModule implements Module { public ModuleDebugInfo getModuleDebugInfo() { return moduleDebugInfo; } + + public Map getClasses() { + return classes; + } + } diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/runtime/RuntimeModule.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/runtime/RuntimeModule.java index 5ae73c412..2e35427cd 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/runtime/RuntimeModule.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/runtime/RuntimeModule.java @@ -3,9 +3,15 @@ package org.simantics.scl.compiler.runtime; import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.commons.ClassRemapper; +import org.objectweb.asm.commons.Remapper; import org.simantics.scl.compiler.constants.Constant; import org.simantics.scl.compiler.elaboration.modules.SCLValue; import org.simantics.scl.compiler.elaboration.rules.TransformationRule; @@ -16,6 +22,7 @@ import org.simantics.scl.compiler.internal.codegen.utils.JavaNamingPolicy; import org.simantics.scl.compiler.internal.codegen.utils.TransientClassBuilder; import org.simantics.scl.compiler.internal.decompilation.DecompilerFactory; import org.simantics.scl.compiler.internal.decompilation.IDecompiler; +import org.simantics.scl.compiler.module.ConcreteModule; import org.simantics.scl.compiler.module.Module; import org.simantics.scl.compiler.top.SCLCompilerConfiguration; import org.simantics.scl.compiler.top.ValueNotFound; @@ -28,7 +35,7 @@ public class RuntimeModule { private static final Logger LOGGER = LoggerFactory.getLogger(RuntimeModule.class); public static final boolean VALIDATE_CLASS_NAMES = true; - public static final boolean TRACE_CLASS_CREATION = false; + public static final boolean TRACE_CLASS_CREATION = true; Module module; ModuleClassLoader classLoader; @@ -123,7 +130,8 @@ public class RuntimeModule { } private Class getClass(String name) throws ClassNotFoundException { - //System.out.println("getClass " + name); + + System.out.println(moduleName + ":getClass " + name); // If the class is not generated from SCL, use parent class loader if(!name.startsWith(SCL_PACKAGE_PREFIX)) { @@ -160,6 +168,22 @@ public class RuntimeModule { } } +// protected Class loadClass(String name, boolean resolve) +// throws ClassNotFoundException +// { +// synchronized (getClassLoadingLock(name)) { +// // First, check if the class has already been loaded +// Class c = findLoadedClass(name); +// if (c == null) { +// c = getClass(name); +// } +// if (resolve) { +// resolveClass(c); +// } +// return c; +// } +// } + @Override public synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException { Class clazz = getClass(name); @@ -168,6 +192,11 @@ public class RuntimeModule { return clazz; } + @Override + public Class loadClass(String name) throws ClassNotFoundException { + return super.loadClass(name); + } + public Module getModule(String moduleName) { //System.out.println("ModuleClassLoader.getModule(" + moduleName + ")"); if(moduleName.equals(this.moduleName)) @@ -285,4 +314,105 @@ public class RuntimeModule { classLoader = null; classBuilder = null; } + + public class ClassNameRecordingRemapper extends Remapper { + + private final Set classNames; + + public ClassNameRecordingRemapper(Set classNames) { + this.classNames = classNames; + } + + @Override + public String map(String typeName) { + classNames.add(typeName); + return super.map(typeName); + } + + @Override + public String mapDesc(String desc) { + //classNames.add(desc); + return super.mapDesc(desc); + } + @Override + public String mapFieldName(String owner, String name, String desc) { + return super.mapFieldName(owner, name, desc); + } + @Override + public String mapInvokeDynamicMethodName(String name, String desc) { + // TODO Auto-generated method stub + return super.mapInvokeDynamicMethodName(name, desc); + } + @Override + public String mapMethodDesc(String desc) { + //classNames.add(desc); + return super.mapMethodDesc(desc); + } + @Override + public String mapMethodName(String owner, String name, String desc) { + // TODO Auto-generated method stub + return super.mapMethodName(owner, name, desc); + } + @Override + public String mapSignature(String signature, boolean typeSignature) { + //classNames.add(signature); + return super.mapSignature(signature, typeSignature); + } + @Override + public String mapType(String type) { + classNames.add(type); + return super.mapType(type); + } + @Override + public String[] mapTypes(String[] types) { + for(String type : types) + classNames.add(type); + // TODO Auto-generated method stub + return super.mapTypes(types); + } + @Override + public Object mapValue(Object value) { + //classNames.add(value.toString()); + // TODO Auto-generated method stub + return super.mapValue(value); + } + } + + public Set classReferences(String className) { + try { + HashSet referencedClasses = new HashSet<>(); + ClassNameRecordingRemapper m = new ClassNameRecordingRemapper(referencedClasses); + ClassReader cr = new ClassReader(module.getClass(className)); + int ASM5 = 5 << 16 | 0 << 8 | 0; + //TraceClassVisitor tcv = new TraceClassVisitor(null, new PrintWriter(System.err)); + ClassVisitor cv1 = new ClassVisitor(ASM5) {}; + ClassVisitor cv = new ClassRemapper(cv1, m); + cr.accept(cv, ClassReader.SKIP_DEBUG); + System.err.println(className + " refs: " + referencedClasses); + return referencedClasses; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public void loadReferences() { + ConcreteModule cm = (ConcreteModule)module; + try { + for(String className : cm.getClasses().keySet()) { + Set refs = classReferences(className); + for(String s : refs) { + String internalName = s.replace('/', '.'); + try { + classLoader.loadClass(internalName); + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + } catch (Throwable e) { + e.printStackTrace(); + } + } + } \ No newline at end of file diff --git a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/top/ExpressionEvaluator.java b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/top/ExpressionEvaluator.java index b51b188cd..f69395c3d 100644 --- a/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/top/ExpressionEvaluator.java +++ b/bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/top/ExpressionEvaluator.java @@ -76,7 +76,7 @@ public class ExpressionEvaluator { private Type expectedType; private LocalEnvironment localEnvironment; private LocalStorage localStorage; - private boolean interpretIfPossible = true; + private boolean interpretIfPossible = false; private ExpressionParseMode parseMode = ExpressionParseMode.EXPRESSION; private boolean validateOnly; diff --git a/bundles/org.simantics.scl.osgi/src/org/simantics/scl/osgi/SCLOsgi.java b/bundles/org.simantics.scl.osgi/src/org/simantics/scl/osgi/SCLOsgi.java index 2e717f945..1e0360051 100644 --- a/bundles/org.simantics.scl.osgi/src/org/simantics/scl/osgi/SCLOsgi.java +++ b/bundles/org.simantics.scl.osgi/src/org/simantics/scl/osgi/SCLOsgi.java @@ -4,10 +4,12 @@ import java.util.ArrayList; import org.simantics.scl.compiler.errors.DoesNotExist; import org.simantics.scl.compiler.errors.Failable; +import org.simantics.scl.compiler.module.ConcreteModule; import org.simantics.scl.compiler.module.Module; import org.simantics.scl.compiler.module.options.ModuleCompilationOptions; import org.simantics.scl.compiler.module.options.ModuleCompilationOptionsAdvisor; import org.simantics.scl.compiler.module.repository.ModuleRepository; +import org.simantics.scl.compiler.runtime.RuntimeModule; import org.simantics.scl.compiler.source.repository.ModuleSourceRepository; import org.simantics.scl.compiler.testing.repository.TestRepository; import org.simantics.scl.osgi.internal.Activator; @@ -47,9 +49,9 @@ public class SCLOsgi { System.out.print(moduleName); System.out.print(" - "); Failable module = SCLOsgi.MODULE_REPOSITORY.getModule(moduleName); - if(module.didSucceed()) + if(module.didSucceed()) { System.out.println("succeeded"); - else if(module == DoesNotExist.INSTANCE) + } else if(module == DoesNotExist.INSTANCE) System.out.println("does not exist"); // should not happen else { System.out.println("error"); @@ -67,4 +69,54 @@ public class SCLOsgi { } return null; } + + public static String compileAllModules2() { + ArrayList modulesWithErrors = new ArrayList(); + SCLOsgi.SOURCE_REPOSITORY.forAllModules(new TObjectProcedure() { + @Override + public boolean execute(String moduleName) { + System.out.print(moduleName); + System.out.print(" - "); + Failable module = SCLOsgi.MODULE_REPOSITORY.getModule(moduleName); + if(module.didSucceed()) { + System.out.println("succeeded"); + } else if(module == DoesNotExist.INSTANCE) + System.out.println("does not exist"); // should not happen + else { + System.out.println("error"); + modulesWithErrors.add(moduleName); + } + return true; + } + }); + SCLOsgi.SOURCE_REPOSITORY.forAllModules(new TObjectProcedure() { + @Override + public boolean execute(String moduleName) { + System.out.print(moduleName); + System.out.print(" - "); + Failable module = SCLOsgi.MODULE_REPOSITORY.getModule(moduleName); + if(module.didSucceed()) { + Failable frm = SCLOsgi.MODULE_REPOSITORY.getRuntimeModule(moduleName); + RuntimeModule rm = frm.getResult(); + rm.loadReferences(); + System.out.println("succeeded"); + } else if(module == DoesNotExist.INSTANCE) + System.out.println("does not exist"); // should not happen + else { + System.out.println("error"); + modulesWithErrors.add(moduleName); + } + return true; + } + }); + if(!modulesWithErrors.isEmpty()) { + StringBuilder b = new StringBuilder(); + b.append("Some SCL modules failed to compile:"); + for(String module : modulesWithErrors) + b.append(' ').append(module); + return b.toString(); + } + return null; + } + } diff --git a/bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/logger/ThreadLogVisualizer.java b/bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/logger/ThreadLogVisualizer.java index 5a1bb23fb..07d32a8e9 100644 --- a/bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/logger/ThreadLogVisualizer.java +++ b/bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/logger/ThreadLogVisualizer.java @@ -27,7 +27,7 @@ import java.util.Map; public class ThreadLogVisualizer { // Do not show tasks shorter than 5ms - final public static long DISCARD_LIMIT = 2 * 1000 * 1000; + final public static long DISCARD_LIMIT = 50 * 1000 * 1000; // 1s columns final public static long COLUMN_WIDTH = 1000000000; diff --git a/bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/logger/ThreadLogger.java b/bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/logger/ThreadLogger.java index 2f3425c58..67cc92903 100644 --- a/bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/logger/ThreadLogger.java +++ b/bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/logger/ThreadLogger.java @@ -23,7 +23,7 @@ public class ThreadLogger implements IThreadLogger { public static String LOG_FILE = "threads.log"; - public static boolean LOG = false; + public static boolean LOG = true; static Object loggerCreationLock = new Object(); static ThreadLogger logger = null; -- 2.47.1