Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tooling updates, database updates #13

Merged
merged 16 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 11 additions & 22 deletions .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,26 @@ name: Java CI with Gradle
on:
push:
pull_request:
workflow_dispatch: # Allow running manually from web UI

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Set up JDK 11
uses: actions/setup-java@v2
with:
java-version: '11'
distribution: 'adopt'
- name: Cache Gradle packages
uses: actions/cache@v2
- name: Check out
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4

- name: Set up JDK 17
uses: actions/setup-java@99b8673ff64fbf99d8d325f52d9a5bdedb8483e9 # v4.2.1
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Grant execute permission for gradlew
run: chmod +x gradlew
distribution: 'temurin'
java-version: '17'
cache: gradle

- name: Gradle Info
run: ./gradlew -version

- name: Build with Gradle
run: ./gradlew build
- name: Cleanup Gradle Cache
# Remove some files from the Gradle cache, so they aren't cached by GitHub Actions.
# Restoring these files from a GitHub Actions cache might cause problems for future builds.
run: |
rm -f ~/.gradle/caches/modules-2/modules-2.lock
rm -f ~/.gradle/caches/modules-2/gc.properties
36 changes: 21 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
Performance Benchmarks
======================
This is an Android app to measure object persistence performance of ObjectBox, Realm, SQLite (with greenDAO as ORM).
# ObjectBox Java Database Performance Benchmarks

Results are printed on the UI and saved as .tsv files.
The files are located in the external storage and can be easily imported into a spreadsheet.
This is an Android app to measure object persistence performance of
- [ObjectBox](/app/src/main/java/io/objectbox/performanceapp/objectbox)
- [Realm](/app/src/main/java/io/objectbox/performanceapp/realm)
- [SQLite using Room](/app/src/main/java/io/objectbox/performanceapp/room)
- [SQLite using greenDAO](/app/src/main/java/io/objectbox/performanceapp/greendao) (deprecated)

How to get good results
-----------------------
* Tests perform differently when multiple products are selected:
Thus, for more representable results, you should only run a single product at a time.
* Go into air plane mode to avoid background apps doing sync over the network
* Screen must be on at all times (plug device in)
* Beware of lazy loaded properties (e.g. live objects on Realm):
loading objects seems very fast because no property data is actually loaded.
Thus it makes more sense to also access properties (at least once) and look add up values for load+access.
* Also consider general notes for [benchmarking on Android](http://greenrobot.org/android/benchmarking-on-android/)
Results are printed on the UI and saved as tab-separated files (`.tvs`) that can be easily imported
into a spreadsheet. The files are located on external storage.

<img src="android-perf-screenshot.png" height="540"/>

## How to get good results

* Tests perform differently when multiple databases are selected:
For comparable results, run only a single database at a time.
* Put the test device into air plane mode to avoid background apps doing sync over the network.
* Screen must be on at all times (e.g. plug the device in).
* Beware of lazy loaded data (e.g. properties on live objects of Realm):
loading objects may seem very fast because no data is actually loaded.
For better comparison it may be necessary to access data (at least once) and combine load and access time to get actual read time.
* We also have written some general notes on [benchmarking on Android](https://greenrobot.org/android/benchmarking-on-android/).
Binary file added android-perf-screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
57 changes: 0 additions & 57 deletions app/build.gradle

This file was deleted.

64 changes: 64 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
plugins {
id("com.android.application")
id("io.objectbox")
id("realm-android")
}

android {
namespace = "io.objectbox.performanceapp"
compileSdk = 34 // Android 14

buildFeatures {
viewBinding = true
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

defaultConfig {
applicationId = "io.objectbox.performanceapp"
minSdk = 19 // Android 4.4
targetSdk = 34 // Android 14
versionCode = 1
versionName = "1.0"

javaCompileOptions {
annotationProcessorOptions {
arguments(mapOf("room.schemaLocation" to "$projectDir/schemas"))
}
}
}

buildTypes {
getByName("release") {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
signingConfig = signingConfigs.getByName("debug")
}
create("releaseDebugCert") {
initWith(getByName("release"))
// Just to use without checkjni
signingConfig = signingConfigs.getByName("debug")
}
create("debugJniNoDebug") {
initWith(getByName("debug"))
// Just to use without checkjni
isJniDebuggable = false
}
}
}

// Print deprecation warnings like Kotlin
tasks.withType(JavaCompile::class).configureEach {
options.isDeprecation = true
}

dependencies {
implementation("androidx.preference:preference:1.2.1")
implementation("androidx.room:room-runtime:2.6.1")
annotationProcessor("androidx.room:room-compiler:2.6.1")
implementation("org.greenrobot:greendao:3.3.0")
implementation("org.greenrobot:essentials:3.1.0")
}
4 changes: 2 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="io.objectbox.performanceapp"
xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<!-- Note: We do not request the permission on Android 6+ - user has to add it manually using App Info-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Expand All @@ -13,6 +12,7 @@
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:exported="true"
android:windowSoftInputMode="stateHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2017 ObjectBox Ltd. All rights reserved.
* Copyright 2017-2024 ObjectBox Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -20,7 +20,6 @@
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.ArrayAdapter;
Expand All @@ -29,6 +28,7 @@
import java.util.ArrayList;
import java.util.List;

import androidx.preference.PreferenceManager;
import io.objectbox.performanceapp.PerfTestRunner.Callback;
import io.objectbox.performanceapp.databinding.ActivityMainBinding;
import io.objectbox.performanceapp.greendao.GreendaoPerfTest;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2017 ObjectBox Ltd. All rights reserved.
* Copyright 2017-2024 ObjectBox Ltd. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -250,15 +250,17 @@ private void runQueryByString() {
startBenchmark("query");

long entitiesFound = 0;
Query<SimpleEntity> query = box.query()
.equal(SimpleEntity_.simpleString, "", CASE_SENSITIVE)
.parameterAlias("string")
.build();
for (int i = 0; i < stringsToLookup.length; i++) {
query.setParameter("string", stringsToLookup[i]);
List<SimpleEntity> result = query.find();
accessAll(result);
entitiesFound += result.size();
try (Query<SimpleEntity> query = box.query(
SimpleEntity_.simpleString
.equal("", CASE_SENSITIVE)
.alias("string")
).build()) {
for (int i = 0; i < stringsToLookup.length; i++) {
query.setParameter("string", stringsToLookup[i]);
List<SimpleEntity> result = query.find();
accessAll(result);
entitiesFound += result.size();
}
}
stopBenchmark();
log("Entities found: " + entitiesFound);
Expand All @@ -277,15 +279,17 @@ private void runQueryByInteger() {

startBenchmark("query");
long entitiesFound = 0;
Query<SimpleEntity> query = box.query()
.equal(SimpleEntity_.simpleInt, 0)
.parameterAlias("int")
.build();
for (int i = 0; i < numberEntities; i++) {
query.setParameter("int", valuesToLookup[i]);
List<SimpleEntity> result = query.find();
accessAll(result);
entitiesFound += result.size();
try (Query<SimpleEntity> query = box.query(
SimpleEntity_.simpleInt
.equal(0)
.alias("int")
).build()) {
for (int i = 0; i < numberEntities; i++) {
query.setParameter("int", valuesToLookup[i]);
List<SimpleEntity> result = query.find();
accessAll(result);
entitiesFound += result.size();
}
}
stopBenchmark();
log("Entities found: " + entitiesFound);
Expand Down Expand Up @@ -321,15 +325,17 @@ private void runQueryByStringIndexed() {

startBenchmark("query");
long entitiesFound = 0;
Query<SimpleEntityIndexed> query = boxIndexed.query()
.equal(SimpleEntityIndexed_.simpleString, "", CASE_SENSITIVE)
.parameterAlias("string")
.build();
for (int i = 0; i < stringsToLookup.length; i++) {
query.setParameter("string", stringsToLookup[i]);
List<SimpleEntityIndexed> result = query.find();
accessAllIndexed(result);
entitiesFound += result.size();
try (Query<SimpleEntityIndexed> query = boxIndexed.query(
SimpleEntityIndexed_.simpleString
.equal("", CASE_SENSITIVE)
.alias("string")
).build()) {
for (int i = 0; i < stringsToLookup.length; i++) {
query.setParameter("string", stringsToLookup[i]);
List<SimpleEntityIndexed> result = query.find();
accessAllIndexed(result);
entitiesFound += result.size();
}
}
stopBenchmark();
log("Entities found: " + entitiesFound);
Expand All @@ -345,15 +351,17 @@ private void runQueryByIntegerIndexed() {

startBenchmark("query");
long entitiesFound = 0;
Query<SimpleEntityIndexed> query = boxIndexed.query()
.equal(SimpleEntityIndexed_.simpleInt, 0)
.parameterAlias("int")
.build();
for (int i = 0; i < numberEntities; i++) {
query.setParameter("int", valuesToLookup[i]);
List<SimpleEntityIndexed> result = query.find();
accessAllIndexed(result);
entitiesFound += result.size();
try (Query<SimpleEntityIndexed> query = boxIndexed.query(
SimpleEntityIndexed_.simpleInt
.equal(0)
.alias("int")
).build()) {
for (int i = 0; i < numberEntities; i++) {
query.setParameter("int", valuesToLookup[i]);
List<SimpleEntityIndexed> result = query.find();
accessAllIndexed(result);
entitiesFound += result.size();
}
}
stopBenchmark();
log("Entities found: " + entitiesFound);
Expand Down
Loading