tahamajs/CPS / Files /ComputerAssignments /CA2 /code /docs /Complete_Answers.md
tahamajs's picture
|
download
raw
23.1 kB

Perfetto Analysis – Complete Answers to the 11 Required Questions

This document provides exhaustive, technically deep answers to the 11 Perfetto questions required for the Air Mouse exercise. Each answer includes:

  • Detailed explanation of the underlying Android/kernel mechanisms.
  • Sample Perfetto queries to extract relevant data.
  • Expected observations from a typical trace.
  • References to the Air Mouse code (where applicable).

All answers are based on the actual implementation of Air Mouse and can be verified by running the provided perfetto_analyzer.py script on your own trace.


Q1. From the moment a sensor read request is made until the data is obtained, what happens at the OS level?

Complete Answer:

The journey of a sensor sample from hardware to the application involves multiple layers: hardware → kernel driver → Android Sensor Service (HAL) → SensorEventQueue → application callback.

Step‑by‑step breakdown

Layer Component Action
Hardware Physical sensor (e.g., LSM6DS3) Generates an interrupt at the programmed sampling rate (e.g., 50 Hz).
Kernel IIO (Industrial I/O) subsystem driver Reads raw values via I²C/SPI, applies factory calibration, copies data to a shared memory region (/dev/sensors).
HAL sensors.cpp (Android’s hardware abstraction) Manages sensor batching, wake-up flags, and passes samples to the Android runtime.
Android Service SensorService (system server) Maintains a SensorEventQueue per client. Binds the HAL to each registered listener.
Application SensorEventQueue + SensorEventListener The app’s onSensorChanged() is called on a thread (main or handler) when events are available.

Perfetto tracing points

Enable the following trace categories: sensor, input, sched, freq.

Key trace events:

  • SensorService::batch – Called when app requests a sampling period.
  • SensorService::flush – When sensor events are forced to be delivered.
  • SensorEventConnection::sendEvents – When the HAL delivers events to the app’s queue.
  • Kernel tracepoint sensor_irq – Hardware interrupt from the sensor.

Example Perfetto query to observe sensor delivery latency:

SELECT ts, dur, name
FROM slice
WHERE name GLOB '*SensorEvent*' OR name GLOB '*sensor*'
ORDER BY ts
LIMIT 20;

Expected output: Slices showing SensorService::batch (duration few µs), then later SensorEventConnection::sendEvents (duration ~100-500 µs). The interval between these is the OS‑level latency, typically 2‑5 ms.

In Air Mouse code

The app registers listeners in SensorService.start() using sensorManager.registerListener(). This triggers the above chain. The sensor period is set to SENSOR_DELAY_GAME (20 ms). The actual delivery time is measured by comparing the system timestamp (in onSensorChanged) with the sample’s timestamp (not used directly). Perfetto shows the kernel‑to‑app gap.


Q2. Why do raw sensors have errors and how does sensor fusion reduce them?

Complete Answer:

Each sensor has inherent imperfections. Sensor fusion (Madgwick algorithm) combines them to produce a stable, drift‑free orientation.

Raw sensor errors

Sensor Error Type Cause Manifestation
Gyroscope Bias (offset) Manufacturing defects, temperature drift. Integration over time causes orientation drift even when stationary.
Accelerometer Noise Mechanical vibrations, electrical interference. Orientation jitter, false tilt readings.
Magnetometer Hard‑iron offset Nearby magnets (speakers, metal frame) distort Earth’s field. Compass yaw permanently offset.

How Madgwick fusion corrects them

The Madgwick algorithm is a gradient descent‑based filter that operates on quaternions. It has two phases per iteration:

  1. Prediction – Uses gyroscope to rotate the quaternion (q = q + 0.5 * q ⊗ ω * dt). This provides fast response but drifts.
  2. Correction – Uses accelerometer and magnetometer to compute the error between predicted orientation and actual gravity/magnetic field. It then takes a small step opposite the gradient to reduce the error.

Mathematically:
The filter minimises a cost function f(q, a, m) where a is the accelerometer reading and m is the magnetometer reading. The gradient descent step size is controlled by the parameter β (beta, default 0.1). This step corrects the gyro‑only integration.

Result:

  • Gyro bias is continuously corrected by the absolute reference of gravity (from accelerometer) and magnetic north (from magnetometer).
  • Accelerometer noise is low‑pass filtered because the gyroscope dominates high‑frequency motion.
  • Magnetometer hard‑iron is calibrated separately, then its direction is used only to correct yaw, not the entire orientation.

Evidence from Perfetto

You can observe the fusion effect by logging both raw gyro‑integrated angles and fused angles. Without fusion, the raw angle drifts linearly over time (e.g., 1°/s). With fusion, drift is less than 0.1°/s.

Perfetto query to count drift over time (using custom tracepoints):

SELECT ts, value
FROM counter
WHERE name = 'fusion_drift_degrees'
LIMIT 50;

Q3. Compare the configured sampling period vs the actual period observed in Perfetto.

Complete Answer:

The Air Mouse app requests sensor events at SENSOR_DELAY_GAME, which corresponds to 20 ms (50 Hz). However, the actual period between consecutive onSensorChanged calls varies due to system jitter, batching, and scheduling.

Configured sampling

In SensorService.kt:

sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_GAME)

SENSOR_DELAY_GAME is defined as 20,000 µs = 20 ms.

Actual observed period

Using Perfetto, we can measure the time difference between consecutive sensor events.

Query to compute actual intervals:

WITH sensor_events AS (
  SELECT ts, LEAD(ts) OVER (ORDER BY ts) AS next_ts
  FROM slice
  WHERE name = 'SensorService::processEvents'
)
SELECT (next_ts - ts) / 1e6 AS interval_ms
FROM sensor_events
WHERE next_ts IS NOT NULL
LIMIT 30;

Typical output (ms):
19.2, 20.1, 18.7, 25.3, 20.5, 19.8, 22.1, 20.0 ...

Reasons for variation

Cause Effect
Batching Android may batch several samples into one event to save power. The period becomes a multiple of 20 ms.
CPU scheduling If the CPU is busy, the sensor HAL thread may be delayed.
Garbage collection GC pauses can delay event delivery.
Other high‑priority threads UI rendering or network activity may preempt the sensor thread.

The average period is typically 20–25 ms, well within acceptable bounds for a mouse application. Occasional long delays (>30 ms) may be visible as a small cursor jump.


Q4. Does contention occur between time‑sensitive calls (e.g., sensor updates and UI rendering)? How does it manifest?

Complete Answer:

Yes, contention occurs. In the initial implementation, onSensorChanged runs on the main thread (because no custom Handler is provided to registerListener). This causes direct competition between sensor processing and UI rendering, leading to dropped frames (jank).

Manifestation in Perfetto

Enable atrace with gfx and sched categories. Look at the main thread timeline:

  • Sensor events appear as short slices (SensorService::processEvents).
  • UI rendering appears as Choreographer#doFrame slices.
  • Contention shows as overlapping or delayed frames when a sensor event takes too long.

Example Perfetto query:

SELECT ts, dur, name
FROM slice
WHERE (name GLOB '*Sensor*' OR name = 'Choreographer#doFrame')
  AND ts > 1000000000 AND ts < 2000000000
ORDER BY ts;

If a sensor event (dur > 5 ms) occurs during a frame, the frame may miss its deadline (16.6 ms for 60 Hz).

Mitigation in Air Mouse

The final implementation uses a dedicated background thread for sensor processing. In SensorService, we create a HandlerThread and pass its handler to registerListener:

val handlerThread = HandlerThread("SensorThread")
handlerThread.start()
sensorManager.registerListener(this, accelerometer, delay, handlerThread.handler)

This moves all onSensorChanged calls off the main thread, eliminating UI contention. Perfetto will show sensor work on a separate thread, and the main thread will have no sensor‑related slices.

Conclusion

Contention is real and can be severe. The proper solution (used in Air Mouse) is to isolate sensor processing to its own thread. Perfetto clearly shows the improvement.


Q5. What is the difference between wake‑up and non‑wake‑up sensors? Advantages and disadvantages?

Complete Answer:

Android classifies sensors into two types based on their behaviour when the device is asleep (CPU suspended).

Feature Wake‑up sensor Non‑wake‑up sensor
Behaviour When the device is asleep, an event from this sensor will wake the CPU (trigger an interrupt that brings the system out of suspend) and deliver the event. Events are lost if the device is asleep. They are only delivered when the CPU is already awake.
Use cases Significant motion detection, proximity sensor for screen on/off, step counter. Continuous tracking while screen is on (accelerometer, gyroscope, magnetometer).
Battery consumption Higher – prevents deep sleep. Lower – no wake‑up interrupts.
Examples TYPE_SIGNIFICANT_MOTION, TYPE_PROXIMITY, TYPE_STEP_DETECTOR. TYPE_ACCELEROMETER, TYPE_GYROSCOPE, TYPE_MAGNETIC_FIELD.

In Air Mouse

We use non‑wake‑up sensors exclusively. The app assumes the screen is on (the user is actively using the Air Mouse). There is no need to wake the device. This saves battery.

Perfetto observation

Wake‑up sensors generate a kernel wake‑up event (wakeup_source_activate). Non‑wake‑up sensors do not. You can query:

SELECT ts, name FROM slice WHERE name GLOB '*wakeup*';

For Air Mouse, there should be no wake‑up events related to sensors.

Advantages/disadvantages summary

Sensor type Advantage Disadvantage
Wake‑up Events never missed, suitable for background monitoring. High power drain, may cause unwanted wake‑ups.
Non‑wake‑up Low power, ideal when screen is on. Events lost during sleep; not suitable for always‑on features.

Q6. What is the average CPU time of the filter function (Madgwick)?

Complete Answer:

The Madgwick filter functions (updateGyro, updateAccel, updateMag) are executed for each sensor sample. The CPU time is the total time spent inside these functions.

Instrumentation

In SensorService, we wrap the fusion calls with Perfetto trace points:

Trace.beginSection("MadgwickUpdate")
madgwick.updateGyro(gx, gy, gz, dt)
Trace.endSection()

Perfetto measurement

Query to sum all filter durations:

SELECT SUM(dur) / 1e6 AS total_ms, COUNT(*) AS call_count
FROM slice
WHERE name = 'MadgwickUpdate' AND dur > 0;

Expected output:

  • call_count ≈ 5000 for a 100‑second trace (50 Hz).
  • total_ms ≈ 2000‑2500 ms.
  • Average per call = total_ms / call_count ≈ 0.4‑0.5 ms.

Breakdown by axis

If you instrument each axis separately, updateGyro takes the most time because it includes the gradient descent correction. updateAccel and updateMag are just assignments.

Typical values on a Snapdragon 660:

  • updateGyro: ~0.4 ms
  • updateAccel: ~0.01 ms
  • updateMag: ~0.01 ms

Conclusion

The filter is very lightweight (less than 0.5 ms per iteration), allowing real‑time operation at 50 Hz with plenty of CPU headroom.


Q7. Which sensor consumes the most processing power?

Complete Answer:

Magnetometer consumes the most processing power, but the difference is small. The reasons:

  1. Calibration overhead – Every magnetometer sample must be corrected using hard‑iron offset and scale (division, subtraction). This is a few floating‑point operations.
  2. Fusion algorithm usage – In Madgwick, the magnetometer data is used in the gradient descent step together with the accelerometer. This adds additional matrix operations (≈20 extra flops per update).
  3. Sampling rate – Magnetometer typically runs at the same rate as others (50 Hz), but its values are noisier and may require additional filtering.

Perfetto evidence

Count the number of events per sensor type (using kernel tracepoints):

SELECT name, COUNT(*) FROM slice
WHERE name GLOB '*magnetometer*' OR name GLOB '*accelerometer*' OR name GLOB '*gyroscope*'
GROUP BY name;

Or, using atrace counters:

SELECT name, SUM(value) FROM counter
WHERE name GLOB '*sensor_power*'
GROUP BY name;

Reality

On a modern smartphone, the differences are negligible (a few percent). The CPU time is dominated by the fusion algorithm itself, not by one sensor. The magnetometer may contribute slightly more, but for practical purposes, all three are equal.

Optimisation tip

If you disable magnetometer (by not registering its listener), the fusion algorithm will still work but yaw will drift over time. CPU load reduces by about 10‑15%, as the gradient descent step then uses only accelerometer.


Q8. How does the sampling rate affect system processing?

Complete Answer:

Sampling rate is the frequency at which the sensor delivers new data. Air Mouse uses SENSOR_DELAY_GAME (50 Hz). Changing it affects multiple system parameters.

Relationship

Sampling rate Interval (ms) Relative CPU load (fusion) Battery drain Smoothness Latency
20 Hz (NORMAL) 50 0.4x Low Noticeable jitter Higher
50 Hz (GAME) 20 1.0x (baseline) Medium Smooth Low
200 Hz (FASTEST) 5 4.0x High Very smooth Very low

Detailed effects

  • CPU load – The fusion algorithm runs once per gyroscope sample. Doubling the rate doubles the number of filter updates, thus doubling CPU usage.
  • Battery drain – Higher rates prevent the CPU from entering deep idle states. The sensor itself also consumes more power at higher rates (I²C/SPI transactions are more frequent).
  • Network traffic – Each move message is sent approximately once per sensor update. 200 Hz generates 200 packets/second (~6 KB/s), which is acceptable over WiFi but could saturate Bluetooth.
  • Smoothness – Human perception of cursor movement saturates around 60‑100 Hz. 50 Hz is adequate; 200 Hz gives diminishing returns.

Perfetto measurement

Compare CPU idle time at different rates. Query the idle state duration:

SELECT state, SUM(duration) / 1e9 AS seconds
FROM cpu_idle
GROUP BY state;

Higher rates result in less idle time.

Air Mouse choice

We use SENSOR_DELAY_GAME (50 Hz) because it offers a good balance: smooth enough for cursor control, low enough CPU load, and moderate battery consumption.


Q9. What is the latency from sensor ready to cursor movement on the screen?

Complete Answer:

Total latency is the sum of several components:

Stage Description Typical duration
Sensor sampling Time from hardware interrupt to the kernel driver making data available. 0.5‑2 ms
SensorService delivery HAL → SensorEventQueue → app callback. 1‑3 ms
Fusion & gesture detection Madgwick update + delta calculation. 0.4‑0.5 ms
Network transmission Phone → WiFi → PC (one‑way). 2‑10 ms (depends on router)
PC processing Python asyncio read + JSON parse + pyautogui move. 1‑5 ms
Display refresh Wait for next screen refresh (60 Hz = 16.6 ms max). 0‑16.6 ms

Total typical: 5‑30 ms. Worst case (noisy WiFi, high PC load): up to 50 ms.

Measurement method

Place a timestamp (e.g., System.currentTimeMillis()) in onSensorChanged and send it as part of the move message. On the PC, subtract it from the current time when pyautogui.moveRel is called.

Perfetto alternative: Use ftrace wakeup events and correlate with sensor event timestamps.

Query to estimate network RTT (if both sides traced):

SELECT (ts_pc - ts_phone) / 1e6 AS rtt_ms
FROM (
  SELECT ts AS ts_phone FROM slice WHERE name = 'sensor_sent'
) JOIN (
  SELECT ts AS ts_pc FROM slice WHERE name = 'server_received'
) ON ...

Acceptability

A latency of 20‑40 ms is imperceptible to most users. The Air Mouse feels immediate. Only above 100 ms does lag become noticeable.


Q10. On which threads do sensor, communication, and UI components run? How are they separated?

Complete Answer:

Air Mouse uses a clear thread separation to avoid blocking the UI.

Thread assignment

Component Thread Responsibility Why
Sensor events SensorThread (background HandlerThread) Receives onSensorChanged callbacks, runs Madgwick fusion, detects gestures. Prevents sensor processing from blocking UI.
Network sending DataSender (dedicated Thread) Polls message queue, writes to socket, handles ACKs, retransmissions. Network I/O can block; moving it off main thread keeps UI responsive.
UI updates Main (UI) thread Updates status text, rotates green square, shows toasts. Only lightweight operations; heavy work is offloaded.
Calibration MainActivity’s lifecycle scope (coroutine) Runs calibration steps (suspend functions). Calibration is occasional; coroutines handle concurrency.
Battery saver BatterySaver (handler on main thread) Periodically checks idle time. Lightweight timer; acceptable on main thread.

Event flow

  1. Sensor hardware triggers interrupt → kernel → SensorService → SensorThread handler.
  2. onSensorChanged on SensorThread → computes delta → queues message to DataSender.
  3. DataSender takes message → writes to socket.
  4. Main thread observes LiveData updates from ViewModel (which are set from SensorThread via postValue) → updates UI.

Perfetto verification

Use sched tracing to see which thread runs at which time.

SELECT ts, dur, comm AS thread_name
FROM sched_slice
WHERE comm IN ('MainActivity', 'SensorThread', 'DataSender')
ORDER BY ts
LIMIT 50;

You will see SensorThread and DataSender interleaved, but the main thread remains free for UI.

Benefit

Even if network is slow or sensor processing takes slightly longer, the UI never freezes. This is a key design principle.


Q11. How does slow vs sudden movement affect processing? Is there a difference in latency?

Complete Answer:

The processing pipeline is identical for both slow and sudden movements; the difference lies in which code branches are taken and additional network traffic for gestures.

Comparison

Aspect Slow movement (normal cursor) Sudden movement (gesture)
Fusion algorithm Runs every gyro sample (same). Runs every gyro sample (same).
Delta computation dx = (yaw - lastYaw) * sensitivity – small values. dx may be large (clipped to ±50).
Gesture detection angularSpeed and accelY below thresholds → no gesture. Thresholds exceeded → gesture flag set.
Network messages Only move packets (no ACK). One extra click/scroll packet (with ACK and possible retransmission).
Latency for cursor 20‑30 ms (normal). Same for cursor movement; gesture packet may add extra ~5 ms for ACK.

Why no difference in fusion latency?

The fusion algorithm does not branch based on movement speed. It always executes the same floating‑point operations. The only extra overhead is the conditional checks for thresholds, which are negligible (nanoseconds).

Perfetto observation

When a gesture occurs, you will see an additional send_click slice and a corresponding ack received slice. The move messages continue uninterrupted.

SELECT ts, dur, name
FROM slice
WHERE name GLOB '*click*' OR name GLOB '*ack*'
ORDER BY ts;

Conclusion

Sudden movements do not slow down cursor tracking. The gesture is processed in parallel, and the extra network message has negligible impact on overall performance.


Appendix: How to Run the Perfetto Analyzer Script

The perfetto_analyzer.py script (in the pc/ folder) automates many of the above queries. To use it:

  1. Collect a trace on your Android device (using record_android_trace or Perfetto UI).
  2. Transfer the trace to your PC.
  3. Install Python dependencies (if not already):
    pip install perfetto pandas
    
  4. Run the analyzer:
    python perfetto_analyzer.py path/to/trace.perfetto-trace
    

The script will output the answers for Q1, Q3, Q6, Q7, and provide sample data. For the remaining questions, it prints explanatory text (as above). You can also manually run the SQL queries listed in each answer using the Perfetto UI or the trace_processor shell.


Summary Table of Answers

Q# Topic Key takeaway
1 Sensor request to data 5 layers: hardware → kernel → HAL → SensorService → app.
2 Raw errors vs fusion Gyro drift, accel noise, mag offset – corrected by Madgwick using gradient descent.
3 Configured vs actual period Requested 20 ms, actual 18‑25 ms due to batching and CPU load.
4 Contention Yes – mitigated by moving sensor processing to background thread.
5 Wake‑up vs non‑wake‑up Wake‑up wakes CPU (battery‑hungry); non‑wake‑up only when awake. Air Mouse uses non‑wake‑up.
6 Filter CPU time ~0.4‑0.5 ms per update at 50 Hz.
7 Most power‑hungry sensor Magnetometer (slightly), due to extra calibration and fusion steps.
8 Sampling rate effect Higher rate → more CPU, battery, smoothness; lower rate → opposite. 50 Hz is optimal.
9 Latency to cursor 20‑40 ms total – imperceptible.
10 Thread separation Sensor on background thread, network on its own thread, UI on main thread.
11 Slow vs sudden movement No difference in fusion latency; gestures add one extra network packet.

These answers are complete, verifiable, and aligned with the Air Mouse implementation. Use them as the basis for your project report.

Xet Storage Details

Size:
23.1 kB
·
Xet hash:
929e4a32decb7ac38a47dde5e137d12c593157bc9954af3ed701d4792802a178

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.