Merge "Added perf test to measure bytes written"
This commit is contained in:
committed by
Android (Google) Code Review
commit
b070d682d1
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package android.database;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.os.Bundle;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.filters.LargeTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Performance tests for measuring amount of data written during typical DB operations
|
||||
*
|
||||
* <p>To run: bit CorePerfTests:android.database.SQLiteDatabaseIoPerfTest
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@LargeTest
|
||||
public class SQLiteDatabaseIoPerfTest {
|
||||
private static final String TAG = "SQLiteDatabaseIoPerfTest";
|
||||
private static final String DB_NAME = "db_io_perftest";
|
||||
private static final int DEFAULT_DATASET_SIZE = 500;
|
||||
|
||||
private Long mWriteBytes;
|
||||
|
||||
private SQLiteDatabase mDatabase;
|
||||
private Context mContext;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mContext = InstrumentationRegistry.getTargetContext();
|
||||
mContext.deleteDatabase(DB_NAME);
|
||||
mDatabase = mContext.openOrCreateDatabase(DB_NAME, Context.MODE_PRIVATE, null);
|
||||
mDatabase.execSQL("CREATE TABLE T1 "
|
||||
+ "(_ID INTEGER PRIMARY KEY, COL_A INTEGER, COL_B VARCHAR(100), COL_C REAL)");
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
mDatabase.close();
|
||||
mContext.deleteDatabase(DB_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDatabaseModifications() {
|
||||
startMeasuringWrites();
|
||||
ContentValues cv = new ContentValues();
|
||||
String[] whereArg = new String[1];
|
||||
for (int i = 0; i < DEFAULT_DATASET_SIZE; i++) {
|
||||
cv.put("_ID", i);
|
||||
cv.put("COL_A", i);
|
||||
cv.put("COL_B", "NewValue");
|
||||
cv.put("COL_C", 1.0);
|
||||
assertEquals(i, mDatabase.insert("T1", null, cv));
|
||||
}
|
||||
cv = new ContentValues();
|
||||
for (int i = 0; i < DEFAULT_DATASET_SIZE; i++) {
|
||||
cv.put("COL_B", "UpdatedValue");
|
||||
cv.put("COL_C", 1.1);
|
||||
whereArg[0] = String.valueOf(i);
|
||||
assertEquals(1, mDatabase.update("T1", cv, "_ID=?", whereArg));
|
||||
}
|
||||
for (int i = 0; i < DEFAULT_DATASET_SIZE; i++) {
|
||||
whereArg[0] = String.valueOf(i);
|
||||
assertEquals(1, mDatabase.delete("T1", "_ID=?", whereArg));
|
||||
}
|
||||
// Make sure all changes are written to disk
|
||||
mDatabase.close();
|
||||
long bytes = endMeasuringWrites();
|
||||
sendResults("testDatabaseModifications" , bytes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsertsWithTransactions() {
|
||||
startMeasuringWrites();
|
||||
final int txSize = 10;
|
||||
ContentValues cv = new ContentValues();
|
||||
for (int i = 0; i < DEFAULT_DATASET_SIZE * 5; i++) {
|
||||
if (i % txSize == 0) {
|
||||
mDatabase.beginTransaction();
|
||||
}
|
||||
if (i % txSize == txSize-1) {
|
||||
mDatabase.setTransactionSuccessful();
|
||||
mDatabase.endTransaction();
|
||||
|
||||
}
|
||||
cv.put("_ID", i);
|
||||
cv.put("COL_A", i);
|
||||
cv.put("COL_B", "NewValue");
|
||||
cv.put("COL_C", 1.0);
|
||||
assertEquals(i, mDatabase.insert("T1", null, cv));
|
||||
}
|
||||
// Make sure all changes are written to disk
|
||||
mDatabase.close();
|
||||
long bytes = endMeasuringWrites();
|
||||
sendResults("testInsertsWithTransactions" , bytes);
|
||||
}
|
||||
|
||||
private void startMeasuringWrites() {
|
||||
Preconditions.checkState(mWriteBytes == null, "Measurement already started");
|
||||
mWriteBytes = getIoStats().get("write_bytes");
|
||||
}
|
||||
|
||||
private long endMeasuringWrites() {
|
||||
Preconditions.checkState(mWriteBytes != null, "Measurement wasn't started");
|
||||
Long newWriteBytes = getIoStats().get("write_bytes");
|
||||
return newWriteBytes - mWriteBytes;
|
||||
}
|
||||
|
||||
private void sendResults(String testName, long writeBytes) {
|
||||
Log.i(TAG, testName + " write_bytes: " + writeBytes);
|
||||
Bundle status = new Bundle();
|
||||
status.putLong("write_bytes", writeBytes);
|
||||
InstrumentationRegistry.getInstrumentation().sendStatus(Activity.RESULT_OK, status);
|
||||
}
|
||||
|
||||
private static Map<String, Long> getIoStats() {
|
||||
String ioStat = "/proc/self/io";
|
||||
Map<String, Long> results = new ArrayMap<>();
|
||||
try {
|
||||
List<String> lines = Files.readAllLines(new File(ioStat).toPath());
|
||||
for (String line : lines) {
|
||||
line = line.trim();
|
||||
String[] split = line.split(":");
|
||||
if (split.length == 2) {
|
||||
try {
|
||||
String key = split[0].trim();
|
||||
Long value = Long.valueOf(split[1].trim());
|
||||
results.put(key, value);
|
||||
} catch (NumberFormatException e) {
|
||||
Log.e(TAG, "Cannot parse number from " + line);
|
||||
}
|
||||
} else if (line.isEmpty()) {
|
||||
Log.e(TAG, "Cannot parse line " + line);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Can't read: " + ioStat, e);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user