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 Original line Diff line number Diff line
@@ -29,9 +29,13 @@ import android.net.Uri;


import org.dmfs.iterables.SingletonIterable;
import org.dmfs.iterables.SingletonIterable;
import org.dmfs.iterables.decorators.Flattened;
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.ArrayList;
import java.util.HashSet;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import java.util.Set;




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


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

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




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

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




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

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

            return count;
            return count;
        });
    }
    }




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

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




    @Override
    @Override
    public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) throws OperationApplicationException
    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 ypCount = 0;
                    int opCount = 0;
                    int opCount = 0;
@@ -300,6 +314,7 @@ abstract class SQLiteContentProvider extends ContentProvider
                        db.endTransaction();
                        db.endTransaction();
                        onEndTransaction(callerIsSyncAdapter);
                        onEndTransaction(callerIsSyncAdapter);
                    }
                    }
                });
    }
    }




+4 −3
Original line number Original line 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.FTSDatabaseHelper;
import org.dmfs.provider.tasks.model.TaskAdapter;
import org.dmfs.provider.tasks.model.TaskAdapter;
import org.dmfs.provider.tasks.processors.EntityProcessor;
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)
    public TaskAdapter insert(SQLiteDatabase db, TaskAdapter task, boolean isSyncAdapter)
    {
    {
        TaskAdapter result = mDelegate.insert(db, task, isSyncAdapter);
        TaskAdapter result = mDelegate.insert(db, task, isSyncAdapter);
        FTSDatabaseHelper.updateTaskFTSEntries(db, task);
        new Profiled("InsertFTS").run(() -> FTSDatabaseHelper.updateTaskFTSEntries(db, task));
        return result;
        return result;
    }
    }


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


@@ -60,6 +61,6 @@ public final class Searchable implements EntityProcessor<TaskAdapter>
    @Override
    @Override
    public void delete(SQLiteDatabase db, TaskAdapter entityAdapter, boolean isSyncAdapter)
    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 Original line 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));
        }
    }

}