~eliasnaur/gio

4 2

profiling framerate and fixing blocking code in widgets

Details
Message ID
<G90sRdpR-Oz8ZhyevgTlvRXhCTeIQVJ1KgZThHxlrWKrp7-WUBGZmZjuW8ocYNrP8sOAsYe7xcwPxNCv6esUZEUMMkdn3hiUW-lDmrgs2wg=@protonmail.ch>
DKIM signature
pass
Download raw message
I am in the process of finding various ways to trace concurrency issues in my application ( https://github.com/p9c/pod ), code is spiced through the widgets it can be difficult to figure out where to look to fix an issue that is causing framerate and event timing problems.

So I'm just wondering how other people do it, finding and eliminating, or better, preventing such bugs creeping in and making the interface (nearly) unusable, as I think that there should be some kind of set of axioms or rules of thumb for how to connect background processing to the front end without stalling the front end. Synchronisation primitives are the suspects in my current bit of debugging, either waiting channels or mutexes, which complicates things. I am also a little suspicious that it's not good to start goroutines inside widgets.


Sent with ProtonMail Secure Email.
Details
Message ID
<vx7SX3vOLIloNZNW2s-c2NhlI--JiGtP6pHQwkhYlFB2J8jdUJI-u3ALaHgb9YqYRScUASJ9T7aMbjFIWnk_0PWHmH6CQrycRSksz9aXLHE=@protonmail.ch>
In-Reply-To
<G90sRdpR-Oz8ZhyevgTlvRXhCTeIQVJ1KgZThHxlrWKrp7-WUBGZmZjuW8ocYNrP8sOAsYe7xcwPxNCv6esUZEUMMkdn3hiUW-lDmrgs2wg=@protonmail.ch> (view parent)
DKIM signature
pass
Download raw message
apologies for the lack of line breaks, first time using this mailing list.

Sent with ProtonMail Secure Email.

‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐

On Monday, December 28th, 2020 at 21:20, Loki Verloren <stalker.loki@protonmail.ch> wrote:

> I am in the process of finding various ways to trace concurrency issues my application
( https://github.com/p9c/pod ), is spiced through the widgets it can be difficult to
figure out where to look to fix an issue that is causing and event timing problems.
>
> So I'm just wondering how other people do it, finding and eliminating, or better,
> preventing such bugs creeping in and the interface (nearly) unusable, as I think that
> there should be some kind of set of axioms or rules of thumb for how to connect
> background processing to the front end without stalling the front end.
>
> Synchronisation primitives the suspects in my current bit of debugging, either waiting
> channels or mutexes, which complicates things. I am also a little suspicious that it's
> not good to start goroutines inside widgets.
>
> Sent with ProtonMail Secure Email.
Details
Message ID
<CAE_4BPC4Y9o769wcyVbWt1Bkt4WccVqo7tTH6PLc=jW4_0YfWA@mail.gmail.com>
In-Reply-To
<G90sRdpR-Oz8ZhyevgTlvRXhCTeIQVJ1KgZThHxlrWKrp7-WUBGZmZjuW8ocYNrP8sOAsYe7xcwPxNCv6esUZEUMMkdn3hiUW-lDmrgs2wg=@protonmail.ch> (view parent)
DKIM signature
missing
Download raw message
Good questions.  First off, I'd agree that starting a goroutine in
widget layout code is probably a bad idea.

In general, you want to remember that your layout code could run 0
times per second, or 60+ times per second, and code accordingly.  Both
situations require care.

If your layout code isn't called at all (maybe your app is iconified),
will your app crash or hang?  If it's called at 60 Hz, will it crash /
hang / fork a gazillion goroutines?  If a cat takes a nap on the
keyboard (causing a redraw per keystroke if a text field has focus),
will your app be okay?

If you call a function, how long will it take?  Can it hang?  Does it
hit a network or a database or a file (or read a channel)?  You
probably shouldn't be doing any of those things in your layout code.

Layout should display the application state and as little else as
possible.  Actually mutating that application state should happen
asynchronously in other goroutines.

So if you *do* need to hit the network or a database or whatever, send
a request to a channel and move on.  The channel listener should do
whatever it does and signal your display code to do an Invalidate.

And if the channel is buffered, what if it's full?  If it's
unbuffered, what if the send blocks?  And vice versa for channel
reads.

One way to think about all this is: if you ripped out all your layout
code, could you simulate user interaction?  Like, if you have a button
that the user can press, could you write code to essentially simulate
the user pressing that button?  (Your app doesn't *have* to be, like,
100% scriptable — I'm pretty sure mine isn't! — but thinking about
whether it is or why it's not can help you keep appropriate separation
of concerns.)

Hope that helps.

-- Larry

On Mon, Dec 28, 2020 at 3:20 PM Loki Verloren
<stalker.loki@protonmail.ch> wrote:
> I am in the process of finding various ways to trace concurrency issues in
> my application ( https://github.com/p9c/pod ), code is spiced through the
> widgets it can be difficult to figure out where to look to fix an issue that
> is causing framerate and event timing problems.
>
> So I'm just wondering how other people do it, finding and eliminating, or
> better, preventing such bugs creeping in and making the interface (nearly)
> unusable, as I think that there should be some kind of set of axioms or
> rules of thumb for how to connect background processing to the front end
> without stalling the front end. Synchronisation primitives are the suspects
> in my current bit of debugging, either waiting channels or mutexes, which
> complicates things. I am also a little suspicious that it's not good to
> start goroutines inside widgets.
>
>
> Sent with ProtonMail Secure Email.
Details
Message ID
<X1-yYXBy391RHwxd73oHKrzB6W9LtRreoF2JTGe-BfgmoQHzvjM3jtJbReEgtz_wCfFO_DPIIh3LF3wj1FIiOMb69esfjfIlyxk-dXZSw3Q=@protonmail.ch>
In-Reply-To
<CAE_4BPC4Y9o769wcyVbWt1Bkt4WccVqo7tTH6PLc=jW4_0YfWA@mail.gmail.com> (view parent)
DKIM signature
pass
Download raw message
One thing that has occurred to me this morning as I am working through the process
of finding the code that is causing problems is that as they are implemented in most
versions, the event handlers for press, click and release are function calls.

Maybe they could be changed into a channel instead of function call `chan func()`
so they are sent to one buffered handler that runs the event callbacks
asynchronously by default, processing them first in first out as a channel queue
runs.

This would also neck down the processing into one thread and eliminate race
conditions in event handlers, they could be written with the mind of them existing
in one thread ordered exactly as they were generated.

It's not directly on the subject but event callbacks definitely can cause stalls
in the queue so it's one area that I know by the operation of the app needs
attention.

Note: protonmail's interface doesn't quite incorporate support for mailing list
replies, sorry to larry for emails direct to his address.

Sent with ProtonMail Secure Email.

‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐

On Monday, December 28th, 2020 at 23:17, Larry Clapp <larry@theclapp.org> wrote:

> Good questions. First off, I'd agree that starting a goroutine in
>
> widget layout code is probably a bad idea.
>
> In general, you want to remember that your layout code could run 0
>
> times per second, or 60+ times per second, and code accordingly. Both
>
> situations require care.
>
> If your layout code isn't called at all (maybe your app is iconified),
>
> will your app crash or hang? If it's called at 60 Hz, will it crash /
>
> hang / fork a gazillion goroutines? If a cat takes a nap on the
>
> keyboard (causing a redraw per keystroke if a text field has focus),
>
> will your app be okay?
>
> If you call a function, how long will it take? Can it hang? Does it
>
> hit a network or a database or a file (or read a channel)? You
>
> probably shouldn't be doing any of those things in your layout code.
>
> Layout should display the application state and as little else as
>
> possible. Actually mutating that application state should happen
>
> asynchronously in other goroutines.
>
> So if you do need to hit the network or a database or whatever, send
>
> a request to a channel and move on. The channel listener should do
>
> whatever it does and signal your display code to do an Invalidate.
>
> And if the channel is buffered, what if it's full? If it's
>
> unbuffered, what if the send blocks? And vice versa for channel
>
> reads.
>
> One way to think about all this is: if you ripped out all your layout
>
> code, could you simulate user interaction? Like, if you have a button
>
> that the user can press, could you write code to essentially simulate
>
> the user pressing that button? (Your app doesn't have to be, like,
>
> 100% scriptable — I'm pretty sure mine isn't! — but thinking about
>
> whether it is or why it's not can help you keep appropriate separation
>
> of concerns.)
>
> Hope that helps.
>
> -- Larry
>
> On Mon, Dec 28, 2020 at 3:20 PM Loki Verloren
>
> stalker.loki@protonmail.ch wrote:
>
> > I am in the process of finding various ways to trace concurrency issues in
> >
> > my application ( https://github.com/p9c/pod ), code is spiced through the
> >
> > widgets it can be difficult to figure out where to look to fix an issue that
> >
> > is causing framerate and event timing problems.
> >
> > So I'm just wondering how other people do it, finding and eliminating, or
> >
> > better, preventing such bugs creeping in and making the interface (nearly)
> >
> > unusable, as I think that there should be some kind of set of axioms or
> >
> > rules of thumb for how to connect background processing to the front end
> >
> > without stalling the front end. Synchronisation primitives are the suspects
> >
> > in my current bit of debugging, either waiting channels or mutexes, which
> >
> > complicates things. I am also a little suspicious that it's not good to
> >
> > start goroutines inside widgets.
> >
> > Sent with ProtonMail Secure Email.
Details
Message ID
<CAE_4BPCWHVH7HNsrN8sbzz2oRG=SeggpmS9yR8oj3u2SPecPSQ@mail.gmail.com>
In-Reply-To
<X1-yYXBy391RHwxd73oHKrzB6W9LtRreoF2JTGe-BfgmoQHzvjM3jtJbReEgtz_wCfFO_DPIIh3LF3wj1FIiOMb69esfjfIlyxk-dXZSw3Q=@protonmail.ch> (view parent)
DKIM signature
missing
Download raw message
> Note: protonmail's interface doesn't quite incorporate support for mailing list
> replies, sorry to larry for emails direct to his address.

:)  No worries.

On Tue, Dec 29, 2020 at 4:27 AM Loki Verloren
<stalker.loki@protonmail.ch> wrote:
> One thing that has occurred to me this morning as I am working through the process
> of finding the code that is causing problems is that as they are implemented in most
> versions, the event handlers for press, click and release are function calls.
>
> Maybe they could be changed into a channel instead of function call `chan func()`
> so they are sent to one buffered handler that runs the event callbacks
> asynchronously by default, processing them first in first out as a channel queue
> runs.

That would seem to remove one of the biggest benefits of "immediate
mode" of Gio, which is (more or less) no callbacks.  Processing user
events inline, synchronously, is one of the big simplifiers of Gio /
immediate-mode code.  Perhaps I'm misunderstanding you.

In any case, note that you could implement what you're asking for on
top of the current architecture, so you can give it a shot if you
like.

> This would also neck down the processing into one thread and eliminate race
> conditions in event handlers, they could be written with the mind of them existing
> in one thread ordered exactly as they were generated.

But that's true now, though, so far as I know / understand.  If you
traced all the Layout code from the top to the bottom, it'd all be in
one thread.  That's why layout code is generally lock-free with
respect to other layout code.

Now, as I've mentioned earlier, if you need to do anything that takes
a long time, you do need to talk to a different goroutine.  But I
don't think a single-threaded event queue would solve that.

-- Larry
Reply to thread Export thread (mbox)