Home | History | Annotate | Download | only in util
      1 /*
      2  * Copyright (C) 2018 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 package com.android.internal.util;
     17 
     18 import android.os.SystemClock;
     19 import android.util.SparseBooleanArray;
     20 import android.util.SparseLongArray;
     21 
     22 import java.io.PrintWriter;
     23 
     24 public class ProviderAccessStats {
     25     private final Object mLock = new Object();
     26 
     27     private final long mStartUptime = SystemClock.uptimeMillis();
     28 
     29     private final SparseBooleanArray mAllCallingUids = new SparseBooleanArray();
     30     private final SparseLongArray mQueryStats = new SparseLongArray(16);
     31     private final SparseLongArray mBatchStats = new SparseLongArray(0);
     32     private final SparseLongArray mInsertStats = new SparseLongArray(0);
     33     private final SparseLongArray mUpdateStats = new SparseLongArray(0);
     34     private final SparseLongArray mDeleteStats = new SparseLongArray(0);
     35     private final SparseLongArray mInsertInBatchStats = new SparseLongArray(0);
     36     private final SparseLongArray mUpdateInBatchStats = new SparseLongArray(0);
     37     private final SparseLongArray mDeleteInBatchStats = new SparseLongArray(0);
     38 
     39     private final SparseLongArray mOperationDurationMillis = new SparseLongArray(16);
     40 
     41     private static class PerThreadData {
     42         public int nestCount;
     43         public long startUptimeMillis;
     44     }
     45 
     46     private final ThreadLocal<PerThreadData> mThreadLocal =
     47             ThreadLocal.withInitial(() -> new PerThreadData());
     48 
     49     private void incrementStats(int callingUid, SparseLongArray stats) {
     50         synchronized (mLock) {
     51             stats.put(callingUid, stats.get(callingUid) + 1);
     52             mAllCallingUids.put(callingUid, true);
     53         }
     54 
     55         final PerThreadData data = mThreadLocal.get();
     56         data.nestCount++;
     57         if (data.nestCount == 1) {
     58             data.startUptimeMillis = SystemClock.uptimeMillis();
     59         }
     60     }
     61 
     62     private void incrementStats(int callingUid, boolean inBatch,
     63             SparseLongArray statsNonBatch, SparseLongArray statsInBatch) {
     64         incrementStats(callingUid, inBatch ? statsInBatch : statsNonBatch);
     65     }
     66 
     67     public final void incrementInsertStats(int callingUid, boolean inBatch) {
     68         incrementStats(callingUid, inBatch, mInsertStats, mInsertInBatchStats);
     69     }
     70 
     71     public final void incrementUpdateStats(int callingUid, boolean inBatch) {
     72         incrementStats(callingUid, inBatch, mUpdateStats, mUpdateInBatchStats);
     73     }
     74 
     75     public final void incrementDeleteStats(int callingUid, boolean inBatch) {
     76         incrementStats(callingUid, inBatch, mDeleteStats, mDeleteInBatchStats);
     77     }
     78 
     79     public final void incrementQueryStats(int callingUid) {
     80         incrementStats(callingUid, mQueryStats);
     81     }
     82 
     83     public final void incrementBatchStats(int callingUid) {
     84         incrementStats(callingUid, mBatchStats);
     85     }
     86 
     87     public void finishOperation(int callingUid) {
     88         final PerThreadData data = mThreadLocal.get();
     89         data.nestCount--;
     90         if (data.nestCount == 0) {
     91             // Because we only have millisecond granularity, let's always attribute at least 1ms
     92             // for each operation.
     93             final long duration = Math.max(1, SystemClock.uptimeMillis() - data.startUptimeMillis);
     94 
     95             synchronized (mLock) {
     96                 mOperationDurationMillis.put(callingUid,
     97                         mOperationDurationMillis.get(callingUid) + duration);
     98             }
     99         }
    100     }
    101 
    102     public void dump(PrintWriter pw, String prefix) {
    103         synchronized (mLock) {
    104             pw.print("  Process uptime: ");
    105             pw.print((SystemClock.uptimeMillis() - mStartUptime) / (60 * 1000));
    106             pw.println(" minutes");
    107             pw.println();
    108 
    109             pw.print(prefix);
    110             pw.println("Client activities:");
    111             pw.print(prefix);
    112             pw.println("  UID        Query  Insert Update Delete   Batch Insert Update Delete"
    113                     + "          Sec");
    114             for (int i = 0; i < mAllCallingUids.size(); i++) {
    115                 final int uid = mAllCallingUids.keyAt(i);
    116                 pw.print(prefix);
    117                 pw.println(String.format(
    118                         "  %-9d %6d  %6d %6d %6d  %6d %6d %6d %6d %12.3f",
    119                         uid,
    120                         mQueryStats.get(uid),
    121                         mInsertStats.get(uid),
    122                         mUpdateStats.get(uid),
    123                         mDeleteStats.get(uid),
    124                         mBatchStats.get(uid),
    125                         mInsertInBatchStats.get(uid),
    126                         mUpdateInBatchStats.get(uid),
    127                         mDeleteInBatchStats.get(uid),
    128                         (mOperationDurationMillis.get(uid) / 1000.0)
    129                 ));
    130             }
    131             pw.println();
    132         }
    133     }
    134 }
    135