Added some gc debugging / helpers.
authorNot Zed <notzed@gmail.com>
Sat, 25 Jan 2020 03:07:54 +0000 (13:37 +1030)
committerNot Zed <notzed@gmail.com>
Sat, 25 Jan 2020 03:07:54 +0000 (13:37 +1030)
nbproject/project.properties
src/notzed.zcl.fxdemo/classes/fxdemo/fract/Mandelbrot.java
src/notzed.zcl/classes/api/Callback.java
src/notzed.zcl/classes/api/Memory.java
src/notzed.zcl/classes/api/Native.java
src/notzed.zcl/classes/au/notzed/zcl/CLPlatform.java

index faa0316..c05dc39 100644 (file)
@@ -81,7 +81,7 @@ run.classpath=
 # Space-separated list of JVM arguments used when running the project.
 # You may also define separate properties like run-sys-prop.name=value instead of -Dname=value.
 # To set system properties for unit tests define test-sys-prop.name=value:
-run.jvmargs=-Djava.library.path=../nativez/bin/notzed.nativez/linux-amd64/lib:bin/notzed.zcl/linux-amd64/lib
+run.jvmargs=--add-exports jdk.incubator.foreign/jdk.incubator.foreign.unsafe=notzed.zcl
 run.modulepath=\
     ${javac.modulepath}:\
     ${build.modules.dir}
index 4a2cb1c..f5bd01c 100644 (file)
@@ -36,8 +36,10 @@ import javafx.stage.Stage;
 import javafx.util.Duration;
 import java.nio.ByteBuffer;
 import au.notzed.zcl.CLMemory;
+import au.notzed.zcl.CLObject;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Stream;
 import javafx.geometry.Rectangle2D;
 import javafx.stage.Screen;
@@ -59,6 +61,9 @@ public class Mandelbrot extends Application {
                return t;
        });
 
+       Timeline tofps;
+       Transition spin;
+       Zoom zoom;
        long nframes;
        long lframes;
 
@@ -112,7 +117,7 @@ public class Mandelbrot extends Application {
                        case "target":
                                if (v.equals("list")) {
                                        System.out.println("Available targets:");
-                                       for (Target t : targets) {
+                                       for (Target t: targets) {
                                                System.out.print("\t");
                                                System.out.println(t.name);
                                        }
@@ -148,8 +153,8 @@ public class Mandelbrot extends Application {
                        case "size":
                                if (v.equals("full")) {
                                        Rectangle2D size = Screen.getPrimary().getBounds();
-                                       width = (int) size.getWidth();
-                                       height = (int) size.getHeight();
+                                       width = (int)size.getWidth();
+                                       height = (int)size.getHeight();
                                        fullscreen = true;
                                } else {
                                        String coords[] = v.split(",");
@@ -208,7 +213,7 @@ public class Mandelbrot extends Application {
 
                buffer = CLMemory.alloc(width * height * 4);
 
-               Timeline tofps = new Timeline(new KeyFrame(Duration.seconds(0.1), (ActionEvent event) -> {
+               tofps = new Timeline(new KeyFrame(Duration.seconds(0.1), (ActionEvent event) -> {
                        fps.setText(String.format("fps %4d maxiter %d", (nframes - lframes) * 10, lastiter));
                        lframes = nframes;
                }));
@@ -216,7 +221,7 @@ public class Mandelbrot extends Application {
                tofps.play();
 
                if (delta != 0.0) {
-                       Transition spin = new Transition(rate) {
+                       spin = new Transition(rate) {
                                {
                                        setCycleDuration(Duration.seconds(360 / (Math.abs(delta))));
                                }
@@ -233,7 +238,7 @@ public class Mandelbrot extends Application {
                        arg = Math.toRadians(90);
                }
 
-               Zoom zoom = synchronous ? new Zoom() : new Zoom(rate);
+               zoom = synchronous ? new Zoom() : new Zoom(rate);
                zoom.setInterpolator(Interpolator.EASE_BOTH);
                zoom.setAutoReverse(true);
                zoom.setCycleCount(Timeline.INDEFINITE);
@@ -242,7 +247,18 @@ public class Mandelbrot extends Application {
 
        @Override
        public void stop() throws Exception {
+               // weird, one needs to explitly stop animations?
+               zoom.stop();
+               tofps.stop();
+               if (spin != null)
+                       spin.stop();
+               CLObject.debugDumpReachable("Running objects at exit");
+               queue.shutdown();
+               queue.awaitTermination(5, TimeUnit.SECONDS);
                calc.release();
+               System.gc();
+               Thread.sleep(1000);
+               CLObject.debugDumpReachable("Post release");
        }
 
        class Zoom extends Transition {
@@ -259,7 +275,7 @@ public class Mandelbrot extends Application {
                @Override
                protected void interpolate(double frac) {
                        double scale = alpha / Math.exp(frac * beta);
-                       int depth = (int) (-Math.log(scale) * gamma);
+                       int depth = (int)(-Math.log(scale) * gamma);
 
                        recalc(target, isdouble, scale, arg, depth);
                }
@@ -304,4 +320,8 @@ public class Mandelbrot extends Application {
                                .setPixels(0, 0, width, height, PixelFormat.getByteBgraInstance(), buffer, width * 4);
                }
        }
+
+       public static void main(String[] args) {
+               launch(args);
+       }
 }
index 936ae55..e688f56 100644 (file)
@@ -35,6 +35,11 @@ public class Callback<T> extends Native implements AutoCloseable {
                this.func = func;
        }
 
+       @Override
+       public String toString() {
+               return func == null ? "Callback.NULL" : func.toString();
+       }
+
        /*
         * A callback that resolve to MemoryAddress.NULL.
         * This can be released safely any number of times.
index 8107d6c..a1d008e 100644 (file)
@@ -87,6 +87,7 @@ public class Memory {
                final MemorySegment stack;
                final MemoryAddress base;
                long sp;
+               Thread origin;
 
                Stack(MemoryAddress p, long size) {
                        super(p);
@@ -94,6 +95,12 @@ public class Memory {
                        stack = ForeignUnsafe.ofNativeUnchecked(addr(), size);
                        base = stack.baseAddress();
                        sp = size;
+
+                       origin = Thread.currentThread();
+               }
+
+               public String toString() {
+                       return "api.Memory$Stack thread=" + origin.toString();
                }
 
                private static void release(MemoryAddress p) {
index f8a4dc7..5518b26 100644 (file)
@@ -36,10 +36,16 @@ import java.lang.System.Logger.Level;
 
 /**
  * Base class for all native objects.
- * 
+ *
  * Handles instantiation and provides helper functions for native access.
- * 
+ *
  * Work in progress.
+ *
+ * For better safety the 'p' field should be the CHandle, and addr() would
+ * call get().  Otherwise one must not release ANY object which might ever
+ * be used again - including any objects returned by the getInfo().  However ...
+ * it's a trade-off and it's a lot of code to change.
+ *
  */
 public class Native {
 
@@ -671,22 +677,32 @@ public class Native {
                T o;
                boolean step = false;
 
-               if (dolog)
-                       log().log(Level.DEBUG, () -> String.format("  resolv $%016x %s", Memory.toLong(p), create));
+               //if (dolog)
+               //      log().log(Level.DEBUG, () -> String.format("  resolv $%016x %s", Memory.toLong(p), create));
 
-               // ??? who the fuck knows if this will work
-               if (p.offset() == 0)
+               if (Memory.toLong(p) == 0)
                        return null;
 
                // Instantiation needs to be synchronized for obvious reasons.
                synchronized (map) {
                        CHandle h = (CHandle) map.get(p);
 
+                       String fmt;
+
                        if (h == null || (o = (T)(h.get())) == null) {
                                o = create.apply(p);
+
+                               fmt = h == null ? "  create $%016x %s" : "  replac $%016x %s";
+
                                h = new CHandle(o, references, p);
                                map.put(h);
                                step = true;
+                       } else {
+                               fmt = "  exists $%016x %s";
+                       }
+                       {
+                               T x = o;
+                               log().log(Level.DEBUG, () -> String.format(fmt, Memory.toLong(p), x.getClass().getName()));
                        }
                }
 
@@ -721,13 +737,15 @@ public class Native {
                WeakReference<? extends Native> ref;
 
                synchronized (map) {
-                       ref = map.remove(p);
+                       //ref = map.remove(p);
+                       ref = map.get(p);
                }
 
                if (ref != null) {
                        if (dolog)
                                log().log(Level.DEBUG, () -> String.format("  force  $%016x %s", Memory.toLong(p), getClass().getName()));
 
+                       ref.clear();
                        ref.enqueue();
                }
        }
@@ -850,6 +868,23 @@ public class Native {
                }
        }
 
+       public static void debugDumpReachable(String title) {
+               synchronized (map) {
+                       System.out.println(title);
+                       for (CHandle h: map.table) {
+                               while (h != null) {
+                                       Native o = h.get();
+                                       System.out.printf(" $%016x: %s %-40s %s\n",
+                                               Memory.toLong(h.p),
+                                               o == null ? "dead" : "live",
+                                               h.jtype.getName(),
+                                               o);
+                                       h = h.next;
+                               }
+                       }
+               }
+       }
+
        /**
         * Lightweight pointer hashtable.
         * <p>
index 2151e7d..9b11165 100644 (file)
@@ -56,11 +56,7 @@ public class CLPlatform extends CLObject {
 
        private static void release(MemoryAddress p) {
                // noop
-       }
-
-       @Override
-       public void release() {
-               // noop
+               System.out.println("** release clplatform");
        }
 
        @Override
@@ -94,7 +90,7 @@ public class CLPlatform extends CLObject {
                        res = (int)clGetPlatformIDs.invokeExact(0, MemoryAddress.NULL, lenp);
                        if (res != 0)
                                throw new CLRuntimeException(res);
-                       
+
                        len = Native.getInt(lenp);
                        list = frame.alloca(8 * len);
 
@@ -201,16 +197,16 @@ public class CLPlatform extends CLObject {
 
        /**
         * Get the platform api versiom.
-        * 
+        *
         * This may be compared to the version constants
         * {@link #VERSION_1_0}, {@link #VERSION_1_1}, and so on.
-        * 
+        *
         * @return platform api version.
         */
        public int getAPIVersion() {
                return apiVersion;
        }
-       
+
        /**
         * get CL_PLATFORM_PROFILE.
         *