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

Commit a64fd1b4 authored by Dmitri Plotnikov's avatar Dmitri Plotnikov Committed by Android (Google) Code Review
Browse files

Merge "Use varint to record cpu usage data and measured energy in battery history"

parents 59182b3b d8371008
Loading
Loading
Loading
Loading
+74 −7
Original line number Diff line number Diff line
@@ -79,7 +79,7 @@ public class BatteryStatsHistory {
    private static final String TAG = "BatteryStatsHistory";

    // Current on-disk Parcel version. Must be updated when the format of the parcelable changes
    private static final int VERSION = 208;
    private static final int VERSION = 209;

    private static final String HISTORY_DIR = "battery-history";
    private static final String FILE_SUFFIX = ".bin";
@@ -198,6 +198,7 @@ public class BatteryStatsHistory {
    private long mHistoryBaseTimeMs;
    private boolean mMeasuredEnergyHeaderWritten = false;
    private boolean mCpuUsageHeaderWritten = false;
    private final VarintParceler mVarintParceler = new VarintParceler();

    private byte mLastHistoryStepLevel = 0;

@@ -1665,9 +1666,7 @@ public class BatteryStatsHistory {
                    }
                    mMeasuredEnergyHeaderWritten = true;
                }
                for (long chargeUC : cur.measuredEnergyDetails.chargeUC) {
                    dest.writeLong(chargeUC);
                }
                mVarintParceler.writeLongArray(dest, cur.measuredEnergyDetails.chargeUC);
            }

            if (cur.cpuUsageDetails != null) {
@@ -1679,9 +1678,7 @@ public class BatteryStatsHistory {
                    mCpuUsageHeaderWritten = true;
                }
                dest.writeInt(cur.cpuUsageDetails.uid);
                for (long cpuUsageMs: cur.cpuUsageDetails.cpuUsageMs) {
                    dest.writeLong(cpuUsageMs);
                }
                mVarintParceler.writeLongArray(dest, cur.cpuUsageDetails.cpuUsageMs);
            }
        }
    }
@@ -1930,4 +1927,74 @@ public class BatteryStatsHistory {
                    entry.getKey());
        }
    }

    /**
     * Writes/reads an array of longs into Parcel using a compact format, where small integers use
     * fewer bytes.  It is a bit more expensive than just writing the long into the parcel,
     * but at scale saves a lot of storage and allows recording of longer battery history.
     */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
    public static final class VarintParceler {
        /**
         * Writes an array of longs into Parcel using the varint format, see
         * https://developers.google.com/protocol-buffers/docs/encoding#varints
         */
        public void writeLongArray(Parcel parcel, long[] values) {
            int out = 0;
            int shift = 0;
            for (long value : values) {
                boolean done = false;
                while (!done) {
                    final byte b;
                    if ((value & ~0x7FL) == 0) {
                        b = (byte) value;
                        done = true;
                    } else {
                        b = (byte) (((int) value & 0x7F) | 0x80);
                        value >>>= 7;
                    }
                    if (shift == 32) {
                        parcel.writeInt(out);
                        shift = 0;
                        out = 0;
                    }
                    out |= (b & 0xFF) << shift;
                    shift += 8;
                }
            }
            if (shift != 0) {
                parcel.writeInt(out);
            }
        }

        /**
         * Reads a long written with {@link #writeLongArray}
         */
        public void readLongArray(Parcel parcel, long[] values) {
            int in = parcel.readInt();
            int available = 4;
            for (int i = 0; i < values.length; i++) {
                long result = 0;
                int shift;
                for (shift = 0; shift < 64; shift += 7) {
                    if (available == 0) {
                        in = parcel.readInt();
                        available = 4;
                    }
                    final byte b = (byte) in;
                    in >>= 8;
                    available--;

                    result |= (long) (b & 0x7F) << shift;
                    if ((b & 0x80) == 0) {
                        values[i] = result;
                        break;
                    }
                }
                if (shift >= 64) {
                    throw new ParcelFormatException("Invalid varint format");
                }
            }
        }
    }
}
+5 −7
Original line number Diff line number Diff line
@@ -35,6 +35,8 @@ public class BatteryStatsHistoryIterator {
    private final SparseArray<BatteryStats.HistoryTag> mHistoryTags = new SparseArray<>();
    private BatteryStats.MeasuredEnergyDetails mMeasuredEnergyDetails;
    private BatteryStats.CpuUsageDetails mCpuUsageDetails;
    private final BatteryStatsHistory.VarintParceler mVarintParceler =
            new BatteryStatsHistory.VarintParceler();

    public BatteryStatsHistoryIterator(@NonNull BatteryStatsHistory history) {
        mBatteryStatsHistory = history;
@@ -61,7 +63,7 @@ public class BatteryStatsHistoryIterator {
        return true;
    }

    void readHistoryDelta(Parcel src, BatteryStats.HistoryItem cur) {
    private void readHistoryDelta(Parcel src, BatteryStats.HistoryItem cur) {
        int firstToken = src.readInt();
        int deltaTimeToken = firstToken & BatteryStatsHistory.DELTA_TIME_MASK;
        cur.cmd = BatteryStats.HistoryItem.CMD_UPDATE;
@@ -226,9 +228,7 @@ public class BatteryStatsHistoryIterator {
                    throw new IllegalStateException("MeasuredEnergyDetails without a header");
                }

                for (int i = 0; i < mMeasuredEnergyDetails.chargeUC.length; i++) {
                    mMeasuredEnergyDetails.chargeUC[i] = src.readLong();
                }
                mVarintParceler.readLongArray(src, mMeasuredEnergyDetails.chargeUC);
                cur.measuredEnergyDetails = mMeasuredEnergyDetails;
            } else {
                cur.measuredEnergyDetails = null;
@@ -249,9 +249,7 @@ public class BatteryStatsHistoryIterator {
                }

                mCpuUsageDetails.uid = src.readInt();
                for (int i = 0; i < mCpuUsageDetails.cpuUsageMs.length; i++) {
                    mCpuUsageDetails.cpuUsageMs[i] = src.readLong();
                }
                mVarintParceler.readLongArray(src, mCpuUsageDetails.cpuUsageMs);
                cur.cpuUsageDetails = mCpuUsageDetails;
            } else {
                cur.cpuUsageDetails = null;
+64 −0
Original line number Diff line number Diff line
@@ -382,4 +382,68 @@ public class BatteryStatsHistoryTest {
        pw.flush();
        return writer.toString();
    }

    @Test
    public void testVarintParceler() {
        long[] values = {
                0,
                1,
                42,
                0x1234,
                0x10000000,
                0x12345678,
                0x7fffffff,
                0xffffffffL,
                0x100000000000L,
                0x123456789012L,
                0x1000000000000000L,
                0x1234567890123456L,
                0x7fffffffffffffffL,
                0xffffffffffffffffL};

        // Parcel subarrays of different lengths and assert the size of the resulting parcel
        testVarintParceler(Arrays.copyOfRange(values, 0, 1), 4);   // v. 8
        testVarintParceler(Arrays.copyOfRange(values, 0, 2), 4);   // v. 16
        testVarintParceler(Arrays.copyOfRange(values, 0, 3), 4);   // v. 24
        testVarintParceler(Arrays.copyOfRange(values, 0, 4), 8);   // v. 32
        testVarintParceler(Arrays.copyOfRange(values, 0, 5), 12);  // v. 40
        testVarintParceler(Arrays.copyOfRange(values, 0, 6), 16);  // v. 48
        testVarintParceler(Arrays.copyOfRange(values, 0, 7), 20);  // v. 56
        testVarintParceler(Arrays.copyOfRange(values, 0, 8), 28);  // v. 64
        testVarintParceler(Arrays.copyOfRange(values, 0, 9), 32);  // v. 72
        testVarintParceler(Arrays.copyOfRange(values, 0, 10), 40); // v. 80
        testVarintParceler(Arrays.copyOfRange(values, 0, 11), 48); // v. 88
        testVarintParceler(Arrays.copyOfRange(values, 0, 12), 60); // v. 96
        testVarintParceler(Arrays.copyOfRange(values, 0, 13), 68); // v. 104
        testVarintParceler(Arrays.copyOfRange(values, 0, 14), 76); // v. 112
    }

    private void testVarintParceler(long[] values, int expectedLength) {
        BatteryStatsHistory.VarintParceler parceler = new BatteryStatsHistory.VarintParceler();
        Parcel parcel = Parcel.obtain();
        parcel.writeString("begin");
        int pos = parcel.dataPosition();
        parceler.writeLongArray(parcel, values);
        int length = parcel.dataPosition() - pos;
        parcel.writeString("end");

        byte[] bytes = parcel.marshall();
        parcel.recycle();

        parcel = Parcel.obtain();
        parcel.unmarshall(bytes, 0, bytes.length);
        parcel.setDataPosition(0);

        assertThat(parcel.readString()).isEqualTo("begin");

        long[] result = new long[values.length];
        parceler.readLongArray(parcel, result);

        assertThat(result).isEqualTo(values);
        assertThat(length).isEqualTo(expectedLength);

        assertThat(parcel.readString()).isEqualTo("end");

        parcel.recycle();
    }
}