Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit 3a906fc2 authored by Marten Gajda's avatar Marten Gajda Committed by GitHub
Browse files

Add some simple profiling for provider operations. supports #738 (#762)

In order to evaluate the provider performance and its impact on the UX this commit adds some simple profiling statments which measure the execution time of certain operations and write them to logcat.
Hopefully this helps a but to detect slow operations and bottlenecks.
parent 1db690bb
Loading
Loading
Loading
Loading
+127 −112
Original line number Diff line number Diff line
@@ -29,9 +29,13 @@ import android.net.Uri;

import org.dmfs.iterables.SingletonIterable;
import org.dmfs.iterables.decorators.Flattened;
import org.dmfs.jems.fragile.Fragile;
import org.dmfs.jems.single.Single;
import org.dmfs.provider.tasks.utils.Profiled;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;


@@ -141,6 +145,8 @@ abstract class SQLiteContentProvider extends ContentProvider

    @Override
    public Uri insert(Uri uri, ContentValues values)
    {
        return new Profiled("Insert").run((Single<Uri>) () ->
        {
            Uri result;
            boolean callerIsSyncAdapter = isCallerSyncAdapter(uri);
@@ -158,7 +164,6 @@ abstract class SQLiteContentProvider extends ContentProvider
                {
                    db.endTransaction();
                }

                onEndTransaction(callerIsSyncAdapter);
            }
            else
@@ -166,11 +171,14 @@ abstract class SQLiteContentProvider extends ContentProvider
                result = insertInTransaction(db, uri, values, callerIsSyncAdapter);
            }
            return result;
        });
    }


    @Override
    public int bulkInsert(Uri uri, ContentValues[] values)
    {
        return new Profiled("BulkInsert").run((Single<Integer>) () ->
        {
            int numValues = values.length;
            boolean callerIsSyncAdapter = isCallerSyncAdapter(uri);
@@ -189,14 +197,16 @@ abstract class SQLiteContentProvider extends ContentProvider
            {
                db.endTransaction();
            }

            onEndTransaction(callerIsSyncAdapter);
            return numValues;
        });
    }


    @Override
    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)
    {
        return new Profiled("Update").run((Single<Integer>) () ->
        {
            int count;
            boolean callerIsSyncAdapter = isCallerSyncAdapter(uri);
@@ -214,20 +224,21 @@ abstract class SQLiteContentProvider extends ContentProvider
                {
                    db.endTransaction();
                }

                onEndTransaction(callerIsSyncAdapter);
            }
            else
            {
                count = updateInTransaction(db, uri, values, selection, selectionArgs, callerIsSyncAdapter);
            }

            return count;
        });
    }


    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs)
    {
        return new Profiled("Delete").run((Single<Integer>) () ->
        {
            int count;
            boolean callerIsSyncAdapter = isCallerSyncAdapter(uri);
@@ -245,7 +256,6 @@ abstract class SQLiteContentProvider extends ContentProvider
                {
                    db.endTransaction();
                }

                onEndTransaction(callerIsSyncAdapter);
            }
            else
@@ -253,11 +263,15 @@ abstract class SQLiteContentProvider extends ContentProvider
                count = deleteInTransaction(db, uri, selection, selectionArgs, callerIsSyncAdapter);
            }
            return count;
        });
    }


    @Override
    public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) throws OperationApplicationException
    {
        return new Profiled(String.format(Locale.ENGLISH, "Batch of %d operations", operations.size())).run(
                (Fragile<ContentProviderResult[], OperationApplicationException>) () ->
                {
                    int ypCount = 0;
                    int opCount = 0;
@@ -300,6 +314,7 @@ abstract class SQLiteContentProvider extends ContentProvider
                        db.endTransaction();
                        onEndTransaction(callerIsSyncAdapter);
                    }
                });
    }


+4 −3
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.database.sqlite.SQLiteDatabase;
import org.dmfs.provider.tasks.FTSDatabaseHelper;
import org.dmfs.provider.tasks.model.TaskAdapter;
import org.dmfs.provider.tasks.processors.EntityProcessor;
import org.dmfs.provider.tasks.utils.Profiled;


/**
@@ -43,7 +44,7 @@ public final class Searchable implements EntityProcessor<TaskAdapter>
    public TaskAdapter insert(SQLiteDatabase db, TaskAdapter task, boolean isSyncAdapter)
    {
        TaskAdapter result = mDelegate.insert(db, task, isSyncAdapter);
        FTSDatabaseHelper.updateTaskFTSEntries(db, task);
        new Profiled("InsertFTS").run(() -> FTSDatabaseHelper.updateTaskFTSEntries(db, task));
        return result;
    }

@@ -52,7 +53,7 @@ public final class Searchable implements EntityProcessor<TaskAdapter>
    public TaskAdapter update(SQLiteDatabase db, TaskAdapter task, boolean isSyncAdapter)
    {
        TaskAdapter result = mDelegate.update(db, task, isSyncAdapter);
        FTSDatabaseHelper.updateTaskFTSEntries(db, task);
        new Profiled("UpdateFTS").run(() -> FTSDatabaseHelper.updateTaskFTSEntries(db, task));
        return result;
    }

@@ -60,6 +61,6 @@ public final class Searchable implements EntityProcessor<TaskAdapter>
    @Override
    public void delete(SQLiteDatabase db, TaskAdapter entityAdapter, boolean isSyncAdapter)
    {
        mDelegate.delete(db, entityAdapter, isSyncAdapter);
        new Profiled("DeleteFTS").run(() -> mDelegate.delete(db, entityAdapter, isSyncAdapter));
    }
}
+80 −0
Original line number Diff line number Diff line
/*
 * Copyright 2019 dmfs GmbH
 *
 * 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 org.dmfs.provider.tasks.utils;

import android.util.Log;

import org.dmfs.jems.fragile.Fragile;
import org.dmfs.jems.single.Single;

import java.util.Locale;


/**
 * A simple class to measure the execution time of a given piece of code.
 *
 * @author Marten Gajda
 */
public final class Profiled
{
    private final String mSubject;


    public Profiled(String subject)
    {
        mSubject = subject;
    }


    public void run(Runnable runnable)
    {
        long start = System.currentTimeMillis();
        runnable.run();
        Log.d("Profiled", String.format(Locale.ENGLISH, "Time spent in %s: %d milliseconds", mSubject, System.currentTimeMillis() - start));
    }


    public <V> V run(Single<V> runnable)
    {

        long start = System.currentTimeMillis();
        try
        {
            return runnable.value();
        }
        finally
        {
            Log.d("Profiled", String.format(Locale.ENGLISH, "Time spent in %s: %d milliseconds", mSubject, System.currentTimeMillis() - start));
        }
    }


    public <V, E extends Exception> V run(Fragile<V, E> runnable) throws E
    {

        long start = System.currentTimeMillis();
        try
        {
            return runnable.value();
        }
        finally
        {
            Log.d("Profiled", String.format(Locale.ENGLISH, "Time spent in %s: %d milliseconds", mSubject, System.currentTimeMillis() - start));
        }
    }

}