diff options
| author | 2018-11-08 19:54:22 -0800 | |
|---|---|---|
| committer | 2019-01-22 14:40:28 -0800 | |
| commit | 9ffab0cc56a4b7e12fe329845c4c60d422129370 (patch) | |
| tree | 2d2321ebff9e97d4f85099c16ec600fdd55433c2 | |
| parent | 85bd1ec6d01b357a3fdc1fa50caee51ed5cbfa29 (diff) | |
Metrics for touch latency
Add some basic metrics for touch latency here.
Currently just measure the time from evdev to eventhub.
This will later become "hard interrupt" to eventhub, after we fix
b/119840121.
Bug: 111431676
Test: set reporting interval to 5 seconds instead of 5 minutes, then run
'statsd_testdrive 34' and touch the screen for a minute. Review the
results to ensure that times are reported as expected.
Change-Id: I6144aa0feab897a161f1ee058686dd0a790d17f1
| -rw-r--r-- | services/inputflinger/Android.bp | 3 | ||||
| -rw-r--r-- | services/inputflinger/InputReader.cpp | 25 | ||||
| -rw-r--r-- | services/inputflinger/InputReader.h | 68 |
3 files changed, 91 insertions, 5 deletions
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp index 843eb379d9..e3a237ef73 100644 --- a/services/inputflinger/Android.bp +++ b/services/inputflinger/Android.bp @@ -76,7 +76,8 @@ cc_library_shared { "libutils", "libui", "libhardware_legacy", - "libutils" + "libstatslog", + "libutils", ], header_libs: [ diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp index 2b31f6e0e6..64070e3fa3 100644 --- a/services/inputflinger/InputReader.cpp +++ b/services/inputflinger/InputReader.cpp @@ -57,6 +57,7 @@ #include <android-base/stringprintf.h> #include <input/Keyboard.h> #include <input/VirtualKeyMap.h> +#include <statslog.h> #define INDENT " " #define INDENT2 " " @@ -71,18 +72,21 @@ namespace android { // --- Constants --- // Maximum number of slots supported when using the slot-based Multitouch Protocol B. -static const size_t MAX_SLOTS = 32; +static constexpr size_t MAX_SLOTS = 32; // Maximum amount of latency to add to touch events while waiting for data from an // external stylus. -static const nsecs_t EXTERNAL_STYLUS_DATA_TIMEOUT = ms2ns(72); +static constexpr nsecs_t EXTERNAL_STYLUS_DATA_TIMEOUT = ms2ns(72); // Maximum amount of time to wait on touch data before pushing out new pressure data. -static const nsecs_t TOUCH_DATA_TIMEOUT = ms2ns(20); +static constexpr nsecs_t TOUCH_DATA_TIMEOUT = ms2ns(20); // Artificial latency on synthetic events created from stylus data without corresponding touch // data. -static const nsecs_t STYLUS_DATA_LATENCY = ms2ns(10); +static constexpr nsecs_t STYLUS_DATA_LATENCY = ms2ns(10); + +// How often to report input event statistics +static constexpr nsecs_t STATISTICS_REPORT_FREQUENCY = seconds_to_nanoseconds(5 * 60); // --- Static Functions --- @@ -4287,12 +4291,25 @@ void TouchInputMapper::clearStylusDataPendingFlags() { mExternalStylusFusionTimeout = LLONG_MAX; } +void TouchInputMapper::reportEventForStatistics(nsecs_t evdevTime) { + nsecs_t now = systemTime(CLOCK_MONOTONIC); + nsecs_t latency = now - evdevTime; + mStatistics.addValue(nanoseconds_to_microseconds(latency)); + nsecs_t timeSinceLastReport = now - mStatistics.lastReportTime; + if (timeSinceLastReport > STATISTICS_REPORT_FREQUENCY) { + android::util::stats_write(android::util::TOUCH_EVENT_REPORTED, + mStatistics.min, mStatistics.max, mStatistics.mean(), mStatistics.stdev()); + mStatistics.reset(now); + } +} + void TouchInputMapper::process(const RawEvent* rawEvent) { mCursorButtonAccumulator.process(rawEvent); mCursorScrollAccumulator.process(rawEvent); mTouchButtonAccumulator.process(rawEvent); if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { + reportEventForStatistics(rawEvent->when); sync(rawEvent->when); } } diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h index 35f3c232c7..aaffce294e 100644 --- a/services/inputflinger/InputReader.h +++ b/services/inputflinger/InputReader.h @@ -567,6 +567,69 @@ struct CookedPointerData { } }; +/** + * Basic statistics information. + * Keep track of min, max, average, and standard deviation of the received samples. + * Used to report latency information about input events. + */ +struct LatencyStatistics { + float min; + float max; + // Sum of all samples + float sum; + // Sum of squares of all samples + float sum2; + // The number of samples + size_t count; + // The last time statistics were reported. + nsecs_t lastReportTime; + + LatencyStatistics() { + reset(systemTime(SYSTEM_TIME_MONOTONIC)); + } + + inline void addValue(float x) { + if (x < min) { + min = x; + } + if (x > max) { + max = x; + } + sum += x; + sum2 += x * x; + count++; + } + + // Get the average value. Should not be called if no samples have been added. + inline float mean() { + if (count == 0) { + return 0; + } + return sum / count; + } + + // Get the standard deviation. Should not be called if no samples have been added. + inline float stdev() { + if (count == 0) { + return 0; + } + float average = mean(); + return sqrt(sum2 / count - average * average); + } + + /** + * Reset internal state. The variable 'when' is the time when the data collection started. + * Call this to start a new data collection window. + */ + inline void reset(nsecs_t when) { + max = 0; + min = std::numeric_limits<float>::max(); + sum = 0; + sum2 = 0; + count = 0; + lastReportTime = when; + } +}; /* Keeps track of the state of single-touch protocol. */ class SingleTouchMotionAccumulator { @@ -1511,6 +1574,9 @@ private: VelocityControl mWheelXVelocityControl; VelocityControl mWheelYVelocityControl; + // Latency statistics for touch events + struct LatencyStatistics mStatistics; + std::optional<DisplayViewport> findViewport(); void resetExternalStylus(); @@ -1580,6 +1646,8 @@ private: static void assignPointerIds(const RawState* last, RawState* current); + void reportEventForStatistics(nsecs_t evdevTime); + const char* modeToString(DeviceMode deviceMode); }; |