FAQ
As the x/mobile/app package is moving towards a channel-oriented model
for event dispatching and handling, x/mobile/exp/sensor package may
benefit from similar APIs.

Having multiple instances of sensor.Manager has a performance cost
both on Android and iOS. Rather than allowing users to create multiple
sensor data resources (managers), we can switch to a global single
manager whose events will be consumed by the main package.

Given the constraints above, the changes I am planning to make are below.

- Manager type should not be exported, a Manager instance should be
initiated at package init.
- sensor package should keep providing Enable/Disable functions to
turn on/off which sensor data must be provided from the channel.
- We don't need to deallocate the global Manager instance.
(*Manager).Close is not required anymore.
- sensor events should have their own event types under the
x/mobile/event/motion package.
- Events could be sent to the app events channel via app.Send. Due to
the high frequency nature of the sensor data, using the main app event
channel might be a bottleneck. Alternatively, the sensor package can
export its own channel but we must figure out how to disable the cases
where there are multiple consumers.

The current implementation constraints and how it influenced the
current APIs is explained more in detail at my previous design doc,
https://docs.google.com/document/d/1uZLObF0Ce7NZ6QAqE-jp9dai-rbs8Om4CUw-TmqyLJo/preview.

With the removal of the Reader-like interfaces, we are taking the
oppurtunity to optimize the read rate against the cgo overhead. We
won't be able optimize the number of values we must return each time
we go from Go to C.

Unlike Android NDK, iOS SDK doesn't provide queue based event
buffering. CMMotionManager provides two APIs to read accelerometer
data: `startAccelerometerUpdatesToQueue:withHandler:` and
`accelerometerData`. We either can buffer the event data to an
intermediate buffer as startAccelerometerUpdatesToQueue is invoking
the handler and consume the buffer to send events to the event channel
or periodically poll accelerometerData to see if there is new data.
The initial suggestion may lead to an ever growing buffer if the
consumers stop or work at a low rate. The latter solution might be CPU
intensive and battery draining if we can't optimize how often we
should do the check. Enabling sensors (see the current
(*Manager).Enable) requires users to set a target frequency. As a
primitive solution, we can use this value to sleep between reads.

I am also not sure what should happen if the user is not consuming the
events channel. Should it be ever growing?

I am looking forward to see your input and will be working on a
working prototype to gather benchmarks.

Thanks
Burcu Dogan

--
You received this message because you are subscribed to the Google Groups "golang-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Search Discussions

  • Hyang-Ah Hana Kim at Aug 19, 2015 at 12:28 am
    Thanks for the overview on the upcoming changes.

    2015-08-18 19:48 GMT-04:00 Burcu Dogan <jbd@google.com>:
    As the x/mobile/app package is moving towards a channel-oriented model
    for event dispatching and handling, x/mobile/exp/sensor package may
    benefit from similar APIs.

    Having multiple instances of sensor.Manager has a performance cost
    both on Android and iOS. Rather than allowing users to create multiple
    sensor data resources (managers), we can switch to a global single
    manager whose events will be consumed by the main package.

    Given the constraints above, the changes I am planning to make are below.

    - Manager type should not be exported, a Manager instance should be
    initiated at package init.
    - sensor package should keep providing Enable/Disable functions to
    turn on/off which sensor data must be provided from the channel.
    - We don't need to deallocate the global Manager instance.
    (*Manager).Close is not required anymore.
    - sensor events should have their own event types under the
    x/mobile/event/motion package.
    SGTM.

    One thing: for sensor types supported by the current sensor package,
    'motion'
    seems to be a reasonable choice. But as we add more sensor types, I
    don't know how the event should be structured. Should it be
    x/mobile/event/sensor/blah?


    - Events could be sent to the app events channel via app.Send. Due to
    the high frequency nature of the sensor data, using the main app event
    channel might be a bottleneck. Alternatively, the sensor package can
    export its own channel but we must figure out how to disable the cases
    where there are multiple consumers.
    Can you please add some code snippets that present the usage? Especially,
    I'd like to see how it mixes up with the app package. And, how the
    cancellation
    or Disable would work.

    Also, it would be helpful if you can provide some numbers based on
    benchmark on each approach.

    The current implementation constraints and how it influenced the
    current APIs is explained more in detail at my previous design doc,

    https://docs.google.com/document/d/1uZLObF0Ce7NZ6QAqE-jp9dai-rbs8Om4CUw-TmqyLJo/preview
    .

    With the removal of the Reader-like interfaces, we are taking the
    oppurtunity to optimize the read rate against the cgo overhead. We
    won't be able optimize the number of values we must return each time
    we go from Go to C.
    Can you elaborate on the optimization of the read rate against cgo overhead
    a bit more?

    Unlike Android NDK, iOS SDK doesn't provide queue based event
    buffering. CMMotionManager provides two APIs to read accelerometer
    data: `startAccelerometerUpdatesToQueue:withHandler:` and
    `accelerometerData`. We either can buffer the event data to an
    intermediate buffer as startAccelerometerUpdatesToQueue is invoking
    the handler and consume the buffer to send events to the event channel
    or periodically poll accelerometerData to see if there is new data.
    The initial suggestion may lead to an ever growing buffer if the
    consumers stop or work at a low rate. The latter solution might be CPU
    intensive and battery draining if we can't optimize how often we
    should do the check. Enabling sensors (see the current
    (*Manager).Enable) requires users to set a target frequency. As a
    primitive solution, we can use this value to sleep between reads.
    Sleep or time.Ticker?
    I am also not sure what should happen if the user is not consuming the
    events channel. Should it be ever growing?

    Why cannot drop if the user doesn't consume the data as fast as the user
    requested for?


    I am looking forward to see your input and will be working on a
    working prototype to gather benchmarks.
    Thanks.


    --
    __

    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Burcu Dogan at Aug 19, 2015 at 1:11 am

    One thing: for sensor types supported by the current sensor package,
    'motion'
    seems to be a reasonable choice. But as we add more sensor types, I
    don't know how the event should be structured. Should it be
    x/mobile/event/sensor/blah?
    Good point. I haven't considered what else may need to return
    acceleration, gyroscope or magnetometer event types in the future. If
    there is nowhere else, we can group the motion types under
    events/sensor.
    Can you please add some code snippets that present the usage? Especially,
    I'd like to see how it mixes up with the app package. And, how the
    cancellation
    or Disable would work.
    I will send snippets once I am done with the prototype.
    Can you elaborate on the optimization of the read rate against cgo overhead
    a bit more?
    This optimization only involves the use cases with high frequency sensors.

    The main challenge with the initial implementation was the overhead of
    invoking (*Manager).Read with a buffer that has length is 1. We are
    able to support higher frequencies as the length grows because there
    is an overhead for making the Go to C switch and returning multiple
    values while we are in the C context is faster than doing the
    roundtrip again. The benchmarks I have previously collected for
    different buffer sizes:

    1 event: ~56 usec to read
    8 events: ~240 usec to read
    16 events: ~500 usec to read

    Returning a single event at once is still great if we target to return
    a few events per each frame (at every 1/60 secs). But if we are
    targeting high frequency sensors, the cgo barrier will be more
    significant. At this point, supporting high frequency sensors
    shouldn't be in our scope therefore we can avoid them. On the other
    hand, the availability of such sensors is restricted to a very limited
    number of Android devices. Anyone who requires optimization may write
    their own bindings to NDK.
    Sleep or time.Ticker? Tick.
    Why cannot drop if the user doesn't consume the data as fast as the user
    requested for?
    Agreed that we need a dropping mechanism.

    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Nigel Tao at Aug 19, 2015 at 10:45 am

    On Wed, Aug 19, 2015 at 9:48 AM, Burcu Dogan wrote:
    - Events could be sent to the app events channel via app.Send. Due to
    the high frequency nature of the sensor data, using the main app event
    channel might be a bottleneck.
    How high is this frequency? For example, how many accelerometer events
    per second would you expect, peak?

    I am also not sure what should happen if the user is not consuming the
    events channel. Should it be ever growing?
    It might be worth exploring the idea of adding a buffer argument to
    Enable, perhaps with type []Event, although maybe a little more state
    is required if you want to use it as a ringbuffer.

    Then, the library's event backlog won't grow without bound. If it's a
    ringbuffer, recent events will overwrite (i.e. drop) the oldest
    events. You only get the N most recent events, where N is the length
    of the slice.

    The motion.Event doesn't actually carry the buffer. Instead, it just
    says that there's sensor data available. A separate function lets the
    app atomically swap buffers: the app gives the library an empty buffer
    and takes the (partially or completely) full one. There are no further
    motion.Events sent for that sensor type until the buffer swap, and
    there is no further allocation in the steady state.

    Passing a zero-length buffer to Enable or to Swap means to disable the sensor.

    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • David Crawshaw at Aug 19, 2015 at 2:00 pm

    On Wed, Aug 19, 2015 at 6:45 AM, Nigel Tao wrote:
    On Wed, Aug 19, 2015 at 9:48 AM, Burcu Dogan wrote:
    - Events could be sent to the app events channel via app.Send. Due to
    the high frequency nature of the sensor data, using the main app event
    channel might be a bottleneck.
    How high is this frequency? For example, how many accelerometer events
    per second would you expect, peak?

    I am also not sure what should happen if the user is not consuming the
    events channel. Should it be ever growing?
    It might be worth exploring the idea of adding a buffer argument to
    Enable, perhaps with type []Event, although maybe a little more state
    is required if you want to use it as a ringbuffer.

    Then, the library's event backlog won't grow without bound. If it's a
    ringbuffer, recent events will overwrite (i.e. drop) the oldest
    events. You only get the N most recent events, where N is the length
    of the slice.

    The motion.Event doesn't actually carry the buffer. Instead, it just
    says that there's sensor data available. A separate function lets the
    app atomically swap buffers: the app gives the library an empty buffer
    and takes the (partially or completely) full one. There are no further
    motion.Events sent for that sensor type until the buffer swap, and
    there is no further allocation in the steady state.
    That's clever, and may well be worth it for the scenario when all of
    these conditions hold:

    1. sensor event frequency is very high
    2. the app needs to see all the events
    3. the app cannot keep up

    But this seems to me to be an unusual situation. If an app requests a
    high-frequency event, it should plan on being able to process it.
    Worst case, it can insert its own buffering between the app events
    channel and its processing of an events.

    The cgo calling cost is a problem, but I suspect we can work around it
    if it's significant. For example, if the frequency really is high
    enough the Go side could spin on a couple of buffers, communicating
    state with the C side using atomic ops, and avoid uses of cgocall on
    the hot path. This would be tricky to get right and only a good use of
    CPU in the high frequency case, so a standard cgo version should come
    first.
    Passing a zero-length buffer to Enable or to Swap means to disable the sensor.
    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Burcu Dogan at Aug 19, 2015 at 6:26 pm

    The cgo calling cost is a problem, but I suspect we can work around it
    if it's significant. For example, if the frequency really is high
    enough the Go side could spin on a couple of buffers, communicating
    state with the C side using atomic ops, and avoid uses of cgocall on
    the hot path. This would be tricky to get right and only a good use of
    CPU in the high frequency case, so a standard cgo version should come
    first.

    It is far from being significant. The cgocall cost to read a single event
    is 56 micro secs which means we can support sensors up to ~15kHz without
    optimization.

    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Burcu Dogan at Aug 25, 2015 at 10:41 pm
    Updating the thread with a sample program that consumes the events.

    func main() {
       sensor.Enable(sensor.Accelerometer, time.Millisecond)
       sensor.Enable(sensor.Gyroscope, time.Second)
       go func() {
         for e := range sensor.Events() {
           log.Printf("%v\n", e)
         }
       }()

       go func() {
         <-time.Tick(5 * time.Second)
         sensor.Disable(sensor.Gyroscope)
       }()

       app.Main(func(a app.App) {})
    }

    sensor.Events() will return a chan interface{} and the user is supposed to
    select on type.

    iOS SDK doesn't provide an events queue similar to Android NDK. We ought to
    start a goroutine to pull each time a sensor gets enabled and kill it once
    it is disabled. I don't like the backend mechanism required to support an
    event channel on iOS, since it is:

    - error prone and complex implementation, multiple goroutines need to be
    managed
    - battery drain is a problem, how often to check the status
    - how to report error cases, by returning an error channel?

    Rather than going with an event channel approach, we may prefer to do what
    iOS SDK is already doing. Returning the latest known value from the sensor.
    This strategy requires the Android implementation to have a background
    goroutine and consume the queue continuously. But we don't need to manage
    multiple goroutines because Android can multiplex all the events in a
    single queue. By reading the single queue, we will be able to read all
    sensor data. And Android blocks until new data is available, so we don't
    need to worry how often we should consume the queue and the battery drain
    because our reads will be blocked if there is no data.

    The users who would like to work with a sample of events rather than the
    latest known values can always poll the Go APIs over a period of time.
    On Wed, Aug 19, 2015 at 11:26 AM, Burcu Dogan wrote:

    The cgo calling cost is a problem, but I suspect we can work around it
    if it's significant. For example, if the frequency really is high
    enough the Go side could spin on a couple of buffers, communicating
    state with the C side using atomic ops, and avoid uses of cgocall on
    the hot path. This would be tricky to get right and only a good use of
    CPU in the high frequency case, so a standard cgo version should come
    first.

    It is far from being significant. The cgocall cost to read a single event
    is 56 micro secs which means we can support sensors up to ~15kHz without
    optimization.


    --
    Burcu Dogan

    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • David Crawshaw at Aug 26, 2015 at 1:25 am
    Reading through this thread, I'm unclear why there is a separate
    events channel for the sensor package. It looks like sensor events are
    infrequent enough they can be sent individually on the app event
    channel. Was there something I missed?
    On Tue, Aug 25, 2015 at 6:40 PM, Burcu Dogan wrote:
    Updating the thread with a sample program that consumes the events.

    func main() {
    sensor.Enable(sensor.Accelerometer, time.Millisecond)
    sensor.Enable(sensor.Gyroscope, time.Second)
    go func() {
    for e := range sensor.Events() {
    log.Printf("%v\n", e)
    }
    }()

    go func() {
    <-time.Tick(5 * time.Second)
    sensor.Disable(sensor.Gyroscope)
    }()

    app.Main(func(a app.App) {})
    }

    sensor.Events() will return a chan interface{} and the user is supposed to
    select on type.

    iOS SDK doesn't provide an events queue similar to Android NDK. We ought to
    start a goroutine to pull each time a sensor gets enabled and kill it once
    it is disabled. I don't like the backend mechanism required to support an
    event channel on iOS, since it is:

    - error prone and complex implementation, multiple goroutines need to be
    managed
    - battery drain is a problem, how often to check the status
    - how to report error cases, by returning an error channel?

    Rather than going with an event channel approach, we may prefer to do what
    iOS SDK is already doing. Returning the latest known value from the sensor.
    This strategy requires the Android implementation to have a background
    goroutine and consume the queue continuously. But we don't need to manage
    multiple goroutines because Android can multiplex all the events in a single
    queue. By reading the single queue, we will be able to read all sensor data.
    And Android blocks until new data is available, so we don't need to worry
    how often we should consume the queue and the battery drain because our
    reads will be blocked if there is no data.

    The users who would like to work with a sample of events rather than the
    latest known values can always poll the Go APIs over a period of time.
    On Wed, Aug 19, 2015 at 11:26 AM, Burcu Dogan wrote:

    The cgo calling cost is a problem, but I suspect we can work around it
    if it's significant. For example, if the frequency really is high
    enough the Go side could spin on a couple of buffers, communicating
    state with the C side using atomic ops, and avoid uses of cgocall on
    the hot path. This would be tricky to get right and only a good use of
    CPU in the high frequency case, so a standard cgo version should come
    first.

    It is far from being significant. The cgocall cost to read a single event
    is 56 micro secs which means we can support sensors up to ~15kHz without
    optimization.



    --
    Burcu Dogan
    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Burcu Dogan at Aug 26, 2015 at 1:40 am
    I was assuming that sensor.Events vs using the app event channel is still
    an open question. It sounds good to me use the app event channel.

    Getting back to my previous email, the first question we need to tackle is
    whether we should provide motion sensor data through a channel or not. I am
    proposing to export accessor that returns the latest known value.

    package sensor

    func Acceleration() (timestamp int64, x,y,z float64)
    // ...

    On Tue, Aug 25, 2015 at 6:25 PM, David Crawshaw wrote:

    Reading through this thread, I'm unclear why there is a separate
    events channel for the sensor package. It looks like sensor events are
    infrequent enough they can be sent individually on the app event
    channel. Was there something I missed?
    On Tue, Aug 25, 2015 at 6:40 PM, Burcu Dogan wrote:
    Updating the thread with a sample program that consumes the events.

    func main() {
    sensor.Enable(sensor.Accelerometer, time.Millisecond)
    sensor.Enable(sensor.Gyroscope, time.Second)
    go func() {
    for e := range sensor.Events() {
    log.Printf("%v\n", e)
    }
    }()

    go func() {
    <-time.Tick(5 * time.Second)
    sensor.Disable(sensor.Gyroscope)
    }()

    app.Main(func(a app.App) {})
    }

    sensor.Events() will return a chan interface{} and the user is supposed to
    select on type.

    iOS SDK doesn't provide an events queue similar to Android NDK. We ought to
    start a goroutine to pull each time a sensor gets enabled and kill it once
    it is disabled. I don't like the backend mechanism required to support an
    event channel on iOS, since it is:

    - error prone and complex implementation, multiple goroutines need to be
    managed
    - battery drain is a problem, how often to check the status
    - how to report error cases, by returning an error channel?

    Rather than going with an event channel approach, we may prefer to do what
    iOS SDK is already doing. Returning the latest known value from the sensor.
    This strategy requires the Android implementation to have a background
    goroutine and consume the queue continuously. But we don't need to manage
    multiple goroutines because Android can multiplex all the events in a single
    queue. By reading the single queue, we will be able to read all sensor data.
    And Android blocks until new data is available, so we don't need to worry
    how often we should consume the queue and the battery drain because our
    reads will be blocked if there is no data.

    The users who would like to work with a sample of events rather than the
    latest known values can always poll the Go APIs over a period of time.
    On Wed, Aug 19, 2015 at 11:26 AM, Burcu Dogan wrote:

    The cgo calling cost is a problem, but I suspect we can work around it
    if it's significant. For example, if the frequency really is high
    enough the Go side could spin on a couple of buffers, communicating
    state with the C side using atomic ops, and avoid uses of cgocall on
    the hot path. This would be tricky to get right and only a good use of
    CPU in the high frequency case, so a standard cgo version should come
    first.

    It is far from being significant. The cgocall cost to read a single
    event
    is 56 micro secs which means we can support sensors up to ~15kHz without
    optimization.



    --
    Burcu Dogan


    --
    Burcu Dogan

    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Andrew Gerrand at Aug 26, 2015 at 1:56 am
    In my limited experience with apps that track motion on Android, I
    implemented a callback to handle sensor data events.
    (android.hardware.SensorEventListener) In my case I was logging the data as
    telemetry data for a weather balloon. But that might be an unusual use case.

    I'd be interested to see whether app developers typically implement that
    listener as something that stores the current values, and then have
    accessors on top of that (kind of like what you're proposing here).

    My natural inclination, however, is to go with what the Android and iOS
    SDKs provide. If they both want the user to implement callbacks, then
    perhaps an accessor function is fighting against the grain and we're better
    off providing the sensor data as a stream of events.

    On 26 August 2015 at 11:40, 'Burcu Dogan' via golang-dev wrote:

    I was assuming that sensor.Events vs using the app event channel is still
    an open question. It sounds good to me use the app event channel.

    Getting back to my previous email, the first question we need to tackle is
    whether we should provide motion sensor data through a channel or not. I am
    proposing to export accessor that returns the latest known value.

    package sensor

    func Acceleration() (timestamp int64, x,y,z float64)
    // ...

    On Tue, Aug 25, 2015 at 6:25 PM, David Crawshaw wrote:

    Reading through this thread, I'm unclear why there is a separate
    events channel for the sensor package. It looks like sensor events are
    infrequent enough they can be sent individually on the app event
    channel. Was there something I missed?
    On Tue, Aug 25, 2015 at 6:40 PM, Burcu Dogan wrote:
    Updating the thread with a sample program that consumes the events.

    func main() {
    sensor.Enable(sensor.Accelerometer, time.Millisecond)
    sensor.Enable(sensor.Gyroscope, time.Second)
    go func() {
    for e := range sensor.Events() {
    log.Printf("%v\n", e)
    }
    }()

    go func() {
    <-time.Tick(5 * time.Second)
    sensor.Disable(sensor.Gyroscope)
    }()

    app.Main(func(a app.App) {})
    }

    sensor.Events() will return a chan interface{} and the user is supposed to
    select on type.

    iOS SDK doesn't provide an events queue similar to Android NDK. We ought to
    start a goroutine to pull each time a sensor gets enabled and kill it once
    it is disabled. I don't like the backend mechanism required to support an
    event channel on iOS, since it is:

    - error prone and complex implementation, multiple goroutines need to be
    managed
    - battery drain is a problem, how often to check the status
    - how to report error cases, by returning an error channel?

    Rather than going with an event channel approach, we may prefer to do what
    iOS SDK is already doing. Returning the latest known value from the sensor.
    This strategy requires the Android implementation to have a background
    goroutine and consume the queue continuously. But we don't need to manage
    multiple goroutines because Android can multiplex all the events in a single
    queue. By reading the single queue, we will be able to read all sensor data.
    And Android blocks until new data is available, so we don't need to worry
    how often we should consume the queue and the battery drain because our
    reads will be blocked if there is no data.

    The users who would like to work with a sample of events rather than the
    latest known values can always poll the Go APIs over a period of time.
    On Wed, Aug 19, 2015 at 11:26 AM, Burcu Dogan wrote:

    The cgo calling cost is a problem, but I suspect we can work around it
    if it's significant. For example, if the frequency really is high
    enough the Go side could spin on a couple of buffers, communicating
    state with the C side using atomic ops, and avoid uses of cgocall on
    the hot path. This would be tricky to get right and only a good use of
    CPU in the high frequency case, so a standard cgo version should come
    first.

    It is far from being significant. The cgocall cost to read a single
    event
    is 56 micro secs which means we can support sensors up to ~15kHz
    without
    optimization.



    --
    Burcu Dogan


    --
    Burcu Dogan

    --
    You received this message because you are subscribed to the Google Groups
    "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Burcu Dogan at Aug 26, 2015 at 3:25 am
    I'd be interested to see whether app developers typically implement that
    listener as something that stores the current values

    To briefly summarize two common use cases of sensor data:

    - Basic usage: Use the last known values from the sensors, use them to
    determine an action.
    - More advanced usage: Use a sample of values from multiple values, apply
    filters on them and determine an action. In games, they repeat this
    pipeline of actions once for each 5/10 frames.

    The apps who needs to run sophisticated algorithms need to buffer event
    data. exp/sensor is doing a great job with its Read method currently to
    address this necessity.

    func (m *Manager) Read(e []Event) (n int, err error)

    It buffers the last len(e) samples from multiple sensors and fills the
    buffer, e. It is also relatively easy to use it with a buffer with length=1
    to target the apps who fit in the basic usage group. I was quite happy with
    the current state of the package, but it is contradicting with the app
    event channel driven system.
    If they both want the user to implement callbacks
    I would not consider Android and iOS SDKs. They are both based on
    languages concurrency is hard. By providing handlers, they are handling the
    read/poll in the background and notifying the main thread with the data.
    Callback-based driven APIs are nothing but a limitation of their languages.
    In Go, it is easy for developers to start a goroutine and call a blocking
    API without much work and performance concern.
    On Tue, Aug 25, 2015 at 6:56 PM, Andrew Gerrand wrote:

    In my limited experience with apps that track motion on Android, I
    implemented a callback to handle sensor data events.
    (android.hardware.SensorEventListener) In my case I was logging the data as
    telemetry data for a weather balloon. But that might be an unusual use case.

    I'd be interested to see whether app developers typically implement that
    listener as something that stores the current values, and then have
    accessors on top of that (kind of like what you're proposing here).

    My natural inclination, however, is to go with what the Android and iOS
    SDKs provide. If they both want the user to implement callbacks, then
    perhaps an accessor function is fighting against the grain and we're better
    off providing the sensor data as a stream of events.


    On 26 August 2015 at 11:40, 'Burcu Dogan' via golang-dev <
    golang-dev@googlegroups.com> wrote:
    I was assuming that sensor.Events vs using the app event channel is still
    an open question. It sounds good to me use the app event channel.

    Getting back to my previous email, the first question we need to tackle
    is whether we should provide motion sensor data through a channel or not. I
    am proposing to export accessor that returns the latest known value.

    package sensor

    func Acceleration() (timestamp int64, x,y,z float64)
    // ...


    On Tue, Aug 25, 2015 at 6:25 PM, David Crawshaw <crawshaw@golang.org>
    wrote:
    Reading through this thread, I'm unclear why there is a separate
    events channel for the sensor package. It looks like sensor events are
    infrequent enough they can be sent individually on the app event
    channel. Was there something I missed?
    On Tue, Aug 25, 2015 at 6:40 PM, Burcu Dogan wrote:
    Updating the thread with a sample program that consumes the events.

    func main() {
    sensor.Enable(sensor.Accelerometer, time.Millisecond)
    sensor.Enable(sensor.Gyroscope, time.Second)
    go func() {
    for e := range sensor.Events() {
    log.Printf("%v\n", e)
    }
    }()

    go func() {
    <-time.Tick(5 * time.Second)
    sensor.Disable(sensor.Gyroscope)
    }()

    app.Main(func(a app.App) {})
    }

    sensor.Events() will return a chan interface{} and the user is
    supposed to
    select on type.

    iOS SDK doesn't provide an events queue similar to Android NDK. We ought to
    start a goroutine to pull each time a sensor gets enabled and kill it once
    it is disabled. I don't like the backend mechanism required to support an
    event channel on iOS, since it is:

    - error prone and complex implementation, multiple goroutines need to be
    managed
    - battery drain is a problem, how often to check the status
    - how to report error cases, by returning an error channel?

    Rather than going with an event channel approach, we may prefer to do what
    iOS SDK is already doing. Returning the latest known value from the sensor.
    This strategy requires the Android implementation to have a background
    goroutine and consume the queue continuously. But we don't need to manage
    multiple goroutines because Android can multiplex all the events in a single
    queue. By reading the single queue, we will be able to read all sensor data.
    And Android blocks until new data is available, so we don't need to worry
    how often we should consume the queue and the battery drain because our
    reads will be blocked if there is no data.

    The users who would like to work with a sample of events rather than the
    latest known values can always poll the Go APIs over a period of time.
    On Wed, Aug 19, 2015 at 11:26 AM, Burcu Dogan wrote:

    The cgo calling cost is a problem, but I suspect we can work around
    it
    if it's significant. For example, if the frequency really is high
    enough the Go side could spin on a couple of buffers, communicating
    state with the C side using atomic ops, and avoid uses of cgocall on
    the hot path. This would be tricky to get right and only a good use
    of
    CPU in the high frequency case, so a standard cgo version should come
    first.

    It is far from being significant. The cgocall cost to read a single
    event
    is 56 micro secs which means we can support sensors up to ~15kHz
    without
    optimization.



    --
    Burcu Dogan


    --
    Burcu Dogan

    --
    You received this message because you are subscribed to the Google Groups
    "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an
    email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.

    --
    Burcu Dogan

    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Andrew Gerrand at Aug 26, 2015 at 4:45 am

    On 26 August 2015 at 13:25, Burcu Dogan wrote:

    I would not consider Android and iOS SDKs. They are both based on
    languages concurrency is hard. By providing handlers, they are handling the
    read/poll in the background and notifying the main thread with the data.
    Callback-based driven APIs are nothing but a limitation of their languages.
    In Go, it is easy for developers to start a goroutine and call a blocking
    API without much work and performance concern.

    Sure, but don't we have to use the underlying APIs exposed by those SDKs?

    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Burcu Dogan at Aug 26, 2015 at 5:33 am
    Sure, but don't we have to use the underlying APIs exposed by those SDKs?
    Yes, but we are a consumer of those SDKs. We can't write 1:1 bindings
    because we cant invoke a Go handler from C context. So, the Go package will
    eventually need to implement a polling-based mechanism to retrieve data
    back to the Go context.
    On Tue, Aug 25, 2015 at 9:44 PM, Andrew Gerrand wrote:

    On 26 August 2015 at 13:25, Burcu Dogan wrote:

    I would not consider Android and iOS SDKs. They are both based on
    languages concurrency is hard. By providing handlers, they are handling the
    read/poll in the background and notifying the main thread with the data.
    Callback-based driven APIs are nothing but a limitation of their languages.
    In Go, it is easy for developers to start a goroutine and call a blocking
    API without much work and performance concern.

    Sure, but don't we have to use the underlying APIs exposed by those SDKs?
    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Andrew Gerrand at Aug 26, 2015 at 5:49 am
    Aha, well if the proposed accesor function maps directly to the C function
    call then that SGTM.
    I was concerned that we'd be adding another layer of indirection.
    On 26 August 2015 at 15:33, Burcu Dogan wrote:

    Sure, but don't we have to use the underlying APIs exposed by those
    SDKs?

    Yes, but we are a consumer of those SDKs. We can't write 1:1 bindings
    because we cant invoke a Go handler from C context. So, the Go package will
    eventually need to implement a polling-based mechanism to retrieve data
    back to the Go context.
    On Tue, Aug 25, 2015 at 9:44 PM, Andrew Gerrand wrote:

    On 26 August 2015 at 13:25, Burcu Dogan wrote:

    I would not consider Android and iOS SDKs. They are both based on
    languages concurrency is hard. By providing handlers, they are handling the
    read/poll in the background and notifying the main thread with the data.
    Callback-based driven APIs are nothing but a limitation of their languages.
    In Go, it is easy for developers to start a goroutine and call a blocking
    API without much work and performance concern.

    Sure, but don't we have to use the underlying APIs exposed by those SDKs?
    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Burcu Dogan at Aug 26, 2015 at 6:10 am
    The proposed accessor maps directly to an Obj-C function on iOS. Android
    NDK doesn't have a a function that returns the latest known sensor values.
    The Go package will be continuously consume the underlying events queue on
    Android to retrieve the latest value. Android NDK provides low-level
    optimization options that allows us to run the consumer without performance
    concerns.

    The initial proposal on this thread was to dispatch the events through the
    app event channel which is trivial to implement on Android but might be
    slightly hard to test/maintain on iOS. The underlying mechanism will start
    multiple goroutines to poll the latest known value to feed the channel. We
    need to stop the goroutines if a particular sensor is disabled and restart
    if it is enabled again. I am not sure if the library code should contain a
    sophisticated mechanism given the fact that users can implement it
    themselves by polling the Go accessor easily.
    On Tue, Aug 25, 2015 at 10:49 PM, Andrew Gerrand wrote:

    Aha, well if the proposed accesor function maps directly to the C function
    call then that SGTM.
    I was concerned that we'd be adding another layer of indirection.
    On 26 August 2015 at 15:33, Burcu Dogan wrote:

    Sure, but don't we have to use the underlying APIs exposed by those
    SDKs?

    Yes, but we are a consumer of those SDKs. We can't write 1:1 bindings
    because we cant invoke a Go handler from C context. So, the Go package will
    eventually need to implement a polling-based mechanism to retrieve data
    back to the Go context.
    On Tue, Aug 25, 2015 at 9:44 PM, Andrew Gerrand wrote:

    On 26 August 2015 at 13:25, Burcu Dogan wrote:

    I would not consider Android and iOS SDKs. They are both based on
    languages concurrency is hard. By providing handlers, they are handling the
    read/poll in the background and notifying the main thread with the data.
    Callback-based driven APIs are nothing but a limitation of their languages.
    In Go, it is easy for developers to start a goroutine and call a blocking
    API without much work and performance concern.

    Sure, but don't we have to use the underlying APIs exposed by those SDKs?
    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • David Crawshaw at Aug 26, 2015 at 4:12 pm
    The discussion on this thread is based on hypothetical uses of the
    sensor package, which makes it hard to reason about interface design.
    If we had several programs using sensor data to do common tasks I
    think we could then make concrete statements about the design
    questions here, like polling vs. an active event channel. With what we
    have, I can't say either way.

    As such, I'd like to propose we go with the minimal interface for now,
    where by minimal I don't mean the easiest to implement, but the one
    that most resembles other events (key, mouse, touch, paint, size).
    That is:

    package sensor

    type Event struct {
        ... // actual sensor information
    }

    func Enable()
    func Disable()

    with sensor.Event being delivered on app.Events when sensor data is
    enabled. Once we have that we can try writing some programs and modify
    or expand the interface as needed. Thoughts?
    On Wed, Aug 26, 2015 at 2:10 AM, Burcu Dogan wrote:
    The proposed accessor maps directly to an Obj-C function on iOS. Android NDK
    doesn't have a a function that returns the latest known sensor values. The
    Go package will be continuously consume the underlying events queue on
    Android to retrieve the latest value. Android NDK provides low-level
    optimization options that allows us to run the consumer without performance
    concerns.

    The initial proposal on this thread was to dispatch the events through the
    app event channel which is trivial to implement on Android but might be
    slightly hard to test/maintain on iOS. The underlying mechanism will start
    multiple goroutines to poll the latest known value to feed the channel. We
    need to stop the goroutines if a particular sensor is disabled and restart
    if it is enabled again. I am not sure if the library code should contain a
    sophisticated mechanism given the fact that users can implement it
    themselves by polling the Go accessor easily.
    On Tue, Aug 25, 2015 at 10:49 PM, Andrew Gerrand wrote:

    Aha, well if the proposed accesor function maps directly to the C function
    call then that SGTM.
    I was concerned that we'd be adding another layer of indirection.
    On 26 August 2015 at 15:33, Burcu Dogan wrote:

    Sure, but don't we have to use the underlying APIs exposed by those
    SDKs?
    Yes, but we are a consumer of those SDKs. We can't write 1:1 bindings
    because we cant invoke a Go handler from C context. So, the Go package will
    eventually need to implement a polling-based mechanism to retrieve data back
    to the Go context.
    On Tue, Aug 25, 2015 at 9:44 PM, Andrew Gerrand wrote:

    On 26 August 2015 at 13:25, Burcu Dogan wrote:

    I would not consider Android and iOS SDKs. They are both based on
    languages concurrency is hard. By providing handlers, they are handling the
    read/poll in the background and notifying the main thread with the data.
    Callback-based driven APIs are nothing but a limitation of their languages.
    In Go, it is easy for developers to start a goroutine and call a blocking
    API without much work and performance concern.

    Sure, but don't we have to use the underlying APIs exposed by those
    SDKs?
    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Burcu Dogan at Aug 26, 2015 at 5:06 pm
    I agree. Once the minimal interface is merged, I will focus on solving a
    few real-world examples to give feedback and make improvements.
    On Wed, Aug 26, 2015 at 9:12 AM, David Crawshaw wrote:

    The discussion on this thread is based on hypothetical uses of the
    sensor package, which makes it hard to reason about interface design.
    If we had several programs using sensor data to do common tasks I
    think we could then make concrete statements about the design
    questions here, like polling vs. an active event channel. With what we
    have, I can't say either way.

    As such, I'd like to propose we go with the minimal interface for now,
    where by minimal I don't mean the easiest to implement, but the one
    that most resembles other events (key, mouse, touch, paint, size).
    That is:

    package sensor

    type Event struct {
    ... // actual sensor information
    }

    func Enable()
    func Disable()

    with sensor.Event being delivered on app.Events when sensor data is
    enabled. Once we have that we can try writing some programs and modify
    or expand the interface as needed. Thoughts?
    On Wed, Aug 26, 2015 at 2:10 AM, Burcu Dogan wrote:
    The proposed accessor maps directly to an Obj-C function on iOS. Android NDK
    doesn't have a a function that returns the latest known sensor values. The
    Go package will be continuously consume the underlying events queue on
    Android to retrieve the latest value. Android NDK provides low-level
    optimization options that allows us to run the consumer without
    performance
    concerns.

    The initial proposal on this thread was to dispatch the events through the
    app event channel which is trivial to implement on Android but might be
    slightly hard to test/maintain on iOS. The underlying mechanism will start
    multiple goroutines to poll the latest known value to feed the channel. We
    need to stop the goroutines if a particular sensor is disabled and restart
    if it is enabled again. I am not sure if the library code should contain a
    sophisticated mechanism given the fact that users can implement it
    themselves by polling the Go accessor easily.
    On Tue, Aug 25, 2015 at 10:49 PM, Andrew Gerrand wrote:

    Aha, well if the proposed accesor function maps directly to the C
    function
    call then that SGTM.
    I was concerned that we'd be adding another layer of indirection.
    On 26 August 2015 at 15:33, Burcu Dogan wrote:

    Sure, but don't we have to use the underlying APIs exposed by those
    SDKs?
    Yes, but we are a consumer of those SDKs. We can't write 1:1 bindings
    because we cant invoke a Go handler from C context. So, the Go package
    will
    eventually need to implement a polling-based mechanism to retrieve
    data back
    to the Go context.
    On Tue, Aug 25, 2015 at 9:44 PM, Andrew Gerrand wrote:

    On 26 August 2015 at 13:25, Burcu Dogan wrote:

    I would not consider Android and iOS SDKs. They are both based on
    languages concurrency is hard. By providing handlers, they are
    handling the
    read/poll in the background and notifying the main thread with the
    data.
    Callback-based driven APIs are nothing but a limitation of their
    languages.
    In Go, it is easy for developers to start a goroutine and call a
    blocking
    API without much work and performance concern.

    Sure, but don't we have to use the underlying APIs exposed by those
    SDKs?
    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Burcu Dogan at Aug 29, 2015 at 8:20 pm
    I applied the ideas we have discussed and mailed out two CLs:

    - https://go-review.googlesource.com/#/c/13983/
    - https://go-review.googlesource.com/#/c/14036/
    On Wed, Aug 26, 2015 at 10:05 AM, Burcu Dogan wrote:

    I agree. Once the minimal interface is merged, I will focus on solving a
    few real-world examples to give feedback and make improvements.
    On Wed, Aug 26, 2015 at 9:12 AM, David Crawshaw wrote:

    The discussion on this thread is based on hypothetical uses of the
    sensor package, which makes it hard to reason about interface design.
    If we had several programs using sensor data to do common tasks I
    think we could then make concrete statements about the design
    questions here, like polling vs. an active event channel. With what we
    have, I can't say either way.

    As such, I'd like to propose we go with the minimal interface for now,
    where by minimal I don't mean the easiest to implement, but the one
    that most resembles other events (key, mouse, touch, paint, size).
    That is:

    package sensor

    type Event struct {
    ... // actual sensor information
    }

    func Enable()
    func Disable()

    with sensor.Event being delivered on app.Events when sensor data is
    enabled. Once we have that we can try writing some programs and modify
    or expand the interface as needed. Thoughts?
    On Wed, Aug 26, 2015 at 2:10 AM, Burcu Dogan wrote:
    The proposed accessor maps directly to an Obj-C function on iOS.
    Android NDK
    doesn't have a a function that returns the latest known sensor values. The
    Go package will be continuously consume the underlying events queue on
    Android to retrieve the latest value. Android NDK provides low-level
    optimization options that allows us to run the consumer without
    performance
    concerns.

    The initial proposal on this thread was to dispatch the events through the
    app event channel which is trivial to implement on Android but might be
    slightly hard to test/maintain on iOS. The underlying mechanism will start
    multiple goroutines to poll the latest known value to feed the channel. We
    need to stop the goroutines if a particular sensor is disabled and restart
    if it is enabled again. I am not sure if the library code should contain a
    sophisticated mechanism given the fact that users can implement it
    themselves by polling the Go accessor easily.

    On Tue, Aug 25, 2015 at 10:49 PM, Andrew Gerrand <adg@golang.org>
    wrote:
    Aha, well if the proposed accesor function maps directly to the C
    function
    call then that SGTM.
    I was concerned that we'd be adding another layer of indirection.
    On 26 August 2015 at 15:33, Burcu Dogan wrote:

    Sure, but don't we have to use the underlying APIs exposed by those
    SDKs?
    Yes, but we are a consumer of those SDKs. We can't write 1:1 bindings
    because we cant invoke a Go handler from C context. So, the Go
    package will
    eventually need to implement a polling-based mechanism to retrieve
    data back
    to the Go context.

    On Tue, Aug 25, 2015 at 9:44 PM, Andrew Gerrand <adg@golang.org>
    wrote:
    On 26 August 2015 at 13:25, Burcu Dogan wrote:

    I would not consider Android and iOS SDKs. They are both based on
    languages concurrency is hard. By providing handlers, they are
    handling the
    read/poll in the background and notifying the main thread with the
    data.
    Callback-based driven APIs are nothing but a limitation of their
    languages.
    In Go, it is easy for developers to start a goroutine and call a
    blocking
    API without much work and performance concern.

    Sure, but don't we have to use the underlying APIs exposed by those
    SDKs?
    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.
  • Burcu Dogan at Aug 19, 2015 at 6:24 pm

    How high is this frequency? For example, how many accelerometer events
    per second would you expect, peak?
    Most mainstream Android phones peak at 200Hz whereas iOS SDK has a hard
    limit at 100Hz.
    It might be worth exploring the idea of adding a buffer argument to
    Enable, perhaps with type []Event, although maybe a little more state
    is required if you want to use it as a ringbuffer.

    Then, the library's event backlog won't grow without bound. If it's a
    ringbuffer, recent events will overwrite (i.e. drop) the oldest
    events. You only get the N most recent events, where N is the length
    of the slice.

    The motion.Event doesn't actually carry the buffer. Instead, it just
    says that there's sensor data available. A separate function lets the
    app atomically swap buffers: the app gives the library an empty buffer
    and takes the (partially or completely) full one. There are no further
    motion.Events sent for that sensor type until the buffer swap, and
    there is no further allocation in the steady state.

    Passing a zero-length buffer to Enable or to Swap means to disable the
    sensor.

    There is a simpler solution. If sensor package returns its own channel, we
    can always limit the channel buffer accordingly to ensure the consumer is
    reading from the channel at a good rate.

    package sensor

    var ch chan interface{}

    func Events() <-chan interface{} {
       // TOOD(jbd): guard ch
       if ch != nil {
          return ch
       }

       ch = make(chan interface{}, size)
       e := make([]Event, 1)

       go func() {
         // TODO(jbd): stop the poller if no event types are enabled
         for {
           n, err := m.read(e) // m is the underlying platform specific sensor
    implementation
           if err != nil {
             ...
           }
           for i := 0; i < n; i++ {
             ch <- e[i]
           }
         }
       }()
       return ch
    }

    --
    You received this message because you are subscribed to the Google Groups "golang-dev" group.
    To unsubscribe from this group and stop receiving emails from it, send an email to golang-dev+unsubscribe@googlegroups.com.
    For more options, visit https://groups.google.com/d/optout.

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupgolang-dev @
categoriesgo
postedAug 18, '15 at 11:49p
activeAug 29, '15 at 8:20p
posts19
users5
websitegolang.org

People

Translate

site design / logo © 2022 Grokbase