-
Notifications
You must be signed in to change notification settings - Fork 59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Call 'onchange' on a Senor instance considering its own frequency hint #152
Comments
@tobie PTAL |
There's a difference between obtaining the same data at t0 and t1 (in terms of what this info confers about actual polling frequency, latency, etc.), so we can't just do away with it in some cases. We could however make this behavior opt in or opt out, though. |
than, if we have two sensors: one with polling frequency 5Hz and another with 60Hz, and they both reference to the same shared reading instance. How often |
This gets very complicated very quickly, especially when you start getting sensors with multiple values, even more so if you include a primary/secondary distinction as we might want to (see #151). If think specifying this more clearly is a really good thing and I'm happy (and impressed) you guys are willing to do such a thorough job of thinking this through. The easy answer here is to follow what Android does (report at 5Hz no matter what), but I really want to include this in the broader reflection I'm having on this right now. |
The way Can we just specify that
|
I agree. But that's been argued against a number of times (and I lost these arguments). Terseness trumped correctness here.
Yes, that's a good point. This wasn't an issue before, as I thought implementers were not going to be willing to send events are different frequencies to the different instances for perf reasons (and implementation complexity).
Some use cases (notably motion sensors) might need data sent at regular intervals regardless of whether the sensor values changed, we'll need to dig into this a bit more.
That's the Android way mentioned above and might be the reasonable thing to do. |
@tobie can you link to the issues/threads? In one of my original explanations, I defined both an "ondata" and "onchange" event: https://bugzilla.mozilla.org/show_bug.cgi?id=910150#c5.
I'm not arguing for those semantics—just that I think two events might be ideal (this has always been the design of all sensor classes in J5) |
It's the result of a bunch of discussions, meetings, decisions in meetings, etc. Some rationales jotted down here: #78 (comment). That said, I'm refactoring a bunch of things and open to reconsidering this in the process. |
Originally, J5 had a "read" event, which matches your suggestion here. Eventually that was renamed "data", simply to match the rest of Node.js platform. |
In fixing this, the precise timing of when data changes should also be defined. In https://codereview.chromium.org/2551223003/ there's a change to make the change itself and the event aligned with animation frames, and maybe that's what you want. FWIW, it's not obvious to me that this is what you want. If you have a sensor that produces data faster than animation frames and that data is used to influence Web Audio, faster than 60 Hz could make sense. |
@foolip wow. My understanding from raising this issue with blink folks a while back was that there was no way to sync the frame clocks with the sensor polling. So that's pretty exciting if it's solvable! There's an open issue on this topic here: #4. Note the main reason to request polling frequencies that are great than framerate are:
It feels like this might need a different notation, e.g.: new Gyroscope({ frequency: "2pf" });
// or
new Gyroscope({ readingsPerFrame: "2" }); Thoughts? |
I actually don't know about this. It's not hard to just delay the observable state change and the corresponding event to animation frame timing, but I don't know if that's all that's happening, or if one can also tickle the sensors into sampling and providing data really close to the animation frames. Will defer to @pozdnyakov on that, as long as observable behavior is well defined I'm happy :) |
OK, so that's different, right? The key reason for sampling > display rate is to reduce latency (so you only grab the latest value, but it's as close to the moment where you push pixels to the screen buffer as possible). Being able to sync the polling with rAF would enable similar low latency but avoid polling the sensor so often (for reference, oculus rift polls the gyroscope at 1KHz, but discards all but the latest reading for each frame). If the only thing we're doing, however, is delaying the task that updates the sensor object so it happens right before the new frame, we want to make sure we get the timestamps from when the sensor was polled and not from when the data shows up in JS. |
Sensor polling and sending of 'onchange' event are different things (in Chromium even done in different processes): physical sensor is polled on platform side (and timestamp for reading is fetched from platform) considering the given frequency hint; updating of reading object on JS side and sending of 'onchane' event are synchronized with rAF (so can be deferred a bit) so that Critical Rendering Path is not interrupted and CPU and battery are not drained. |
OK, that is what I initially guessed, that state changes and events are simply delayed to animation frame timing. |
@foolip: that sounds like a non-normative perf improvement, now, no? I could nevertheless add a note along the lines of:
WDYT? |
It's an observable difference that web developers could have reason to care about, so can't the spec require a certain timing? (Otherwise, one might want to requestAnimationFrame in the event handler.) The timing of certain other events is guaranteed by https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-processing-model and in whatwg/html#707 we're thinking about introducing an "animation frame task" concept. Although it is tricky, it is possible to test the timing to some degree, see https://github.com/w3c/web-platform-tests/blob/master/fullscreen/api/element-request-fullscreen-timing-manual.html#L30 |
So I think specifying the processing model precisely and tying it to the event-loop makes a lot of sense for almost all use cases. We can always provide an |
Think we must distinguish between polling frequency (one which is used by the actual device sensor to poll data) and update frequency (how often a JS Sensor object notifies its updates). |
We certainly need to be moving in a direction where we distinguish polling frequency from reporting frequency. For low-level motion sensors, which are essentially going to be used as below (so without event handlers), I think we should make polling frequency settable and be more than a hint (but be clamped to HW values, obviously). let gyro = new Gyro({ pollingFrequency: 120 });
function display() {
requestAnimationFrame(function() {
document.getElementById("foo").innerText = `x: ${gyro.x}, y: ${gyro.y}, z: ${gyro.z}`;
display();
});
}}; We'd also need sound default values for If we move towards supporting BYOB for motion sensors, we'll need to think of reporting frequency in terms of "your buffer is full and needs to be swapped." I like how you're thinking about these two different frequencies once in term of update frequency and once in term of latency. I'd probably argue for thinking about it differently (and I have use cases to back it up that I still need to write up), but I think we're converging here. :) |
^ @jimmy-huang now you are implementing sensor support for Zephyr, I know that you and Geoffrey had discussions regarding frequency and buffers. Could you please have a look at this issue? |
Basically the issue you have on some devices (like the Intel based Arduino 101), is that the actual sensor core sampling frequency might be faster than IPC can handle and thus, data needs to be buffered up and transferred in chunks. |
Why using a faster IPC (i.e. shared memory) is not an option? |
It might be, I don't know, but maybe that is not an option on the Arduino 101 on Zephyr. I don't think you can do shared memory between the x86 and ARC core. @jimmy-huang should be able to answer that better. |
It's not the IPC that's the bottleneck per se, there's ringbuffer that we use that stores the callbacks since the sensor readings are coming in from an interrupt and we have to queue them up so it can be serviced in another context, and if the thread executing the JS application is not able to service them fast enough, the ringbuffer just fills up. The interrupt can be calling in like 1600Hz, where the JS engine might be only able to service the JS calls at 100Hz, and possibly slower if we are sending it out over BLE, as since each onchange() call, we have no control over how long the app returns control. |
The first, once shared reading is updated each of the Sensor instances either sends updates immediately or schedules update sending.
Nothing, in this case continue waiting for shared reading update and notify immediately Please see #210 |
So this won't send the freshest data available, right? I wonder if that's actually the behavior that developers want. |
mm.. why not? It will always send the freshest available data (i.e. freshest at the moment of sending). |
I was referring to the scheduled update sending. |
on scheduled update Sensor should do both 1) update its reading from shared reading and 2) fire |
Fixes w3c#152. Each Sensor instance reads the sensor readings considering its individual frequency hint, sends 'onchange' and caches the sensor latest reading at this moment. The Sensor's attributes return values from the cached reading. Thus we achieve: - appearance of a new Sensor instance with a higher frequency hint does not affect the 'onchange' notification of the existing Sensor instances of the same type. - consistency between the Sensor's 'onchange' notification and its attribute values. Fixes w3c#168. A Sensor object returns reading values only in "activated" state and returns null otherwise.
OK. So is the only point of the cache to make sure that |
Not really, the point is that Sensor A is decoupled from Sensor B. |
Right, but that's completely orthogonal to the existence of a per instance cache of the sensor reading. See, this is precisely why I don't like merging huge diffs in. ;) I'm not saying the per instance cache might not be a desirable feature, but it's unrelated to what you describe above, which is just eventing mechanics. |
to me more clear: Each object returns the cached values from the reading attributes, so that contained data is consistent with |
Well, yes. That's an effect of the caching. My question is: is this desirable, given (1) none of the other behavior we agree we want to add depend on this, and (2) |
Thanks for the links! This is exactly what I had asked for at #152 (comment) :) Still I would like to hear people's opinion on whether it is OK if appearance of one object transparently modifies behavior of another object. |
Oops, sorry. :-/
What do you mean by behavior, here? Getting the value of attributes returning a fresher value or something else? |
yeah, that Reading through #8, I found that the rational for returning the same values from all Sensor objects is Generic thoughts: We do not have good options till we have multiple Sensor instances bound to the same platform sensor: Option 1 (the current ED): Problems: basically described in this issue
Option 2 (#8 (comment)): All Sensor objects point to the same data but the Problems:
Option 3 (#210)
(In the above list I did not mention implementation complexity and memory&cpu resources required: it is increasing steadily from option 1 to option 3) The only good option would be having 1-to-1 mapping between Sensor object and platform sensor. Even though #8 and #9 are closed I propose to file a new dedicated issue and start working on it. |
I'm kind of confused why we would move back to option 1 after having had consensus to move to option 2 or option 3. I initially spec'ed option 1 because my understanding was that it was (a) what was implemented in both Android and iOS and thus something developers would be used to (according to you, that's not the case), and (b) it would be a lot simpler and less resource hungry to implement.
I'm no longer sure about that actually. It becomes especially complicated if we need both rAF-sync and non-rAF sync on the same page. Decoupling the sensor object from sensor observers is something I suggested in the past already and that could make sense looking into again, but I don't think we'd be able to move to a singleton altogether. |
From #152 (comment) I understood that you were opposed to option 3 or did you mean something else? |
I not sure how you've read this from that comment, tbh. What I've been trying to do is get everyone on the same page with making a distinction between option 2 and 3 (as so far this had been conflated, notably in the pull requests you made). I agree that there are other options we could/should explore (such as splitting sensor and observer into two different objects as mentioned above). |
@tobie @pozdnyakov I hope you don't mind hijacking discussion 😄 could everyone answer simple two questions:
|
I treated "(1) none of the other behavior we agree we want to add depend on this, and (2) === was a requirement (see #8)." as a kind of stopper for option 3. If it was not the case, I'm happy to proceed with option 3. @alexshalamov I'd prefer |
I don't think it would be, though. The new task both sets the value that |
Sorry, I confused option 2 and 3 here (I thought they were ordered chronologically, not in order of increasing implementation cost and complexity). So: option 2, we're good to do; option 3 we don't have consensus on (we might end-up doing so, but I'm not sure we want to do so yet). That is: per instance reporting frequency: yes. |
Ok, let's follow option 2 for now, I'll update #210 accordingly |
+1 for option (2), if we rename |
…its individual frequency hint. Thus we achieve that appearance of a new Sensor instance with a higher frequency hint does not affect the 'onchange' notification of the existing Sensor instances of the same type.
@tobie, PR #210 has been updated to reflect the consensus position, quoting it here for clarity:
Could you review #210 and let us know if you have any concerns. Thanks! |
…its individual frequency hint. Thus we achieve that appearance of a new Sensor instance with a higher frequency hint does not affect the 'onchange' notification of the existing Sensor instances of the same type.
…its individual frequency hint. Thus we achieve that appearance of a new Sensor instance with a higher frequency hint does not affect the 'onchange' notification of the existing Sensor instances of the same type.
…d internal slots used in the Sensor interface specification. The refactoring goals are: Recompose abstract operations so that duplication of the algorithms steps is removed. Drop the unused abstract operations and internal slots. Also the change brings the following behavioral changes: Fixes w3c#152. Each Sensor instance reads the sensor readings considering its individual frequency hint, sends 'onchange' and caches the sensor latest reading at this moment. The Sensor's attributes return values from the cached reading. Thus we achieve: appearance of a new Sensor instance with a higher frequency hint does not affect the behavior of the existing Sensor instances of the same type. consistency between the Sensor's 'onchange' notification and its attribute values. Fixes w3c#168. A Sensor object returns reading values only in "activated" state and returns null otherwise. Fixes w3c#199 Fixes w3c#200 Fixes w3c#201 Fixes w3c#203
The spec says: "onchange is an EventHandler which is called whenever a new reading is available."
Would it be better if
onchange
was called only when reading values (except timestamp) are actually changed? User most probably is interested in data fields changing, so callingonchange
only on actual data change would reduce client code and save some cpu instructions.The text was updated successfully, but these errors were encountered: