|Syntactic Confectionery Delight|
Welcome to the Monastery.
I'm running Perl 5.32.0 and Tk 804.035. I have a reasonably high-end rig with a fairly powerful GPU (RTX 2080 Ti). This could easily affect the outcome. What do you have?
The $size variable starts at 410. I increased this, via the Entry box, to 600, then 1000, then 2000. With each increase, rendering was progressively slower (at 2000, the rendering seemed to take some minutes). However, at no point did I experience any hangs or exception messages.
In a current Tk project, I have a canvas with around 2000x1000 pixels. It contains a very large number of elements, which include lines, arcs, rectangles, polygons, as well as Photo and Bitmap images. This renders in about one second: substantially different from what I'm seeing with your code.
"... idletasks ... but I'm not sure exactly what is going on."
There are two methods for updating the display: idletasks() and update(). Both are described in Tk::Widget. You've got the correct one (idletasks()) here but you're only interested in updating the canvas. Change
Calling this intermittently in a for loop is correct; however, you also need to do so after the loop:
Unless the if is TRUE on the last iteration, you'll end up with a strip that isn't updated. This fixes that.
You can also play around with the if condition to get an optimal value based on the range of numbers you're expecting.
"... more than say 400x400 pixels worth of stuff on a canvas, it tends to bog down ..."
There are a lot of places where you're repeating operations needlessly. Consider:
The calculations involving $i are repeated on every iteration of the inner loop; however, the results only change in the outer loop. $a and $b are special variables, so you should avoid using them; but, you don't need either of them, nor do you need $c. You could have written:
Having done that, you may notice that both of those sprintf calls can only result in 256 different values each. With your small, default $size of 410, the inner loop is entered 168,100 times; that number grows exponentially as $size is increased. If you precalculated all 512 possible sprintf values, you could reduce the code further to something like:
You could go a step further by caching @USE. If $size doesn't change, nor will @USE: don't run through those hundreds of thousands (or potentially millions) of iterations when you already have the result. You could use something along these lines:
If you look down the code to the next nested for loops, you'll see something similar: you're calculating $i*$ps and $i*$ps+$ps on every iteration of the inner loop when the value only changes in the outer loop. Also, the assignment to $c is pointless: you could write "-fill=>$USE[$i][$j],-outline=>$USE[$i][$j]" and have no need of the extra $c variable.
I'll leave it there as I think I've written more than enough. Look through all of your code for further opportunities for improvement.