diff --git a/arc-core/src/arc/Events.java b/arc-core/src/arc/Events.java index a838f6f5..6578c72d 100644 --- a/arc-core/src/arc/Events.java +++ b/arc-core/src/arc/Events.java @@ -2,6 +2,7 @@ import arc.func.*; import arc.struct.*; +import arc.util.*; import java.util.*; @@ -12,17 +13,33 @@ public class Events{ private static class Handler{ // FINISHME: Pool these maybe? I doubt it's needed though private int id = ++lastId; private final Cons cons; + private final String trace; Handler(Cons cons){ this.cons = cons; + trace = null; + } + + Handler(Cons cons, String trace){ + this.cons = cons; + this.trace = trace; } } + public static Class debugType; + private static final ObjectMap>> events = new ObjectMap<>(); /** Handle an event by class. */ public static void on(Class type, Cons listener){ - events.get(type, () -> new Seq<>(Handler.class)).add(new Handler<>(listener)); + String trace = null; + if(type == debugType){ + StackTraceElement[] st = Thread.currentThread().getStackTrace(); + StringBuilder sb = new StringBuilder(); + for (int i = 2; i < st.length; i++) sb.append(st[i].toString()).append('\n'); + trace = sb.toString(); + } + events.get(type, () -> new Seq<>(Handler.class)).add(new Handler<>(listener, trace)); } /** Handle an event by class. Returns an id */ @@ -78,17 +95,24 @@ public static void fire(T type){ public static void fire(Class ctype, T type){ Seq> listeners = events.get(ctype); + boolean dbg = ctype == debugType; if(listeners != null){ Iterator> it = listeners.>as().iterator(); + long tot = Time.nanos(); while(it.hasNext()){ Handler listener = it.next(); if(listener.id == -1){ it.remove(); continue; } + long start = Time.nanos(); listener.cons.get(type); + if (dbg) { + Log.info("Event listener in @ms. Trace:\n@", Time.millisSinceNanos(start), listener.trace); + } } + if (dbg) Log.info("Event fired in @ms", Time.millisSinceNanos(tot)); } } diff --git a/arc-core/src/arc/graphics/g2d/TextureAtlas.java b/arc-core/src/arc/graphics/g2d/TextureAtlas.java index 88e97820..2f056bd4 100644 --- a/arc-core/src/arc/graphics/g2d/TextureAtlas.java +++ b/arc-core/src/arc/graphics/g2d/TextureAtlas.java @@ -121,7 +121,7 @@ public PixmapRegion getPixmap(String name){ return getPixmap(find(name)); } - public PixmapRegion getPixmap(AtlasRegion region){ + public PixmapRegion getPixmap(AtlasRegion region){ // FINISHME: Look into optimizing cases where we call the runnable below if(region.pixmapRegion == null){ Pixmap pix = pixmaps.get(region.texture, () -> region.texture.getTextureData().getPixmap()); region.pixmapRegion = new PixmapRegion(pix, region.getX(), region.getY(), region.width, region.height); diff --git a/arc-core/src/arc/util/Threads.java b/arc-core/src/arc/util/Threads.java index d58db7a0..eb1081e9 100644 --- a/arc-core/src/arc/util/Threads.java +++ b/arc-core/src/arc/util/Threads.java @@ -6,6 +6,7 @@ import java.lang.ref.*; import java.util.concurrent.*; +import java.util.concurrent.atomic.*; /** * Utilities for threaded programming. @@ -42,7 +43,64 @@ public static void awaitAll(Seq> futures){ /** @return an executor with a fixed number of threads which do not expire * @param threads the number of threads */ public static ExecutorService executor(@Nullable String name, int threads){ - return Executors.newFixedThreadPool(threads, r -> newThread(r, name, true)); + final AtomicInteger num = new AtomicInteger(); + if (!"Main Executor".equals(name) || threads != OS.cores) return Executors.newFixedThreadPool(threads, r -> newThread(r, threads == 1 ? name : name + "-" + num.incrementAndGet(), true)); + return new ThreadPoolExecutor(threads, threads, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue(){ + @Override + public void put(Runnable o) throws InterruptedException { + super.put(o); + queued.incrementAndGet(); + } + + @Override + public boolean offer(Runnable o, long timeout, TimeUnit unit) throws InterruptedException { + boolean r = super.offer(o, timeout, unit); + if (r) queued.incrementAndGet(); + return r; + } + + @Override + public boolean offer(Runnable o) { + boolean r = super.offer(o); + if (r) queued.incrementAndGet(); + return r; + } + }, + r -> newThread(r, name + "-" + num.incrementAndGet(), true)) { + @Override + protected void afterExecute(Runnable r, Throwable t) { + queued.decrementAndGet(); + done.incrementAndGet(); + } + { + daemon("Main Executor Watcher", () -> { + startTime = Time.millis(); + while(true) { + printStats(queued.get(), done.get()); + sleep(10); + } + }); + prestartAllCoreThreads(); + } + }; + } + + private static final AtomicInteger queued = new AtomicInteger(), done = new AtomicInteger(); + private static long startTime, lastQ, lastD; + private static void printStats(int numQueued, int numDone) { + if (lastQ == numQueued && lastD == numDone) return; + lastQ = numQueued; + lastD = numDone; + System.out.println(Strings.format("@q | @d | @t", numQueued, numDone, Time.timeSinceMillis(startTime))); + } + + private static void getTrace() { + StackTraceElement[] st = Thread.currentThread().getStackTrace(); + StringBuilder sb = new StringBuilder(); + for (int i = 3; i < st.length; i++) sb.append(st[i].toString()).append('\n'); + Log.info(sb.toString()); } /** @see #executor(String, int) */ diff --git a/extensions/packer/src/arc/packer/MaxRectsPacker.java b/extensions/packer/src/arc/packer/MaxRectsPacker.java index 5d46f2c4..81d42101 100644 --- a/extensions/packer/src/arc/packer/MaxRectsPacker.java +++ b/extensions/packer/src/arc/packer/MaxRectsPacker.java @@ -163,6 +163,7 @@ private Page packPage(Seq inputRects){ if(!settings.silent){ if(++i % 70 == 0) System.out.println(); System.out.print("."); + System.out.flush(); } bestWidthResult = getBest(bestWidthResult, result); width = widthSearch.next(result == null);