android_database_SQLiteDebug.cpp revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <JNIHelp.h> 18#include <jni.h> 19#include <utils/misc.h> 20#include <stdio.h> 21#include <stdlib.h> 22#include <string.h> 23#include <unistd.h> 24#include <cutils/mspace.h> 25#include <utils/Log.h> 26 27#include <sqlite3.h> 28 29// From mem_mspace.c in libsqlite 30extern "C" mspace sqlite3_get_mspace(); 31 32// From sqlite.c, hacked in for Android 33extern "C" void sqlite3_get_pager_stats(sqlite3_int64 * totalBytesOut, 34 sqlite3_int64 * referencedBytesOut, 35 sqlite3_int64 * dbBytesOut, 36 int * numPagersOut); 37 38namespace android { 39 40static jfieldID gTotalBytesField; 41static jfieldID gReferencedBytesField; 42static jfieldID gDbBytesField; 43static jfieldID gNumPagersField; 44 45 46#define USE_MSPACE 0 47 48static void getPagerStats(JNIEnv *env, jobject clazz, jobject statsObj) 49{ 50 sqlite3_int64 totalBytes; 51 sqlite3_int64 referencedBytes; 52 sqlite3_int64 dbBytes; 53 int numPagers; 54 55 sqlite3_get_pager_stats(&totalBytes, &referencedBytes, &dbBytes, 56 &numPagers); 57 58 env->SetLongField(statsObj, gTotalBytesField, totalBytes); 59 env->SetLongField(statsObj, gReferencedBytesField, referencedBytes); 60 env->SetLongField(statsObj, gDbBytesField, dbBytes); 61 env->SetIntField(statsObj, gNumPagersField, numPagers); 62} 63 64static jlong getHeapSize(JNIEnv *env, jobject clazz) 65{ 66#if !NO_MALLINFO 67 struct mallinfo info = mspace_mallinfo(sqlite3_get_mspace()); 68 struct mallinfo info = dlmallinfo(); 69 return (jlong) info.usmblks; 70#elif USE_MSPACE 71 mspace space = sqlite3_get_mspace(); 72 if (space != 0) { 73 return mspace_footprint(space); 74 } else { 75 return 0; 76 } 77#else 78 return 0; 79#endif 80} 81 82static jlong getHeapAllocatedSize(JNIEnv *env, jobject clazz) 83{ 84#if !NO_MALLINFO 85 struct mallinfo info = mspace_mallinfo(sqlite3_get_mspace()); 86 return (jlong) info.uordblks; 87#else 88 return sqlite3_memory_used(); 89#endif 90} 91 92static jlong getHeapFreeSize(JNIEnv *env, jobject clazz) 93{ 94#if !NO_MALLINFO 95 struct mallinfo info = mspace_mallinfo(sqlite3_get_mspace()); 96 return (jlong) info.fordblks; 97#else 98 return getHeapSize(env, clazz) - sqlite3_memory_used(); 99#endif 100} 101 102static int read_mapinfo(FILE *fp, 103 int *sharedPages, int *privatePages) 104{ 105 char line[1024]; 106 int len; 107 int skip; 108 109 unsigned start = 0, size = 0, resident = 0; 110 unsigned shared_clean = 0, shared_dirty = 0; 111 unsigned private_clean = 0, private_dirty = 0; 112 unsigned referenced = 0; 113 114 int isAnon = 0; 115 int isHeap = 0; 116 117again: 118 skip = 0; 119 120 if(fgets(line, 1024, fp) == 0) return 0; 121 122 len = strlen(line); 123 if (len < 1) return 0; 124 line[--len] = 0; 125 126 /* ignore guard pages */ 127 if (line[18] == '-') skip = 1; 128 129 start = strtoul(line, 0, 16); 130 131 if (len > 50 && !strncmp(line + 49, "/tmp/sqlite-heap", strlen("/tmp/sqlite-heap"))) { 132 isHeap = 1; 133 } 134 135 if (fgets(line, 1024, fp) == 0) return 0; 136 if (sscanf(line, "Size: %d kB", &size) != 1) return 0; 137 if (fgets(line, 1024, fp) == 0) return 0; 138 if (sscanf(line, "Rss: %d kB", &resident) != 1) return 0; 139 if (fgets(line, 1024, fp) == 0) return 0; 140 if (sscanf(line, "Shared_Clean: %d kB", &shared_clean) != 1) return 0; 141 if (fgets(line, 1024, fp) == 0) return 0; 142 if (sscanf(line, "Shared_Dirty: %d kB", &shared_dirty) != 1) return 0; 143 if (fgets(line, 1024, fp) == 0) return 0; 144 if (sscanf(line, "Private_Clean: %d kB", &private_clean) != 1) return 0; 145 if (fgets(line, 1024, fp) == 0) return 0; 146 if (sscanf(line, "Private_Dirty: %d kB", &private_dirty) != 1) return 0; 147 if (fgets(line, 1024, fp) == 0) return 0; 148 if (sscanf(line, "Referenced: %d kB", &referenced) != 1) return 0; 149 150 if (skip) { 151 goto again; 152 } 153 154 if (isHeap) { 155 *sharedPages += shared_dirty; 156 *privatePages += private_dirty; 157 } 158 return 1; 159} 160 161static void load_maps(int pid, int *sharedPages, int *privatePages) 162{ 163 char tmp[128]; 164 FILE *fp; 165 166 sprintf(tmp, "/proc/%d/smaps", pid); 167 fp = fopen(tmp, "r"); 168 if (fp == 0) return; 169 170 while (read_mapinfo(fp, sharedPages, privatePages) != 0) { 171 // Do nothing 172 } 173 fclose(fp); 174} 175 176static void getHeapDirtyPages(JNIEnv *env, jobject clazz, jintArray pages) 177{ 178 int _pages[2]; 179 180 _pages[0] = 0; 181 _pages[1] = 0; 182 183 load_maps(getpid(), &_pages[0], &_pages[1]); 184 185 // Convert from kbytes to 4K pages 186 _pages[0] /= 4; 187 _pages[1] /= 4; 188 189 env->SetIntArrayRegion(pages, 0, 2, _pages); 190} 191 192/* 193 * JNI registration. 194 */ 195 196static JNINativeMethod gMethods[] = 197{ 198 { "getPagerStats", "(Landroid/database/sqlite/SQLiteDebug$PagerStats;)V", 199 (void*) getPagerStats }, 200 { "getHeapSize", "()J", (void*) getHeapSize }, 201 { "getHeapAllocatedSize", "()J", (void*) getHeapAllocatedSize }, 202 { "getHeapFreeSize", "()J", (void*) getHeapFreeSize }, 203 { "getHeapDirtyPages", "([I)V", (void*) getHeapDirtyPages }, 204}; 205 206int register_android_database_SQLiteDebug(JNIEnv *env) 207{ 208 jclass clazz; 209 210 clazz = env->FindClass("android/database/sqlite/SQLiteDebug$PagerStats"); 211 if (clazz == NULL) { 212 LOGE("Can't find android/database/sqlite/SQLiteDebug$PagerStats"); 213 return -1; 214 } 215 216 gTotalBytesField = env->GetFieldID(clazz, "totalBytes", "J"); 217 if (gTotalBytesField == NULL) { 218 LOGE("Can't find totalBytes"); 219 return -1; 220 } 221 222 gReferencedBytesField = env->GetFieldID(clazz, "referencedBytes", "J"); 223 if (gReferencedBytesField == NULL) { 224 LOGE("Can't find referencedBytes"); 225 return -1; 226 } 227 228 gDbBytesField = env->GetFieldID(clazz, "databaseBytes", "J"); 229 if (gDbBytesField == NULL) { 230 LOGE("Can't find databaseBytes"); 231 return -1; 232 } 233 234 gNumPagersField = env->GetFieldID(clazz, "numPagers", "I"); 235 if (gNumPagersField == NULL) { 236 LOGE("Can't find numPagers"); 237 return -1; 238 } 239 240 return jniRegisterNativeMethods(env, "android/database/sqlite/SQLiteDebug", 241 gMethods, NELEM(gMethods)); 242} 243 244} // namespace android 245