blob: bd84782122ad5f9ee4c232ada7045796208b86b6 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* 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 com.android.server.backup.transport;
import android.annotation.Nullable;
import android.content.ComponentName;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
/** Responsible for aggregating {@link TransportClient} relevant times. */
public class TransportStats {
private final Object mStatsLock = new Object();
private final Map<ComponentName, Stats> mTransportStats = new HashMap<>();
void registerConnectionTime(ComponentName transportComponent, long timeMs) {
synchronized (mStatsLock) {
Stats stats = mTransportStats.get(transportComponent);
if (stats == null) {
stats = new Stats();
mTransportStats.put(transportComponent, stats);
}
stats.register(timeMs);
}
}
/** Returns {@link Stats} for transport whose host service is {@code transportComponent}. */
@Nullable
public Stats getStatsForTransport(ComponentName transportComponent) {
synchronized (mStatsLock) {
Stats stats = mTransportStats.get(transportComponent);
if (stats == null) {
return null;
}
return new Stats(stats);
}
}
public void dump(PrintWriter pw) {
synchronized (mStatsLock) {
Optional<Stats> aggregatedStats =
mTransportStats.values().stream().reduce(Stats::merge);
if (aggregatedStats.isPresent()) {
dumpStats(pw, "", aggregatedStats.get());
}
if (!mTransportStats.isEmpty()) {
pw.println("Per transport:");
for (ComponentName transportComponent : mTransportStats.keySet()) {
Stats stats = mTransportStats.get(transportComponent);
pw.println(" " + transportComponent.flattenToShortString());
dumpStats(pw, " ", stats);
}
}
}
}
private static void dumpStats(PrintWriter pw, String prefix, Stats stats) {
pw.println(
String.format(
Locale.US, "%sAverage connection time: %.2f ms", prefix, stats.average));
pw.println(String.format(Locale.US, "%sMax connection time: %d ms", prefix, stats.max));
pw.println(String.format(Locale.US, "%sMin connection time: %d ms", prefix, stats.min));
pw.println(String.format(Locale.US, "%sNumber of connections: %d ", prefix, stats.n));
}
public static final class Stats {
public static Stats merge(Stats a, Stats b) {
return new Stats(
a.n + b.n,
(a.average * a.n + b.average * b.n) / (a.n + b.n),
Math.max(a.max, b.max),
Math.min(a.min, b.min));
}
public int n;
public double average;
public long max;
public long min;
public Stats() {
n = 0;
average = 0;
max = 0;
min = Long.MAX_VALUE;
}
private Stats(int n, double average, long max, long min) {
this.n = n;
this.average = average;
this.max = max;
this.min = min;
}
private Stats(Stats original) {
this(original.n, original.average, original.max, original.min);
}
private void register(long sample) {
average = (average * n + sample) / (n + 1);
n++;
max = Math.max(max, sample);
min = Math.min(min, sample);
}
}
}