lwjglx / debug Goto Github PK
View Code? Open in Web Editor NEWDebugging LWJGL3 OpenGL applications
License: MIT License
Debugging LWJGL3 OpenGL applications
License: MIT License
Hi, good afternoon. I'm very interested in this project, can I ask you two questions which troubled me for a while ?
buf.slice(index, length)
expected none parameters but found two. I checked the issue#25 and commit history, but I still confused, it seems not support versions before JDK13 anymore.D:\github\debug>mvnw package
[INFO] Scanning for projects...
[INFO]
[INFO] ----------------------< org.lwjglx:lwjglx-debug >-----------------------
[INFO] Building LWJGLX/debug 1.0.0
[INFO] --------------------------------[ jar ]---------------------------------
Downloading from oss.sonatype.org: https://oss.sonatype.org/content/repositories/snapshots/org/lwjgl/lwjgl/3.2.4-SNAPSHOT/maven-metadata.xml
Downloading from repository.ow2.org: https://repository.ow2.org/nexus/content/repositories/snapshots/org/lwjgl/lwjgl/3.2.4-SNAPSHOT/maven-metadata.xml
Downloaded from oss.sonatype.org: https://oss.sonatype.org/content/repositories/snapshots/org/lwjgl/lwjgl/3.2.4-SNAPSHOT/maven-metadata.xml (2.6 kB at 595 B/s)
Downloading from repository.ow2.org: https://repository.ow2.org/nexus/content/repositories/snapshots/org/lwjgl/lwjgl-opengl/3.2.4-SNAPSHOT/maven-metadata.xml
Downloading from oss.sonatype.org: https://oss.sonatype.org/content/repositories/snapshots/org/lwjgl/lwjgl-opengl/3.2.4-SNAPSHOT/maven-metadata.xml
Downloaded from oss.sonatype.org: https://oss.sonatype.org/content/repositories/snapshots/org/lwjgl/lwjgl-opengl/3.2.4-SNAPSHOT/maven-metadata.xml (2.6 kB at 4.4 kB/s)
Downloading from oss.sonatype.org: https://oss.sonatype.org/content/repositories/snapshots/org/lwjgl/lwjgl-glfw/3.2.4-SNAPSHOT/maven-metadata.xml
Downloading from repository.ow2.org: https://repository.ow2.org/nexus/content/repositories/snapshots/org/lwjgl/lwjgl-glfw/3.2.4-SNAPSHOT/maven-metadata.xml
Downloaded from oss.sonatype.org: https://oss.sonatype.org/content/repositories/snapshots/org/lwjgl/lwjgl-glfw/3.2.4-SNAPSHOT/maven-metadata.xml (2.6 kB at 14 B/s)
[INFO]
[INFO] --- maven-antrun-plugin:1.8:run (default) @ lwjglx-debug ---
[INFO] Executing tasks
main:
[INFO] Executed tasks
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ lwjglx-debug ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 2 resources
[INFO]
[INFO] --- maven-compiler-plugin:3.8.1:compile (default-compile) @ lwjglx-debug ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 50 source files to D:\github\debug\target\classes
[INFO] /D:/github/debug/src/org/lwjglx/debug/Profiling.java: D:\github\debug\src\org\lwjglx\debug\Profiling.java使用或覆盖了已过时的 API。
[INFO] /D:/github/debug/src/org/lwjglx/debug/Profiling.java: 有关详细信息, 请使用 -Xlint:deprecation 重新编译。
[INFO] /D:/github/debug/src/org/lwjglx/debug/WeakIdentityHashMap.java: D:\github\debug\src\org\lwjglx\debug\WeakIdentityHashMap.java使用了未经检查或不安全的操作。
[INFO] /D:/github/debug/src/org/lwjglx/debug/WeakIdentityHashMap.java: 有关详细信息, 请使用 -Xlint:unchecked 重新编译。
[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] /D:/github/debug/src/org/lwjglx/debug/RT.java:[182,32] 无法将类 java.nio.ByteBuffer中的方法 slice应用到给定类型;
需要: 没有参数
找到: int,int
原因: 实际参数列表和形式参数列表长度不同
[ERROR] /D:/github/debug/src/org/lwjglx/debug/RT.java:[201,32] 无法将类 java.nio.CharBuffer中的方法 slice应用到给定类型;
需要: 没有参数
找到: int,int
原因: 实际参数列表和形式参数列表长度不同
[ERROR] /D:/github/debug/src/org/lwjglx/debug/RT.java:[218,33] 无法将类 java.nio.ShortBuffer中的方法 slice应用到给定类型;
需要: 没有参数
找到: int,int
原因: 实际参数列表和形式参数列表长度不同
[ERROR] /D:/github/debug/src/org/lwjglx/debug/RT.java:[235,31] 无法将类 java.nio.IntBuffer中的方法 slice应用到给定类型;
需要: 没有参数
找到: int,int
原因: 实际参数列表和形式参数列表长度不同
[ERROR] /D:/github/debug/src/org/lwjglx/debug/RT.java:[252,32] 无法将类 java.nio.LongBuffer中的方法 slice应用到给定类型;
需要: 没有参数
找到: int,int
原因: 实际参数列表和形式参数列表长度不同
[ERROR] /D:/github/debug/src/org/lwjglx/debug/RT.java:[269,33] 无法将类 java.nio.FloatBuffer中的方法 slice应用到给定类型;
需要: 没有参数
找到: int,int
原因: 实际参数列表和形式参数列表长度不同
[ERROR] /D:/github/debug/src/org/lwjglx/debug/RT.java:[286,34] 无法将类 java.nio.DoubleBuffer中的方法 slice应用到给定类型;
需要: 没有参数
找到: int,int
原因: 实际参数列表和形式参数列表长度不同
[INFO] 7 errors
[INFO] -------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 03:12 min
[INFO] Finished at: 2020-11-04T21:43:39+08:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project lwjglx-debug: Compilation failure: Compilation failure:
[ERROR] /D:/github/debug/src/org/lwjglx/debug/RT.java:[182,32] 无法将类 java.nio.ByteBuffer中的方法 slice应用到给定类型;
[ERROR] 需要: 没有参数
[ERROR] 找到: int,int
[ERROR] 原因: 实际参数列表和形式参数列表长度不同
[ERROR] /D:/github/debug/src/org/lwjglx/debug/RT.java:[201,32] 无法将类 java.nio.CharBuffer中的方法 slice应用到给定类型;
[ERROR] 需要: 没有参数
[ERROR] 找到: int,int
[ERROR] 原因: 实际参数列表和形式参数列表长度不同
[ERROR] /D:/github/debug/src/org/lwjglx/debug/RT.java:[218,33] 无法将类 java.nio.ShortBuffer中的方法 slice应用到给定类型;
[ERROR] 需要: 没有参数
[ERROR] 找到: int,int
[ERROR] 原因: 实际参数列表和形式参数列表长度不同
[ERROR] /D:/github/debug/src/org/lwjglx/debug/RT.java:[235,31] 无法将类 java.nio.IntBuffer中的方法 slice应用到给定类型;
[ERROR] 需要: 没有参数
[ERROR] 找到: int,int
[ERROR] 原因: 实际参数列表和形式参数列表长度不同
[ERROR] /D:/github/debug/src/org/lwjglx/debug/RT.java:[252,32] 无法将类 java.nio.LongBuffer中的方法 slice应用到给定类型;
[ERROR] 需要: 没有参数
[ERROR] 找到: int,int
[ERROR] 原因: 实际参数列表和形式参数列表长度不同
[ERROR] /D:/github/debug/src/org/lwjglx/debug/RT.java:[269,33] 无法将类 java.nio.FloatBuffer中的方法 slice应用到给定类型;
[ERROR] 需要: 没有参数
[ERROR] 找到: int,int
[ERROR] 原因: 实际参数列表和形式参数列表长度不同
[ERROR] /D:/github/debug/src/org/lwjglx/debug/RT.java:[286,34] 无法将类 java.nio.DoubleBuffer中的方法 slice应用到给定类型;
[ERROR] 需要: 没有参数
[ERROR] 找到: int,int
[ERROR] 原因: 实际参数列表和形式参数列表长度不同
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
Hi,
as titled, it crashes here:
Context context = CURRENT_CONTEXT.get();
context.caps = caps;
I double cheched and context
is indeed null
In my app I do the following:
glfwWindow = GlfwWindow.fromWin32Window(hwnd).apply {
makeContextCurrent()
println("current: $isCurrent")
createCapabilities(forwardCompatible = false)
}
glfwGetCurrentContext == window.handle
)And the last step is exactly where debug crashes
What is wrong?
ps: glfw
is already initialized at that point, I also have GLFWErrorCallback.createPrint().set()
but I dont get any error from there
Currently, all enums in all enum groups are simply stored in a HashMap, which is wasteful regarding space and runtime, since the enum values are rather densely distributed. Therefore, space requirements and lookup time can be improved by simply allocating a contiguous associative String[] array holding the names of all GLenum values in the effective interval min < max
where min
and max
are the lower and upper bounds of assigned GLenum values.
On-demand loading of enum values into that array can still be used as is now, by lazily populating the respective needed array elements.
I have a lot of code that flip
s or calls glBufferData
an empty buffer (e.g. when there is no input to a compute shader this frame), and if this happens in a certain part of the code I'm pretty sure it's not a problem. It would be nice if I could tell the tool to suppress that warning while that code is executing.
The GL call trace outputs are good to see the general order of GL calls with their arguments and return values.
However, it is not easy to match the GL calls to the user source code they appear in. For this it would be great to annotate each GL call with the source file name and the line number in the IDE-recognized format "(filename:line)". This allows to click them in the IDE's console to jump to the respective line in the source code.
Currently, a full stacktrace is being generated for GL debug message callbacks using Throwable.getStackTrace(). A full stacktrace is likely not needed for each traced GL call, but only the last stracktrace element. For this, we do not even need to call into the JVM runtime, since we have the debug information already read from the classfile.
We just need to introduce two additional parameters (String sourcefile, int linenumber)
in the call interface of the generated trace class, which are being fed by the Transformer class when GL calls are seen.
Possible desired output format:
[trace][1] (MyLwjglProgram.java:15) glUseProgram(6)
[trace][1] (MyLwjglProgram.java:20) glBindBuffer(GL_ARRAY_BUFFER, 3)
[trace][1] (MyLwjglProgram.java:123) glVertexPointer(3, GL_FLOAT, 0, 0L)
[trace][1] (MyLwjglProgram.java:126) glEnableClientState(GL_NORMAL_ARRAY)
[trace][1] (MyLwjglProgram.java:131) glBindBuffer(GL_ARRAY_BUFFER, 4)
[trace][1] (MyLwjglProgram.java:133) glNormalPointer(GL_FLOAT, 0, 0L)
[trace][1] (MyLwjglProgram.java:134) glBindBuffer(GL_ARRAY_BUFFER, 0)
Of course, the output should be properly formatted with padding to account for different sourcefile and line number lengths.
I saw there was a pull request to update dependencies for Java 18 compatibility, but even building against 402539a using ./mvnw clean package
, the resulting target/lwjglx-debug-1.0.0.jar
does not seem to work with Java 18. It's exactly what you'd expect:
java.lang.IllegalArgumentException: Unsupported class file major version 62
at org.lwjglx.debug.org.objectweb.asm.ClassReader.<init>(ClassReader.java:196)
at org.lwjglx.debug.org.objectweb.asm.ClassReader.<init>(ClassReader.java:177)
at org.lwjglx.debug.org.objectweb.asm.ClassReader.<init>(ClassReader.java:163)
at org.lwjglx.debug.Agent.transform_(Agent.java:140)
at org.lwjglx.debug.Agent.transform(Agent.java:65)
[...]
Oddly enough, in the source I have, the new ClassReader
occurs one line later, on line 141, but is reported as being on 140 for reasons I cannot fathom.
There was also one stage of the maven build where it threw an error (not counting the intentional errors in testing), and I'm not sure if it's significant or not:
[INFO] --- maven-antrun-plugin:3.1.0:run (default) @ lwjglx-debug ---
[INFO] Executing tasks
[ERROR] [java] java.lang.UnsupportedOperationException: The Security Manager is deprecated and will be removed in a future release
[java] at org.apache.tools.ant.taskdefs.ExecuteJava.execute(ExecuteJava.java:194)
[java] at org.apache.tools.ant.taskdefs.Java.run(Java.java:891)
[java] at org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:231)
[java] at org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:135)
Certain methods (like the window-related GLFW methods) may only be called in the main thread. We currently have no validation for this.
Since the Java Agent's premain method is started very early in the VM startup process in the main thread, we certainly know which thread is the main thread.
Currently, all GLenum values are resolved to their core name, when available. This even applies in situations when people call ARB/EXT/NV/... extension functions and those functions define alias names for the same core GLenum.
In this case, we should rather output the GLenum name defined by the extension when that extension defines a name of that particular enum value.
All the metadata for this is already available in the gl.xml:
Especially when trying to see all the OpenGL context/object initializations that usually happen at the start of an application, it is quite impossible to connect with a browser quickly enough.
Simple per-frame measures:
That should be it for the beginning.
As for how to actually display the information:
The goal here is to establish a simple way to collect and display profiling data. Later, more profiling capabilities can be added, such as measuring the GPU render time (via timer query objects) of Java methods containing draw calls or other measured GL calls and display it in some sort of call trace, as is done by all other Java profiler tools (VisualVM, YourKit, JProfiler, ...).
ByteBuffer buf = memAlloc(8);
int bytes = 0;
for (int i = 0; i < 64; ++i) {
buf.put((byte) i);
++bytes;
if (i + 1 == bytes)
buf = memRealloc(buf, bytes * 2);
}
for (int i = 0; i < 64; ++i)
System.out.println(buf.get(i));
memFree(buf);
The code above throws an IllegalArgumentException
in the memRealloc
call.
Exception in thread "main" java.lang.IllegalArgumentException: buffer has no remaining elements. Did you forget to flip()/rewind() it?
Without the agent attached it works fine and to confirm I wrote the same code in C and had no issues.
LWJGL 3.2.1 and JDK 11
I’m trying to troubleshoot a LWJGL application using lwjglx-debug.
When running the application, I get a java.lang.NoClassDefFoundError: org/lwjglx/debug/RT
exception.
Command line I’m using to run the application: JAVA_HOME="$(/usr/libexec/java_home -v 1.8)" java -javaagent:"${HOME}/Downloads/lwjglx-debug-1.0.0.jar" -cp "${HOME}/workspace/josm/core/dist/josm-custom.jar:${HOME}/.ivy2/cache/org.lwjgl/lwjgl/jars/lwjgl-3.3.1.jar:${HOME}/Downloads/lwjglx-debug-1.0.0.jar" org.openstreetmap.josm.gui.MainApplication
I’ve also tried some variations (with and without the lwjglx-debug-1.0.0.jar in classpath, an uber jar with all the LWJGL jars packed into it, Java 8 and Java 11)
Source code locations:
System information:
Simple bash script to reproduce (note: you will be swamped with exceptions, and this does not download the plugin files that I actually want to debug)
$ curl -LO https://josm.openstreetmap.de/josm-tested.jar
$ curl -LO https://build.lwjgl.org/addons/lwjglx-debug/lwjglx-debug-1.0.0.jar
$ curl -LO https://build.lwjgl.org/release/latest/bin/lwjgl/lwjgl.jar
$ java -javaagent:"$(pwd)/lwjglx-debug-1.0.0.jar" -cp "$(pwd)/lwjgl.jar:$(pwd)/josm-tested.jar" org.openstreetmap.josm.gui.MainApplication
Additional notes:
adding =t
to the agent doesn’t make a difference
I have to use the workaround from #29 (I'm constrained to Swing for UI).
Everything works properly in a Fedora 35 Silverblue VM (with java-1.8.0-openjdk
layered on top).
Stacktrace:
2022-03-31 13:42:30.787 SEVERE: Handled by bug report queue: java.lang.NoClassDefFoundError: org/lwjglx/debug/RT
java.lang.NoClassDefFoundError: org/lwjglx/debug/RT
at apple.laf.JRSUIControl.loadBufferWithChanges(JRSUIControl.java:140)
at apple.laf.JRSUIControl.paintImage(JRSUIControl.java:219)
at apple.laf.JRSUIControl.paint(JRSUIControl.java:208)
at com.apple.laf.AquaPainter$AquaSingleImagePainter.createImage(AquaPainter.java:200)
at com.apple.laf.AquaPainter$AquaSingleImagePainter.lambda$paintFromSingleCachedImage$0(AquaPainter.java:178)
at sun.awt.image.MultiResolutionCachedImage.getResolutionVariant(MultiResolutionCachedImage.java:66)
at sun.awt.image.MultiResolutionCachedImage.getBaseImage(MultiResolutionCachedImage.java:106)
at sun.awt.image.AbstractMultiResolutionImage.getWidth(AbstractMultiResolutionImage.java:82)
at sun.awt.image.MultiResolutionCachedImage.getWidth(MultiResolutionCachedImage.java:89)
at sun.java2d.SunGraphics2D.drawImage(SunGraphics2D.java:3269)
at sun.java2d.SunGraphics2D.drawImage(SunGraphics2D.java:3221)
at com.apple.laf.AquaPainter$AquaSingleImagePainter.paintFromSingleCachedImage(AquaPainter.java:186)
at com.apple.laf.AquaPainter$AquaSingleImagePainter.paint(AquaPainter.java:141)
at com.apple.laf.AquaPainter.paint(AquaPainter.java:90)
at com.apple.laf.AquaProgressBarUI.paint(AquaProgressBarUI.java:187)
at com.apple.laf.AquaProgressBarUI.paint(AquaProgressBarUI.java:168)
at javax.swing.plaf.ComponentUI.update(ComponentUI.java:161)
at javax.swing.JComponent.paintComponent(JComponent.java:780)
at javax.swing.JComponent.paint(JComponent.java:1056)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paint(JComponent.java:1065)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paint(JComponent.java:1065)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paint(JComponent.java:1065)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paint(JComponent.java:1065)
at javax.swing.JLayeredPane.paint(JLayeredPane.java:586)
at javax.swing.JComponent.paintChildren(JComponent.java:889)
at javax.swing.JComponent.paintToOffscreen(JComponent.java:5217)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(RepaintManager.java:1579)
at javax.swing.RepaintManager$PaintManager.paint(RepaintManager.java:1502)
at javax.swing.RepaintManager.paint(RepaintManager.java:1272)
at javax.swing.JComponent.paint(JComponent.java:1042)
at java.awt.GraphicsCallback$PaintCallback.run(GraphicsCallback.java:39)
at sun.awt.SunGraphicsCallback.runOneComponent(SunGraphicsCallback.java:79)
at sun.awt.SunGraphicsCallback.runComponents(SunGraphicsCallback.java:116)
at java.awt.Container.paint(Container.java:1978)
at java.awt.Window.paint(Window.java:3906)
at javax.swing.RepaintManager$4.run(RepaintManager.java:842)
at javax.swing.RepaintManager$4.run(RepaintManager.java:814)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:814)
at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:789)
at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:738)
at javax.swing.RepaintManager.access$1200(RepaintManager.java:64)
at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1732)
at java.awt.event.InvocationEvent.dispatch$$$capture(InvocationEvent.java:311)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:74)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:205)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
When attempting to use this library on Java 9 it throws an exception because it can not access "ClassLoader.defineClass".
java.lang.AssertionError: Could not find method: ClassLoader.defineClass
at [email protected]/org.lwjglx.debug.ClassUtils.<clinit>(ClassUtils.java:39)
at [email protected]/org.lwjglx.debug.InterceptClassGenerator.generate(InterceptClassGenerator.java:348)
at [email protected]/org.lwjglx.debug.Agent.transform_(Agent.java:182)
at [email protected]/org.lwjglx.debug.Agent.transform(Agent.java:70)
at java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:246)
at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:550)
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1007)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1086)
at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:206)
at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:760)
at java.base/jdk.internal.loader.BuiltinClassLoader.findClassInModuleOrNull(BuiltinClassLoader.java:681)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:606)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:580)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:185)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:496)
at net.gudenau.ScriptKiddie/net.gudenau.scriptkiddie.start.Start.main(Start.java:7)
java.lang.NoClassDefFoundError: Could not initialize class org.lwjglx.debug.ClassUtils
at [email protected]/org.lwjglx.debug.InterceptClassGenerator.generate(InterceptClassGenerator.java:348)
at [email protected]/org.lwjglx.debug.Agent.transform_(Agent.java:182)
at [email protected]/org.lwjglx.debug.Agent.transform(Agent.java:70)
at java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:246)
at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:550)
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1007)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1086)
at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:206)
at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:760)
at java.base/jdk.internal.loader.BuiltinClassLoader.findClassInModuleOrNull(BuiltinClassLoader.java:681)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:606)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:580)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:185)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:496)
[my stuff]
When using LWJGL 3.2.0 build 12 on OpenJDK 11 with the debug library it throws several java.lang.UnsupportedOperationException
during class transformations and a java.lang.NullPointerException
inside org.lwjgl.opengl.GL.createCapabilities
.
Neither of these exceptions are thrown while LWJGLX are used as an agent.
java --version
openjdk 11 2018-09-25
OpenJDK Runtime Environment 18.9 (build 11+28)
OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode)
Java output:
/usr/lib/jvm/jdk-11/bin/java -javaagent:lwjglDebug/lwjglx-debug-1.0.0.jar -javaagent:/home/gudenau/.local/share/JetBrains/Toolbox/apps/IDEA-U/ch-0/182.4892.20/lib/idea_rt.jar=43771:/home/gudenau/.local/share/JetBrains/Toolbox/apps/IDEA-U/ch-0/182.4892.20/bin -Dfile.encoding=UTF-8 -p /home/gudenau/Desktop/projects/java/-snip-/Client/target/classes:/home/gudenau/.m2/repository/com/google/code/gson/gson/2.8.5/gson-2.8.5.jar:/home/gudenau/Desktop/projects/java/-snip-/IPC/target/classes:/home/gudenau/Desktop/projects/java/-snip-/Protocol/target/classes:/home/gudenau/.m2/repository/org/lwjgl/lwjgl/3.2.0/lwjgl-3.2.0.jar:/home/gudenau/.m2/repository/org/lwjgl/lwjgl-glfw/3.2.0/lwjgl-glfw-3.2.0.jar:/home/gudenau/.m2/repository/org/lwjgl/lwjgl-opengl/3.2.0/lwjgl-opengl-3.2.0.jar:/home/gudenau/.m2/repository/org/lwjgl/lwjgl-stb/3.2.0/lwjgl-stb-3.2.0.jar:/home/gudenau/.m2/repository/org/lwjgl/lwjgl/3.2.0/lwjgl-3.2.0-natives-linux.jar:/home/gudenau/.m2/repository/org/lwjgl/lwjgl-glfw/3.2.0/lwjgl-glfw-3.2.0-natives-linux.jar:/home/gudenau/.m2/repository/org/lwjgl/lwjgl-opengl/3.2.0/lwjgl-opengl-3.2.0-natives-linux.jar:/home/gudenau/.m2/repository/org/lwjgl/lwjgl-stb/3.2.0/lwjgl-stb-3.2.0-natives-linux.jar -m net.gudenau.-snip-.Client/net.gudenau.-snip-.client.Client
[LWJGL] Version: 3.2.0 build 12
[LWJGL] OS: Linux v4.18.16
[LWJGL] JRE: 11 amd64
[LWJGL] JVM: OpenJDK 64-Bit Server VM v11+28 by Oracle Corporation
[LWJGL] Loading library (system): lwjgl
[LWJGL] Using SharedLibraryLoader...
[LWJGL] Found at: /tmp/lwjglgudenau/3.2.0-build-12/liblwjgl.so
[LWJGL] Loaded from org.lwjgl.librarypath: /tmp/lwjglgudenau/3.2.0-build-12/liblwjgl.so
[LWJGL] MemoryUtil accessor: MemoryAccessorUnsafe
[LWJGL] Warning: Failed to instantiate memory allocator: org.lwjgl.system.jemalloc.JEmallocAllocator. Using the system default.
[LWJGL] MemoryUtil allocator: DebugAllocator
[LWJGL] Loading library: glfw
[LWJGL] Using SharedLibraryLoader...
[LWJGL] Found at: /tmp/lwjglgudenau/3.2.0-build-12/libglfw.so
[LWJGL] Loaded from org.lwjgl.librarypath: /tmp/lwjglgudenau/3.2.0-build-12/libglfw.so
java.lang.UnsupportedOperationException
at org.lwjglx.debug.org.objectweb.asm.ClassVisitor.visitNestMemberExperimental(ClassVisitor.java:248)
at org.lwjglx.debug.org.objectweb.asm.ClassReader.accept(ClassReader.java:651)
at org.lwjglx.debug.org.objectweb.asm.ClassReader.accept(ClassReader.java:391)
at org.lwjglx.debug.Agent.transform_(Agent.java:205)
at org.lwjglx.debug.Agent.transform(Agent.java:71)
at java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:246)
at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:563)
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1095)
at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:206)
at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:760)
at java.base/jdk.internal.loader.BuiltinClassLoader.findClassInModuleOrNull(BuiltinClassLoader.java:681)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:606)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:580)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at net.gudenau.-snip-.Client/net.gudenau.-snip-.client.ui.key.KeyLayoutManager.loadLayout(KeyLayoutManager.java:81)
at net.gudenau.-snip-.Client/net.gudenau.-snip-.client.ui.key.KeyLayoutManager.<clinit>(KeyLayoutManager.java:20)
at net.gudenau.-snip-.Client/net.gudenau.-snip-.client.Client.start(Client.java:35)
at net.gudenau.-snip-.Client/net.gudenau.-snip-.client.Client.lambda$main$0(Client.java:25)
at java.base/java.lang.Thread.run(Thread.java:834)
java.lang.UnsupportedOperationException
at org.lwjglx.debug.org.objectweb.asm.ClassVisitor.visitNestHostExperimental(ClassVisitor.java:158)
at org.lwjglx.debug.org.objectweb.asm.ClassReader.accept(ClassReader.java:541)
at org.lwjglx.debug.org.objectweb.asm.ClassReader.accept(ClassReader.java:391)
at org.lwjglx.debug.Agent.transform_(Agent.java:205)
at org.lwjglx.debug.Agent.transform(Agent.java:71)
at java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:246)
at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:563)
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1095)
at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:206)
at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:760)
at java.base/jdk.internal.loader.BuiltinClassLoader.findClassInModuleOrNull(BuiltinClassLoader.java:681)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:606)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:580)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at net.gudenau.-snip-.Client/net.gudenau.-snip-.client.ui.key.KeyLayoutManager.loadLayout(KeyLayoutManager.java:83)
at net.gudenau.-snip-.Client/net.gudenau.-snip-.client.ui.key.KeyLayoutManager.<clinit>(KeyLayoutManager.java:20)
at net.gudenau.-snip-.Client/net.gudenau.-snip-.client.Client.start(Client.java:35)
at net.gudenau.-snip-.Client/net.gudenau.-snip-.client.Client.lambda$main$0(Client.java:25)
at java.base/java.lang.Thread.run(Thread.java:834)
java.lang.UnsupportedOperationException
at org.lwjglx.debug.org.objectweb.asm.ClassVisitor.visitNestMemberExperimental(ClassVisitor.java:248)
at org.lwjglx.debug.org.objectweb.asm.ClassReader.accept(ClassReader.java:651)
at org.lwjglx.debug.org.objectweb.asm.ClassReader.accept(ClassReader.java:391)
at org.lwjglx.debug.Agent.transform_(Agent.java:205)
at org.lwjglx.debug.Agent.transform(Agent.java:71)
at java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:246)
at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:563)
at java.base/java.lang.ClassLoader.defineClass1(Native Method)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)
at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1095)
at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:206)
at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:760)
at java.base/jdk.internal.loader.BuiltinClassLoader.findClassInModuleOrNull(BuiltinClassLoader.java:681)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:606)
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:580)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at net.gudenau.-snip-.Client/net.gudenau.-snip-.client.Client.start(Client.java:37)
at net.gudenau.-snip-.Client/net.gudenau.-snip-.client.Client.lambda$main$0(Client.java:25)
at java.base/java.lang.Thread.run(Thread.java:834)
[LWJGL] Loading library (system): lwjgl_opengl
[LWJGL] Using SharedLibraryLoader...
[LWJGL] Found at: /tmp/lwjglgudenau/3.2.0-build-12/liblwjgl_opengl.so
[LWJGL] Loaded from org.lwjgl.librarypath: /tmp/lwjglgudenau/3.2.0-build-12/liblwjgl_opengl.so
[LWJGL] Loading library: libGL.so.1
[LWJGL] libGL.so.1 not found in org.lwjgl.librarypath=/tmp/lwjglgudenau/3.2.0-build-12
[LWJGL] Loaded from system paths: /usr/lib/x86_64-linux-gnu/libGL.so.1
[LWJGL] Java 9 optimizations enabled
[LWJGL] [GL] Using OpenGL 4.3 for error logging.
[LWJGL] [GL] Warning: A non-debug context may not produce any debug output.
Exception in thread "New Main" java.lang.NullPointerException
at org.lwjglx.debug.opengl.GL.createCapabilities(GL.java:39)
at org.lwjglx.debug.$Proxy$5.createCapabilities1(Unknown Source)
at net.gudenau.-snip-.Client/net.gudenau.-snip-.client.Client.start(Client.java:40)
at net.gudenau.-snip-.Client/net.gudenau.-snip-.client.Client.lambda$main$0(Client.java:25)
at java.base/java.lang.Thread.run(Thread.java:834)
The first argument to glGetVertexAttrib() is always zero. It should be 'i' I think.
for (int i = 0; i < context.GL_MAX_VERTEX_ATTRIBS; i++) {
/* Read enable state and buffer bindings */
if (context.caps.OpenGL20) {
context.currentVao.enabledVertexArrays[i] = org.lwjgl.opengl.GL20.glGetVertexAttribi(0, org.lwjgl.opengl.GL20.GL_VERTEX_ATTRIB_ARRAY_ENABLED) == 1;
context.currentVao.initializedVertexArrays[i] = org.lwjgl.opengl.GL20.glGetVertexAttribi(0, org.lwjgl.opengl.GL15.GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING) != 0;
} else if (context.caps.GL_ARB_vertex_shader) {
context.currentVao.enabledVertexArrays[i] = org.lwjgl.opengl.ARBVertexShader.glGetVertexAttribiARB(0, org.lwjgl.opengl.ARBVertexShader.GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB) == 1;
context.currentVao.initializedVertexArrays[i] = org.lwjgl.opengl.GL20.glGetVertexAttribi(0, org.lwjgl.opengl.ARBVertexBufferObject.GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB) != 0;
}
}
When running with the profiler I got it to throw exceptions that does not happen under normal circumstances.
Log without agent.txt
Log with agent.txt
I've attached logs with and without the agent. It seems to mess with the state in unintended ways because these errors are from my own calls to glGetError
. Also, I'm using multi-threaded shared-context to smooth texture loading but only some errors appear to be caused by that.
Sample code, tested on OpenJDK 17:
Supplier<Integer> func = GL30C::glGenVertexArrays;
glBindVertexArray(func.get());
glDisableVertexAttribArray(0);
will crash with
java.lang.NullPointerException: Cannot read field "enabledVertexArrays" because "org.lwjglx.debug.org.lwjgl.opengl.Context.currentContext().currentVao" is null
at org.lwjglx.debug.org.lwjgl.opengl.GL20.glDisableVertexAttribArray(GL20.java:47)
at org.lwjglx.debug.$Proxy$1.glDisableVertexAttribArray3(Unknown Source)
...suggesting that method reference to glGenVertexArrays didn't go through a proxy object
Call with GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX and TEXTURE_FREE_MEMORY_ATI to report an approximation of the currently free memory.
Hello,
I am developing a small game engine on my free time, I decided to activate your agent with the "trace" parameter but when I do it the program stops after a while without even arriving at launch from the engine loop it stops at a random GLFW function and when I remove it it stops at the one before etc.
Without this parameter everything works flawlessly without memory leaks, freezes, lags, crashes, errors, etc.
Shouldn't this parameter make it possible to obtain a lot of information throughout the program, from the initialization, to the stop, passing through the loop?
Did you have an idea?
I am at your disposal to provide all the necessary information.
Good day !
I attempted to run Minecraft 1.13 snapshot with lwjglx debug (because on my system it has a strange memory leak and I'm trying to find the cause on my own). After adding nothrow and trace options, I got this exception:
Exception in thread "main" java.lang.NoSuchMethodError: org.lwjglx.debug.RT.returnValue(DLorg/lwjglx/debug/MethodCall;)D
at org.lwjglx.debug.$Proxy$44.10(Unknown Source)
at bjh.B(SourceFile:2117)
at net.minecraft.client.main.Main.main(SourceFile:45)
public static void main(String[] args) {
byte[] byteArray = new byte[10];
ByteBuffer bug = ByteBuffer.wrap(byteArray);
bug.slice(1, 5);
}
Running this with the java agent produces a NoSuchMethodError
Counting the number of effectively drawn vertices is hard when it comes to:
For this, we should really use OpenGL Query Objects with the GL_PRIMITIVES_GENERATED
target if supported by the context. The documentation says that it counts the actual "vertices" (not the primitives!), so is exactly what we want.
The only real problems are:
glEndQuery
we start a new query (while still remembering that we also need to get the user query's result at the end of the frame)glfwSwapBuffers()
) we wait on all issued queries (including user queries) and accumulate their results to the final number of vertices to reportCurrently, the GPU (draw calls) and CPU time for the whole frame is recorded and plotted. For more fine-grained profiling it is of course desirable to be able to profile designated code sections separately.
There are the following options to designate those code sections:
Even when OpenGL 4.3 or KHR_debug is not exposed by the GL driver, we can intercept the GLCapabilities field query and calls to those methods so that they do work when being run under the profiler.
The result should be a tree of code sections with their names, the number of encountered invocations/executions and the average GPU and CPU time spent.
My project works but when I add the agent to the vm arguments in eclipse, it seems to change the main thread and I get the following stack trace. Is it possible that using this debug tool changes my main thread so that my glfwInit is now called in another thread? Is there a way to fix that in my code?
[LWJGL] Version: 3.2.2 build 10
[LWJGL] OS: Windows 10 v10.0
[LWJGL] JRE: 11.0.2 amd64
[LWJGL] JVM: OpenJDK 64-Bit Server VM v11.0.2+9 by Oracle Corporation
[LWJGL] Loading library (system): lwjgl
[LWJGL] Using SharedLibraryLoader...
[LWJGL] Found at: C:\Users\ramho\AppData\Local\Temp\lwjglramho\3.2.2-build-10\lwjgl.dll
[LWJGL] Found at: C:\Users\ramho\AppData\Local\Temp\lwjglramho\3.2.2-build-10\lwjgl.dll
[LWJGL] Loaded from org.lwjgl.librarypath: C:\Users\ramho\AppData\Local\Temp\lwjglramho\3.2.2-build-10\lwjgl.dll
[LWJGL] Java 9 stack walker enabled
[LWJGL] Warning: Failed to instantiate memory allocator: org.lwjgl.system.jemalloc.JEmallocAllocator. Using the system default.
[LWJGL] MemoryUtil allocator: DebugAllocator
[LWJGL] Loading library: glfw
[LWJGL] Using SharedLibraryLoader...
[LWJGL] Found at: C:\Users\ramho\AppData\Local\Temp\lwjglramho\3.2.2-build-10\glfw.dll
[LWJGL] Loaded from org.lwjgl.librarypath: C:\Users\ramho\AppData\Local\Temp\lwjglramho\3.2.2-build-10\glfw.dll
[trace] (Window.java:57) createPrint(java.io.PrintStream@d7fbb24) = pointer [0x20E3F310000]
java.lang.IllegalStateException: Method glfwInit was called in thread [Thread[GAME_LOOP_THREAD,5,main]] which is not the main thread.
at org.lwjglb.engine.Window.init(Window.java:60)
at org.lwjglb.engine.GameEngine.init(GameEngine.java:62)
at org.lwjglb.engine.GameEngine.run(GameEngine.java:52)
at java.base/java.lang.Thread.run(Thread.java:834)
Exception in thread "GAME_LOOP_THREAD" java.lang.NullPointerException
at org.lwjglb.game.DummyGame.cleanup(DummyGame.java:192)
at org.lwjglb.engine.GameEngine.cleanup(GameEngine.java:96)
at org.lwjglb.engine.GameEngine.run(GameEngine.java:57)
at java.base/java.lang.Thread.run(Thread.java:834)
[LWJGL] 16 bytes leaked, thread 12 (GAME_LOOP_THREAD), address: 0x20E3F310000
at org.lwjgl.system.Callback.create(Callback.java:133)
at org.lwjgl.system.Callback.<init>(Callback.java:83)
at org.lwjgl.glfw.GLFWErrorCallback.<init>(GLFWErrorCallback.java:60)
at org.lwjgl.glfw.GLFWErrorCallback$1.<init>(GLFWErrorCallback.java:97)
at org.lwjgl.glfw.GLFWErrorCallback.createPrint(GLFWErrorCallback.java:97)
at org.lwjglx.debug.$Proxy$14.createPrint18(Unknown Source)
at org.lwjglb.engine.Window.init(Window.java:57)
at org.lwjglb.engine.GameEngine.init(GameEngine.java:62)
at org.lwjglb.engine.GameEngine.run(GameEngine.java:52)
at java.base/java.lang.Thread.run(Thread.java:834)
Currently, OpenGL errors raised by an OpenGL debug callback will be thrown as exception back to user code and can lead to process abort. This can be undesirable in cases where a user might want to react to OpenGL errors at a later point in time or get a log of all OpenGL errors in the application before fixing them.
We should provide an option to just report errors and not throw in such situations.
What:
Currently, we only count the CPU/host time it takes between two consecutive glfwSwapBuffers
calls.
More interesting for bottleneck analysis however would be to know the actual time it takes the GPU to perform a draw call.
So, for contexts that support it, we could use OpenGL Query Objects with glQueryCounter
and the GL_TIMESTAMP
target to count the GPU time.
The JAWT demos use GLX in order to render GL content on Linux. Currently the debug jar has a fatal exception on o.l.o.GL.createCapabilities
because it doesn't see that there is a current context.
Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: No OpenGL context has been made current through recognized API methods (glfwMakeContextCurrent).
Here is what I think should be the correct way of handling those. The steps are being excercised for the example of "glBufferStorage" and its flags
GLbitfield parameter:
/registry/enums
elements that have a type="bitmask" attribute, the generator has to build a separate group with the enum values defined in that element (hint: the "group" attribute cannot be used for anything since it is hardly ever referenced anywhere)/registry/feature/require
(example GL_VERSION_4_4
) and /registry/extensions/extension/require
(example GL_ARB_buffer_storage
) elements, we first have to search whether there is a <command>
defined in it (example glBufferStorage
) that takes at least one GLbitfield
parameter. This information is found in the corresponding /registry/commands/command
element.enum
elements in /registry/feature/require
(example GL_VERSION_4_4
) and /registry/extensions/extension/require
(example GL_ARB_buffer_storage
) with all previously created bitmask
groups to see which of the enums are bitfield enums. For each enum found in a group A
that group A
is then considered a candidate group when looking up the name(s) of a GLbitfield
argument by its value for a called command defined by this extension or core GL version.Currently, whenever a call site is found that invokes a GL/GLFW method, a trace class is being generated for the whole GL/GLFW class and all methods contained in it. This adds a significant amount to startup/classloading time when the Java Agent is asked by the JVM to execute for the loaded user class.
This gets even more troublesome when we assume user code to call into various different GLxx classes, such as GL11, GL12, GL15, GL20 and GL32 and only calling a handful of methods from each of those.
Therefore, we should change the trace class generation strategy to generate a trace class per user class and simply couple all GL methods from all used GLxx classes together. This in turn can mean that we might generate trace methods for the same GLxx class and method multiple times when they are being called from multiple client classes.
Currently, all logging and tracing output is written to stderr. This might not be optimal for the following reasons:
The second situation can be solved today with using shell pipes to direct stderr to a file.
The first situation cannot be solved by this.
We have the following options to specify a file name:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.