]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add some JNI-internal metrics, accessible via passing -v when running Tester1.java...
authorstephan <stephan@noemail.net>
Mon, 31 Jul 2023 12:10:32 +0000 (12:10 +0000)
committerstephan <stephan@noemail.net>
Mon, 31 Jul 2023 12:10:32 +0000 (12:10 +0000)
FossilOrigin-Name: a5d68a6b64abe3c2dfc3a32157f70fd8a4ad89feef2510b3bbb2d86b325d51ae

ext/jni/GNUmakefile
ext/jni/src/c/sqlite3-jni.c
manifest
manifest.uuid

index b313775f2b0970762901ad714b1a7980a921b3cb..424709d413617ca73de800fe8951b7c8b6ba2fe6 100644 (file)
@@ -145,6 +145,7 @@ $(sqlite3-jni.dll): $(dir.bld.c) $(sqlite3-jni.c) $(SQLite3Jni.java) $(MAKEFILE)
       $(sqlite3-jni.c) -shared -o $@
 all: $(sqlite3-jni.dll)
 
+test.flags ?= -v
 test: $(SQLite3Jni.class) $(sqlite3-jni.dll)
        $(bin.java) -ea -Djava.library.path=$(dir.bld.c) \
                $(java.flags) -cp $(classpath) \
index 0dcda80e1a955e38dd67c058db5a99b17b4e8712..088ae4f88b9bceed0ab09cbd67eb9a82a143eb78 100644 (file)
 ** org.sqlite.jni.SQLiteJni (from which sqlite3-jni.h is generated).
 */
 
+/**
+   If you found this comment by searching the code for
+   CallStaticObjectMethod then you're the victim of an OpenJDK bug:
+
+   https://bugs.openjdk.org/browse/JDK-8130659
+
+   It's known to happen with OpenJDK v8 but not with v19.
+
+   This code does not use JNI's CallStaticObjectMethod().
+*/
+
 /*
 ** Define any SQLITE_... config defaults we want if they aren't
 ** overridden by the builder. Please keep these alphabetized.
   (*env)->ExceptionDescribe(env)
 #define IFTHREW_REPORT IFTHREW EXCEPTION_REPORT
 #define IFTHREW_CLEAR IFTHREW EXCEPTION_CLEAR
+#define EXCEPTION_CANNOT_HAPPEN IFTHREW{\
+    EXCEPTION_REPORT; \
+    (*env)->FatalError(env,"This \"cannot happen\".");  \
+    }
 
 
 /** Helpers for extracting pointers from jobjects, noting that the
@@ -391,6 +406,20 @@ static struct {
     PerDbStateJni * aUsed;
     PerDbStateJni * aFree;
   } perDb;
+  struct {
+    unsigned nphCacheHits;
+    unsigned nphCacheMisses;
+    unsigned envCacheHits;
+    unsigned envCacheMisses;
+    unsigned nDestroy;
+    struct {
+      unsigned nFunc;
+      unsigned nStep;
+      unsigned nFinal;
+      unsigned nValue;
+      unsigned nInverse;
+    } udf;
+  } metrics;
 } S3Global;
 
 /**
@@ -455,6 +484,7 @@ static void s3jni_call_xDestroy(JNIEnv *env, jobject jObj, jclass klazz){
     method = (*env)->GetMethodID(env, klazz, "xDestroy", "()V");
     //MARKER(("jObj=%p, klazz=%p, method=%p\n", jObj, klazz, method));
     if(method){
+      ++S3Global.metrics.nDestroy;
       (*env)->CallVoidMethod(env, jObj, method);
       IFTHREW{
         EXCEPTION_WARN_CALLBACK_THREW;
@@ -472,7 +502,6 @@ static void s3jni_call_xDestroy(JNIEnv *env, jobject jObj, jclass klazz){
    insofar as possible. Calls (*env)->FatalError() if the cache
    fills up. That's hypothetically possible but "shouldn't happen."
    If it does, we can dynamically allocate these instead.
-
 */
 FIXME_THREADING
 static struct JNIEnvCacheLine * S3Global_env_cache(JNIEnv * env){
@@ -480,9 +509,13 @@ static struct JNIEnvCacheLine * S3Global_env_cache(JNIEnv * env){
   int i = 0;
   for( ; i < JNIEnvCache_SIZE; ++i ){
     row = &S3Global.envCache.lines[i];
-    if(row->env == env) return row;
+    if(row->env == env){
+      ++S3Global.metrics.envCacheHits;
+      return row;
+    }
     else if(!row->env) break;
   }
+  ++S3Global.metrics.envCacheMisses;
   if(i == JNIEnvCache_SIZE){
     (*env)->FatalError(env, "Maintenance required: JNIEnvCache is full.");
     return NULL;
@@ -510,8 +543,8 @@ static struct JNIEnvCacheLine * S3Global_env_cache(JNIEnv * env){
    zClassName must be a static string so we can use its address as a
    cache key.
 
-   This simple cache catches the overwhelming majority of searches
-   (>95%) in the current (2023-07-24) tests.
+   This simple cache catches >99% of searches in the current
+   (2023-07-31) tests.
 */
 FIXME_THREADING
 static struct NphCacheLine * S3Global_nph_cache(JNIEnv *env, const char *zClassName){
@@ -538,11 +571,11 @@ static struct NphCacheLine * S3Global_nph_cache(JNIEnv *env, const char *zClassN
   for( i = 0; i < NphCache_SIZE; ++i ){
     cacheLine = &envRow->nph[i];
     if(zClassName == cacheLine->zClassName){
+      ++S3Global.metrics.nphCacheHits;
 #define DUMP_NPH_CACHES 0
 #if DUMP_NPH_CACHES
-      static unsigned int n = 0;
       MARKER(("Cache hit #%u %s klazz@%p nativePointer field@%p, ctor@%p\n",
-              ++n, zClassName, cacheLine->klazz, cacheLine->fidValue,
+              S3Global.metrics.nphCacheHits, zClassName, cacheLine->klazz, cacheLine->fidValue,
               cacheLine->midCtor));
 #endif
       assert(cacheLine->klazz);
@@ -554,10 +587,12 @@ static struct NphCacheLine * S3Global_nph_cache(JNIEnv *env, const char *zClassN
   if(freeSlot){
     freeSlot->zClassName = zClassName;
     freeSlot->klazz = REF_G((*env)->FindClass(env, zClassName));
+    EXCEPTION_CANNOT_HAPPEN;
+    ++S3Global.metrics.nphCacheMisses;
 #if DUMP_NPH_CACHES
     static unsigned int cacheMisses = 0;
     MARKER(("Cache miss #%u %s klazz@%p nativePointer field@%p, ctor@%p\n",
-            ++cacheMisses, zClassName, freeSlot->klazz,
+            S3Global.metrics.nphCacheMisses, zClassName, freeSlot->klazz,
             freeSlot->fidValue, freeSlot->midCtor));
 #endif
 #undef DUMP_NPH_CACHES
@@ -756,7 +791,7 @@ static void PerDbStateJni_dump(PerDbStateJni *s){
    If called with a NULL jDb and non-NULL pDb then allocIfNeeded MUST
    be false and it will look for a matching db object. That usage is
    required for functions, like sqlite3_context_db_handle(), which
-   return a (sqlite3*).
+   return a (sqlite3*) but do not take one as an argument.
 */
 FIXME_THREADING
 static PerDbStateJni * PerDbStateJni_for_db(JNIEnv *env, jobject jDb, sqlite3 *pDb, int allocIfNeeded){
@@ -1161,8 +1196,7 @@ static int udf_report_exception(sqlite3_context * cx, UDFState *s,
                                 const char *zFuncType){
   int rc;
   char * z =
-    sqlite3_mprintf("UDF %s.%s() threw. FIXME: extract "
-                    "Java-side exception message.",
+    sqlite3_mprintf("UDF %s.%s() threw. It should not do that.",
                     s->zFuncName, zFuncType);
   if(z){
     sqlite3_result_error(cx, z, -1);
@@ -1174,6 +1208,10 @@ static int udf_report_exception(sqlite3_context * cx, UDFState *s,
   return rc;
 }
 
+/**
+   Sets up the state for calling a Java-side xFunc/xStep/xInverse()
+   UDF, calls it, and returns 0 on success.
+*/
 static int udf_xFSI(sqlite3_context* pCx, int argc,
                     sqlite3_value** argv,
                     UDFState * s,
@@ -1199,6 +1237,10 @@ static int udf_xFSI(sqlite3_context* pCx, int argc,
   return rc;
 }
 
+/**
+   Sets up the state for calling a Java-side xFinal/xValue() UDF,
+   calls it, and returns 0 on success.
+*/
 static int udf_xFV(sqlite3_context* cx, UDFState * s,
                    jmethodID xMethodID,
                    const char *zFuncType){
@@ -1227,24 +1269,29 @@ static int udf_xFV(sqlite3_context* cx, UDFState * s,
 static void udf_xFunc(sqlite3_context* cx, int argc,
                       sqlite3_value** argv){
   UDFState * const s = (UDFState*)sqlite3_user_data(cx);
+  ++S3Global.metrics.udf.nFunc;
   udf_xFSI(cx, argc, argv, s, s->jmidxFunc, "xFunc");
 }
 static void udf_xStep(sqlite3_context* cx, int argc,
                       sqlite3_value** argv){
   UDFState * const s = (UDFState*)sqlite3_user_data(cx);
+  ++S3Global.metrics.udf.nStep;
   udf_xFSI(cx, argc, argv, s, s->jmidxStep, "xStep");
 }
 static void udf_xFinal(sqlite3_context* cx){
   UDFState * const s = (UDFState*)sqlite3_user_data(cx);
+  ++S3Global.metrics.udf.nFinal;
   udf_xFV(cx, s, s->jmidxFinal, "xFinal");
 }
 static void udf_xValue(sqlite3_context* cx){
   UDFState * const s = (UDFState*)sqlite3_user_data(cx);
+  ++S3Global.metrics.udf.nValue;
   udf_xFV(cx, s, s->jmidxValue, "xValue");
 }
 static void udf_xInverse(sqlite3_context* cx, int argc,
                          sqlite3_value** argv){
   UDFState * const s = (UDFState*)sqlite3_user_data(cx);
+  ++S3Global.metrics.udf.nInverse;
   udf_xFSI(cx, argc, argv, s, s->jmidxInverse, "xInverse");
 }
 
@@ -2374,12 +2421,26 @@ JDECL(jbyteArray,1value_1text16be)(JENV_JSELF, jobject jpSVal){
 
 JDECL(void,1do_1something_1for_1developer)(JENV_JSELF){
   MARKER(("\nVarious bits of internal info:\n"));
-#define SO(T) printf("sizeof(" #T ") = %u\n", (unsigned)sizeof(T))
+  puts("sizeofs:");
+#define SO(T) printf("\tsizeof(" #T ") = %u\n", (unsigned)sizeof(T))
   SO(void*);
   SO(JniHookState);
   SO(PerDbStateJni);
   SO(S3Global);
   SO(JNIEnvCache);
+  printf("Cache info:\n");
+  printf("\tNativePointerHolder cache: %u misses, %u hits\n",
+         S3Global.metrics.nphCacheMisses,
+         S3Global.metrics.nphCacheHits);
+  printf("\tJNIEnv cache               %u misses, %u hits\n",
+         S3Global.metrics.envCacheMisses,
+         S3Global.metrics.envCacheHits);
+  puts("UDF calls:");
+#define UDF(T) printf("\t%-8s = %u\n", #T, S3Global.metrics.udf.n##T)
+  UDF(Func); UDF(Step); UDF(Final); UDF(Value); UDF(Inverse);
+#undef UDF
+  printf("xDestroy calls across all callback types: %u\n",
+         S3Global.metrics.nDestroy);
 #undef SO
 }
 
@@ -2443,8 +2504,10 @@ Java_org_sqlite_jni_SQLite3Jni_init(JNIEnv *env, jclass self, jobject sJni){
 
   for( pLimit = &aLimits[0]; pLimit->zName; ++pLimit ){
     fieldId = (*env)->GetStaticFieldID(env, klazz, pLimit->zName, "I");
+    EXCEPTION_CANNOT_HAPPEN;
     //MARKER(("Setting %s (field=%p) = %d\n", pLimit->zName, fieldId, pLimit->value));
     assert(fieldId);
     (*env)->SetStaticIntField(env, klazz, fieldId, (jint)pLimit->value);
+    EXCEPTION_CANNOT_HAPPEN;
   }
 }
index 748cff482257a837f62db6887da32cf0f4d2af6d..82ad29b0658e380d4bd39e73b53986c9376cde20 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Correct\sa\smis-cast\sin\sthe\sJNI\swrapper\swhich\sjust\shappened\sto\saccidentally\swork.\sUpdate\sJNI\sbinding\sof\ssqlite3_context_db_handle()\sto\sreturn\sthe\sbound-at-open()\sdb\sinstance\sinstead\sof\sa\snew/temp\sproxy\sobject.
-D 2023-07-31T10:55:30.156
+C Add\ssome\sJNI-internal\smetrics,\saccessible\svia\spassing\s-v\swhen\srunning\sTester1.java.\sDocument\san\sOpenJDK\sbug\swhich\sleads\sto\sincorrect\s-Xlint:jni\swarnings.
+D 2023-07-31T12:10:32.812
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -230,9 +230,9 @@ F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c
 F ext/icu/README.txt 7ab7ced8ae78e3a645b57e78570ff589d4c672b71370f5aa9e1cd7024f400fc9
 F ext/icu/icu.c c074519b46baa484bb5396c7e01e051034da8884bad1a1cb7f09bbe6be3f0282
 F ext/icu/sqliteicu.h fa373836ed5a1ee7478bdf8a1650689294e41d0c89c1daab26e9ae78a32075a8
-F ext/jni/GNUmakefile 72a1549aa5ef6fd21b7af58baccd512147d0912ec85963da46c3aa011b6f3450
+F ext/jni/GNUmakefile 3d1f106e7a08bb54279c12979b31492b3dea702a732eab445dbc765120995182
 F ext/jni/README.md c0e6e80935e7761acead89b69c87765b23a6bcb2858c321c3d05681fd338292a
-F ext/jni/src/c/sqlite3-jni.c b552ef9c4ec60d4ea29815d5b2cf7e64b20e100a7eb2741c5382e17b0e49999f
+F ext/jni/src/c/sqlite3-jni.c 7be564e523b576b130d930ed7ad3b389cf22372689101766c3a032166f4438a5
 F ext/jni/src/c/sqlite3-jni.h 74aaf87e77f99857aa3afc013517c934cbc2c16618c83d8f5d6294351bc8e7b1
 F ext/jni/src/org/sqlite/jni/BusyHandler.java 1b1d3e5c86cd796a0580c81b6af6550ad943baa25e47ada0dcca3aff3ebe978c
 F ext/jni/src/org/sqlite/jni/Collation.java 8dffbb00938007ad0967b2ab424d3c908413af1bbd3d212b9c9899910f1218d1
@@ -2071,8 +2071,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 8b322d92e247be606f83977767dc361ee4f7bc819122a630bdaa1110177db9b8
-R 42363264995216c484a93a93750ae3b7
+P 9faca5d9ed4a749421e08bd1da8b7672c0fd31366124fdb613c46e19dece0fc1
+R 2f7ebe9a2d19552b91a45c55eec1bac7
 U stephan
-Z e56a10315f9f662ddf790f3b196580e4
+Z 7f375306dd5a29931e39a5081c815b0c
 # Remove this line to create a well-formed Fossil manifest.
index 63395cf23e37679ef02215dbcf49bf83fef228f9..a908ec37fdee9be12e61c5f373e977ac37e552d3 100644 (file)
@@ -1 +1 @@
-9faca5d9ed4a749421e08bd1da8b7672c0fd31366124fdb613c46e19dece0fc1
\ No newline at end of file
+a5d68a6b64abe3c2dfc3a32157f70fd8a4ad89feef2510b3bbb2d86b325d51ae
\ No newline at end of file