blob: 916df351f095024c927c8e2b1aead87d3e1dff29 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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