Scheduling and definition of "display cycle"`

Hi, I found the term "display cycle" mentioned without a def in the most current version of the Reference Manual I've been able to find (for v4.1), in the following context

If several scripts that are visible in the scripting area are running at the same time, all of them are stepped in parallel. However, consider the case of two repeat loops with different numbers of blocks. While not stepping, each script goes through a complete cycle of its loop in each display cycle, despite the difference in the length of a cycle.

Can anyone comment on what a "display cycle" precisely is? Can code from more than one script execute within a given display cycle, and if so, how? Can anyone recommend some material(s) explaining how Snap! 5 scripts get CPU-scheduled in general, i.e., which sort of atomicity guarantees (that is, code guaranteed not to be interrupted by executing code from another script) one can rely on? WARP seems an easy example of an atomicity guarantee; based on the fragment above there seem to be others.

Thanks a lot!

Yes, sorry, this should be better explained in the manual. Next pass...

So, there is no time slicing in Snap!'s scheduler; it works by explicit yields in scripts. The main rule is that a script yields at the bottom of any of the looping blocks. So if a sprite has two scripts, one saying FOREVER [MOVE 10 STEPS] and the other saying FOREVER [TURN 15 DEGREES], the result will be a perfect closed polygon (a near-circle), not a "drunken" one, because each script gets a turn in each cycle.

We talk about display cycles because usually the most time-consuming thing that happens in a scheduling cycle is refreshing the display: moving the sprites, drawing lines, updating the values in variable watchers, updating the direction of the sprite thumbnails in the sprite corral, and so on. So, each sprite runs once, then the display is updated, etc. It's as if the display were a script too.

The programmer can also yield on purpose by using a block with WAIT in its name; in particular, WAIT 0 SECONDS yields but makes the script immediately runnable without waiting.

Because there's no time-slicing, atomicity issues don't arise in most projects; you have to go out of your way to get in trouble. In particular, Snap! guarantees no yield between the test part of an IF and the running of the conditional code -- provided, of course, that that code doesn't yield immediately.

When we want to teach about atomicity, we have to write scripts with random probabilities of waiting explicit in the code. :~)

Fascinating. Thanks very much for the enlightening response. It's a pleasure to interact with people who not only build such a great body of code but also stay around to field random questions from us newbies.

You're welcome. The code's mostly Jens. For me, teaching is the fun part. (Well, for Jens too, but more face-to-face than computer-mediated.)

By the way, if you run Snap!, click on the logo in the top left corner, and choose "Reference Manual" from the menu, you'll get the 5.0 manual.


FOREVER [MOVE 10 STEPS] and the other saying FOREVER [TURN 15 DEGREES], the result will be a perfect closed polygon (a near-circle)

This is very cool but how can one control whether the polygon is rotated 15 degrees or not (i.e. whether the MOVE or TURN happens first)

Hi Ken, the answer I'd like to give is "no", we don't want users to think about the threading inside the protected atomic sections. However, the sequence in which the scripts are run is not really arbitrary, so, clever users have found out that you can prioritize one script over another by brining its (omg, I'm not really saying this, but here ya go) "layer" on top (the script you've last picked up and dropped with the mouse will be first to go). You can see why relying on this is probably a bad idea...

I just tried to see if adding WAIT 0.001 just above one of the FOREVERs and WAIT 0.002 before the other FOREVER would guarantee that the one with 0.001 FOREVER would go first. Seemed to work fine.

Someday when scripts are first class you'll be able to apply the MOVE TO FRONT block to them! :~)

Without knowledge of threading internals it's hard to explain output of this script.

60 iterations (screen refresh rate) of empty loop took 1s. So literally every loop is slowed down to only one iteration per video frame. The same is true for calculation and sprite update scripts. It can lead to unexpected slow down not justified by script complexity and without processor load.
So every non UI script must be "warped" to get some decent performance. For not so trivial script it can be more suitable to run in "turbo" mode but there are no way to force screen updates on demand. Unfortunately "wait 0" doesn't work this way

Ways to avoid it:

  1. Write reporters, which are automatically warped.
  2. Use the warp block.
  3. Use recursion instead of looping, so there are no automatic yields.

It's purely undocumented, internal thread model behaviour. So it's quite legit :smile:

for the sake of performance and usability.

Someday when scripts are first class

But, Snap!'s motto is "Everything fist class"; scripts aren't though? What are grey rings then?

"Everything first class" is aspirational; we're progressing slowly. First class costumes and sounds are new in 5.0.

As for scripts, we suffer from a paucity of language. The script, understood as a procedure, is first class, but you can't examine its innards; you can't, for example, ask for its arity (how many inputs it takes). But "script" also means the text of the script--the blocks that make it up. That's what I want to make first class, so you can, for example, look to see what procedures (blocks) it calls. My plan is to have two primitives converting back and forth between a script and a list structure that embodies the abstract syntax tree for the script. Then you can interrogate it with ordinary list operations.

OK (Post must be at least four characters, so I decided to add this parenthetical statement; it's definitely > 4 now)