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

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

Merge "Use optimized date formatting in battery history dump" into main

parents 6f3edd27 f973f2e8
Loading
Loading
Loading
Loading
+91 −12
Original line number Diff line number Diff line
@@ -6948,8 +6948,9 @@ public abstract class BatteryStats {
        // This constant MUST be incremented whenever the history dump format changes.
        private static final int FORMAT_VERSION = 2;

        private final SimpleDateFormat mHistoryItemTimestampFormat =
                new SimpleDateFormat("MM-dd HH:mm:ss.SSS", Locale.US);
        private final boolean mPerformanceBaseline;
        private final HistoryLogTimeFormatter mHistoryLogTimeFormatter;
        private final SimpleDateFormat mHistoryItemTimestampFormat;
        private final SimpleDateFormat mCurrentTimeEventTimeFormat =
                new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.US);

@@ -6960,6 +6961,7 @@ public abstract class BatteryStats {

        private final int mFormatVersion;

        private final StringBuilder mStringBuilder = new StringBuilder();
        int oldState = 0;
        int oldState2 = 0;
        int oldLevel = -1;
@@ -6974,18 +6976,30 @@ public abstract class BatteryStats {
        long lastTime = -1;

        public HistoryPrinter() {
            this(TimeZone.getDefault());
            this(0);
        }

        public HistoryPrinter(TimeZone timeZone) {
        public HistoryPrinter(int flags) {
            this(TimeZone.getDefault(), flags);
        }

        public HistoryPrinter(TimeZone timeZone, int flags) {
            this(com.android.server.power.optimization.Flags
                    .extendedBatteryHistoryContinuousCollectionEnabled()
                    ? FORMAT_VERSION : FORMAT_LEGACY, timeZone);
                    ? FORMAT_VERSION : FORMAT_LEGACY, timeZone, flags);
        }

        private HistoryPrinter(int formatVersion, TimeZone timeZone) {
        private HistoryPrinter(int formatVersion, TimeZone timeZone, int flags) {
            mFormatVersion = formatVersion;
            mPerformanceBaseline = (flags & DUMP_DEBUG_PERF_BASELINE) != 0;
            if (mPerformanceBaseline) {
                mHistoryItemTimestampFormat = new SimpleDateFormat("MM-dd HH:mm:ss.SSS", Locale.US);
                mHistoryItemTimestampFormat.getCalendar().setTimeZone(timeZone);
                mHistoryLogTimeFormatter = null;
            } else {
                mHistoryItemTimestampFormat = null;
                mHistoryLogTimeFormatter = new HistoryLogTimeFormatter(timeZone);
            }
            mCurrentTimeEventTimeFormat.getCalendar().setTimeZone(timeZone);
        }

@@ -7019,7 +7033,8 @@ public abstract class BatteryStats {
        @SuppressWarnings("JavaUtilDate")
        private String printNextItem(HistoryItem rec, long baseTime, boolean checkin,
                boolean verbose) {
            StringBuilder item = new StringBuilder();
            StringBuilder item = mStringBuilder;
            item.setLength(0);
            if (!checkin) {
                item.append("  ");
                if (mFormatVersion == FORMAT_LEGACY) {
@@ -7029,8 +7044,13 @@ public abstract class BatteryStats {
                    item.append(rec.numReadInts);
                    item.append(") ");
                } else {
                    if (mPerformanceBaseline) {
                        mDate.setTime(rec.currentTime);
                        item.append(mHistoryItemTimestampFormat.format(mDate)).append(' ');
                    } else {
                        mHistoryLogTimeFormatter.append(item, rec.currentTime);
                        item.append(' ');
                    }
                }
            } else {
                item.append(BATTERY_STATS_CHECKIN_VERSION); item.append(',');
@@ -7399,6 +7419,64 @@ public abstract class BatteryStats {
            sb.append(":");
            sb.append(stime);
        }

        /**
         * In essence, this is a wrapper over SimpleDateFormat that takes advantage
         * of the fact that events in battery history are closely spaced, which allows it
         * to reuse the results of the most expensive formatting work.
         */
        private static class HistoryLogTimeFormatter {
            private static final long HOUR_MILLIS = 3600000L;
            private static final long MINUTE_MILLIS = 60000L;
            private final SimpleDateFormat mDateFormat =
                    new SimpleDateFormat("MM-dd HH:", Locale.US);
            private final Date mDate = new Date();

            private final long mTimeZoneOffset;
            private long mCachedHour;
            private String mCachedHourFormatted;

            private HistoryLogTimeFormatter(TimeZone timeZone) {
                mTimeZoneOffset = timeZone.getRawOffset();
                mDateFormat.getCalendar().setTimeZone(timeZone);
            }

            /* Appends timestampMs formatted as  "MM-dd HH:mm:ss.SSS" */
            void append(StringBuilder sb, long timestampMs) {
                long localTime = timestampMs + mTimeZoneOffset;
                long hour = localTime / HOUR_MILLIS;
                if (hour != mCachedHour) {
                    mDate.setTime(timestampMs);
                    mCachedHourFormatted = mDateFormat.format(mDate);
                    mCachedHour = hour;
                }
                sb.append(mCachedHourFormatted);

                long remainder = localTime % HOUR_MILLIS;

                long minutes = remainder / MINUTE_MILLIS;
                if (minutes < 10) {
                    sb.append('0');
                }
                sb.append(minutes).append(':');

                remainder = remainder % MINUTE_MILLIS;
                long seconds = remainder / 1000;
                if (seconds < 10) {
                    sb.append('0');
                }
                sb.append(seconds).append('.');

                long millis = remainder % 1000;
                if (millis < 100) {
                    sb.append('0');
                    if (millis < 10) {
                        sb.append('0');
                    }
                }
                sb.append(millis);
            }
        }
    }

    private void printSizeValue(PrintWriter pw, long size) {
@@ -7584,9 +7662,10 @@ public abstract class BatteryStats {
    public static final int DUMP_INCLUDE_HISTORY = 1<<4;
    public static final int DUMP_VERBOSE = 1<<5;
    public static final int DUMP_DEVICE_WIFI_ONLY = 1<<6;
    public static final int DUMP_DEBUG_PERF_BASELINE = 1 << 7;

    private void dumpHistory(PrintWriter pw, int flags, long histStart, boolean checkin) {
        final HistoryPrinter hprinter = new HistoryPrinter();
        final HistoryPrinter hprinter = new HistoryPrinter(flags);
        synchronized (this) {
            if (!checkin) {
                final long historyTotalSize = getHistoryTotalSize();
@@ -8522,7 +8601,7 @@ public abstract class BatteryStats {
            }

        // History data (HISTORY_DATA)
        final HistoryPrinter hprinter = new HistoryPrinter();
        final HistoryPrinter hprinter = new HistoryPrinter(flags);
        long lastTime = -1;
        long baseTime = -1;
        boolean printed = false;
+8 −0
Original line number Diff line number Diff line
@@ -3368,6 +3368,14 @@ public final class BatteryStatsService extends IBatteryStats.Stub
                    return;
                } else if ("-a".equals(arg)) {
                    flags |= BatteryStats.DUMP_VERBOSE;
                } else if ("--debug".equals(arg)) {
                    i++;
                    if (i >= args.length) {
                        pw.println("Missing time argument for --flags HEX");
                        dumpHelp(pw);
                        return;
                    }
                    flags |= ParseUtils.parseIntWithBase(args[i], 16, 0);
                } else if (arg.length() > 0 && arg.charAt(0) == '-'){
                    pw.println("Unknown option: " + arg);
                    dumpHelp(pw);
+38 −1
Original line number Diff line number Diff line
@@ -67,10 +67,14 @@ import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.TimeUnit;

/**
 * Test BatteryStatsHistory.
@@ -141,7 +145,7 @@ public class BatteryStatsHistoryTest {
                mEventLogger);
        mHistory.forceRecordAllHistory();
        mHistory.startRecordingHistory(mClock.realtime, mClock.uptime, false);
        mHistoryPrinter = new BatteryStats.HistoryPrinter(TimeZone.getTimeZone("GMT"));
        mHistoryPrinter = new BatteryStats.HistoryPrinter(TimeZone.getTimeZone("GMT"), 0);
    }

    @Test
@@ -865,6 +869,39 @@ public class BatteryStatsHistoryTest {
        return events;
    }


    @Test
    public void historyLogTimeFormatter() {
        historyLogTimeFormatting("GMT");
        historyLogTimeFormatting("PST");
        historyLogTimeFormatting("NST");        // UTC−03:30
        historyLogTimeFormatting("NPT");        // UTC+05:45
    }

    private void historyLogTimeFormatting(String timeZoneId) {
        TimeZone timeZone = TimeZone.getTimeZone(timeZoneId);
        BatteryStats.HistoryPrinter printer = new BatteryStats.HistoryPrinter(timeZone, 0);
        SimpleDateFormat simpleDateFormat =
                new SimpleDateFormat("MM-dd HH:mm:ss.SSS", Locale.US);
        simpleDateFormat.getCalendar().setTimeZone(timeZone);
        Date date = new Date();

        HistoryItem item = new HistoryItem();
        long base = 1738746000000L;
        for (long offset = 1; offset < TimeUnit.DAYS.toMillis(365 * 100); offset *= 7) {
            item.currentTime = base + offset;
            date.setTime(item.currentTime);
            String expected = simpleDateFormat.format(date);
            StringWriter sw = new StringWriter();
            PrintWriter writer = new PrintWriter(sw);
            printer.printNextItem(writer, item, 0, false, false);
            writer.flush();
            String actual = sw.toString().trim().substring(0, "MM-dd HH:mm:ss.SSS".length());

            assertThat(actual).isEqualTo(expected);
        }
    }

    private static void awaitCompletion() {
        ConditionVariable done = new ConditionVariable();
        BackgroundThread.getHandler().post(done::open);