CMLogItem.timestamp: which clock is it on, and how to convert to AVCaptureSession.synchronizationClock / host time?

We receive live relative-altitude updates from CMAltimeter.startRelativeAltitudeUpdates(to:withHandler:) on iPhone. CMAltitudeData inherits CMLogItem.timestamp, which the documentation describes as the time when the item is valid and as seconds since device boot.

We need to determine whether a pressure measurement's event time falls inside an application operation bounded by a supported monotonic clock. Could Apple clarify the supported contract for CMAltitudeData.timestamp on iOS?

  1. Does CMAltitudeData.timestamp use the same epoch and rate as mach_absolute_time(), DispatchTime.uptimeNanoseconds, CACurrentMediaTime(), or ProcessInfo.systemUptime? If only some are compatible, which ones?

  2. Does it advance or pause during device sleep, device lock, application suspension, and background execution? In particular, are its sleep/suspension semantics guaranteed to match any of the clocks above?

  3. Is there a supported API for converting CMLogItem.timestamp to a host CMClock/Mach time, or for sampling “now” in the exact same clock domain used by CMAltitudeData.timestamp?

  4. Are the answers contractual across supported iPhone hardware and iOS releases, or are they implementation details that applications should not rely on?

  5. If direct comparison is not supported, what Apple-supported clock or conversion mechanism should an application use to compare a CMAltitudeData event time with two application-side monotonic operation boundaries?

The question concerns clock semantics only. A minimal reproducer can be supplied if requested, but no application identifier, production data, sensor values, or user data is required to answer it.

Answered by DTS Engineer in 906840022

Your point that the altimeter does not perform its own timestamping raises one remaining question: what event does CMAltitudeData.timestamp represent—receipt of a sensor reading by the system, creation of the Core Motion event, or an estimate of when pressure was measured?

locationd collects and stores the data from our various sensors, and that data store* is what then sends the motion events you receive. SO, generally speaking, its behavior is probably closer to this:

*Just to clarify, this doesn't mean that locationd specifically stores every reading it receives and then sends it to your app at some later point. The process of sending data to clients and storing that data all happens as part of the same process.

CMAltitudeData.timestamp represent—receipt of a sensor reading by the system

However, the problem here is that the details of exactly how our sensors generate and process data vary considerably across our full device range and, in fact, a huge part of locationd's "job" is to provide relatively consistent behavior across a very wide range of sensor implementations. Putting that in more concrete terms, if these differences ACTUALLY matter to your app’s implementation, then I think you're expecting a level of precision that the system was never really designed to provide.

Can a newly delivered event contain an older or filtered pressure measurement whose age is not represented by that timestamp?

No.

For implementation, is comparing that timestamp directly with operation boundaries sampled using ProcessInfo.systemUptime, while monitoring for unexpected divergence, a reasonable approach for this coarse association?

You'll need to test it for yourself, but yes, I expect it will work well. One suggestion on that point— if you're planning on integrating this into an existing, mature implementation, I would strongly suggest writing a VERY simple test app that does nothing but collect the sensor data you're interested in and correlate them with ProcessInfo.systemUptime (or any other source you want to try). I'd probably test "all" the time sources at once just to see how things compared, but the details there don't matter. Partly this is just to quickly confirm that this works the way you want, both so you can avoid wasted effort now and so you can validate things in the future. The "pro move" here would actually be to integrate this into your long-term testing process, so that you'll immediately notice if/when something were to change.

However, the bigger issue is that "real" app implementations often work very differently than people realize, and that disconnect can end up causing large amounts of wasted time and effort. The best way to counter that is to start with a clear understanding of what the "basic" behavior is, so that when something different happens, you'll start by looking at your app’s implementation, not the data.

That leads to here:

"Separately, does CMDeviceMotion (gyroscope/accelerometer) timestamping follow the same software-stamping path, or is IMU data timestamped closer to the sensor?"

Down this path lies madness. The problem here is that:

  1. There's no meaningful time difference between those two cases.

  2. Even if there were a meaningful time difference, there's no way your app can account for or compensate for that difference, so it still doesn't matter.

Since you mentioned CMDeviceMotion, a few other tips/tricks that might be useful:

  • If you're using motion data to drive your interface, the best way to do that is by directly using the latest sample property (CMMotionManager.deviceMotion) in your interface rendering code, NOT by receiving the data on a queue and routing it to your interface. Trying to collect and route the data yourself only introduces additional latency and complexity, which is why the properties exist in the first place.

  • If you're doing user activity tracking, I'd strongly recommend using APIs like CMSensorRecorder or CMBatchedSensorManager, NOT CMMotionManager. CMMotionManager delivers data at a far higher rate than meaningful user analysis requires (humans don't really move at 50hz), so a proper CMDeviceMotion implementation ends up needing to batch up events anyway. Even worse, most of the motion analysis issues I've seen with CMDeviceMotion are caused by the app interfering with its own event delivery, then failing to account for the distortion those delays created. All of those issues go away if you use our non-"real time" APIs.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

We need to determine whether a pressure measurement's event time falls inside an application operation bounded by a supported monotonic clock. Could Apple clarify the supported contract for CMAltitudeData.timestamp on iOS?

The official contract is what the timestamp documentation says:

"The timestamp is the amount of time in seconds since the device booted."

...which, as you've noted, isn't all that strong. Informally, I believe it's actually mach_absolute_time, converted to a double of seconds.

Does CMAltitudeData.timestamp use the same epoch and rate as mach_absolute_time(),

We actually have relatively few time sources, with mach_absolute_time and mach_continuous_time being the primary underlying clocks.

If only some are compatible, which ones?

DispatchTime.uptimeNanoseconds or ProcessInfo.systemUptime?

Both of those derive from mach_absolute_time.

CACurrentMediaTime(),

I think this does too, but its implementation is a bit more complicated.

Does it advance or pause during device sleep, device lock, application suspension, and background execution? In particular, are its sleep/suspension semantics guaranteed to match any of the clocks above?

I believe all of the clocks above will behave identically.

Is there a supported API for converting CMLogItem.timestamp to a host CMClock/Mach time, or for sampling “now” in the exact same clock domain used by CMAltitudeData.timestamp?

The main issue here is how "accurate" you think the value will be. If you're trying to correlate events within a second or so, then the comparison is relatively straightforward; however, the more precise you try and make that comparison, the more "philosophical" this question becomes. Our altimeter isn't doing its own timestamping, so below a certain threshold, things like event processing jitter inside Locationd start having a significant effect.

Are the answers contractual across supported iPhone hardware and iOS releases, or are they implementation details that applications should not rely on?

Both? Strictly speaking, they're implementation details that could theoretically change at any time. Having said that, the implementation hasn't changed since iOS 4 (when CoreMotion was introduced), and I don't see any particular reason why it would.

If direct comparison is not supported, what Apple-supported clock or conversion mechanism should an application use to compare a CMAltitudeData event time with two application-side monotonic operation boundaries?

The paranoid implementation here would be for your app to regularly correlate the times returned by the various clock sources you were trying to correlate. Sampling time differences means the times would never align; however, I think you'd find that the actual divergence was always within a fairly narrow band, assuming you were careful not to introduce your own divergence [1].

[1] The main issue here is that thread activity can delay event delivery, which would push CMAltitudeData "back" in time. However, as long as you’re only trying to correlate user-relevant wall times, that divergence shouldn't be large enough to matter.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Thank you, Kevin—this helps considerably. We’re aiming for coarse association with an application operation, not sub-millisecond pressure timing.

Your point that the altimeter does not perform its own timestamping raises one remaining question: what event does CMAltitudeData.timestamp represent—receipt of a sensor reading by the system, creation of the Core Motion event, or an estimate of when pressure was measured? Can a newly delivered event contain an older or filtered pressure measurement whose age is not represented by that timestamp?

For implementation, is comparing that timestamp directly with operation boundaries sampled using ProcessInfo.systemUptime, while monitoring for unexpected divergence, a reasonable approach for this coarse association?

We understand that this would not establish the physical measurement instant or a guaranteed error bound.

"Separately, does CMDeviceMotion (gyroscope/accelerometer) timestamping follow the same software-stamping path, or is IMU data timestamped closer to the sensor?"

Accepted Answer

Your point that the altimeter does not perform its own timestamping raises one remaining question: what event does CMAltitudeData.timestamp represent—receipt of a sensor reading by the system, creation of the Core Motion event, or an estimate of when pressure was measured?

locationd collects and stores the data from our various sensors, and that data store* is what then sends the motion events you receive. SO, generally speaking, its behavior is probably closer to this:

*Just to clarify, this doesn't mean that locationd specifically stores every reading it receives and then sends it to your app at some later point. The process of sending data to clients and storing that data all happens as part of the same process.

CMAltitudeData.timestamp represent—receipt of a sensor reading by the system

However, the problem here is that the details of exactly how our sensors generate and process data vary considerably across our full device range and, in fact, a huge part of locationd's "job" is to provide relatively consistent behavior across a very wide range of sensor implementations. Putting that in more concrete terms, if these differences ACTUALLY matter to your app’s implementation, then I think you're expecting a level of precision that the system was never really designed to provide.

Can a newly delivered event contain an older or filtered pressure measurement whose age is not represented by that timestamp?

No.

For implementation, is comparing that timestamp directly with operation boundaries sampled using ProcessInfo.systemUptime, while monitoring for unexpected divergence, a reasonable approach for this coarse association?

You'll need to test it for yourself, but yes, I expect it will work well. One suggestion on that point— if you're planning on integrating this into an existing, mature implementation, I would strongly suggest writing a VERY simple test app that does nothing but collect the sensor data you're interested in and correlate them with ProcessInfo.systemUptime (or any other source you want to try). I'd probably test "all" the time sources at once just to see how things compared, but the details there don't matter. Partly this is just to quickly confirm that this works the way you want, both so you can avoid wasted effort now and so you can validate things in the future. The "pro move" here would actually be to integrate this into your long-term testing process, so that you'll immediately notice if/when something were to change.

However, the bigger issue is that "real" app implementations often work very differently than people realize, and that disconnect can end up causing large amounts of wasted time and effort. The best way to counter that is to start with a clear understanding of what the "basic" behavior is, so that when something different happens, you'll start by looking at your app’s implementation, not the data.

That leads to here:

"Separately, does CMDeviceMotion (gyroscope/accelerometer) timestamping follow the same software-stamping path, or is IMU data timestamped closer to the sensor?"

Down this path lies madness. The problem here is that:

  1. There's no meaningful time difference between those two cases.

  2. Even if there were a meaningful time difference, there's no way your app can account for or compensate for that difference, so it still doesn't matter.

Since you mentioned CMDeviceMotion, a few other tips/tricks that might be useful:

  • If you're using motion data to drive your interface, the best way to do that is by directly using the latest sample property (CMMotionManager.deviceMotion) in your interface rendering code, NOT by receiving the data on a queue and routing it to your interface. Trying to collect and route the data yourself only introduces additional latency and complexity, which is why the properties exist in the first place.

  • If you're doing user activity tracking, I'd strongly recommend using APIs like CMSensorRecorder or CMBatchedSensorManager, NOT CMMotionManager. CMMotionManager delivers data at a far higher rate than meaningful user analysis requires (humans don't really move at 50hz), so a proper CMDeviceMotion implementation ends up needing to batch up events anyway. Even worse, most of the motion analysis issues I've seen with CMDeviceMotion are caused by the app interfering with its own event delivery, then failing to account for the distortion those delays created. All of those issues go away if you use our non-"real time" APIs.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Thanks, Kevin—this answers our remaining questions and gives us a practical path forward. We’ll start with a minimal test comparing the sensor timestamps with systemUptime, then use that baseline to check our app’s behavior. We’ll keep the claim to coarse association with the capture operation, rather than precision the system wasn’t designed to provide.

Really appreciate the detailed explanations and implementation advice.

CMLogItem.timestamp: which clock is it on, and how to convert to AVCaptureSession.synchronizationClock / host time?
 
 
Q