This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
HPWebcamAble's profile picture

I need a poorly optimized program

Started by HPWebcamAble, 27 October 2015 - 12:28 AM
HPWebcamAble #1
Posted 27 October 2015 - 01:28 AM
So I made a buffer API.

Its a little hard to test though, retrofitting it into a program of mine is difficult as the ones that cause any screen tearing / flickering in MC are really long, plus they aren't even that bad (They are all fine in CCEmuRedux at least)
And I'm finding it difficult to write one that does it on purpose :P/>

So does anyone know of / have a program that might benefit from a buffer?

As long as it causes flickering and won't cause a 'too long without yielding', it should work.
If you only know of long-ish programs (500+ lines), that's ok, I have a use for them too…
HPWebcamAble #2
Posted 27 October 2015 - 04:06 AM
No replies yet, that's ok. I've got more time to optimize it :)/>

FYI just completed a proof-of-concept program that can apply the API to an already existing program
Its pretty cool (still if few bugs of course), but like I said i have limited material to test with, any program suggestions would be appreciated!
MKlegoman357 #3
Posted 27 October 2015 - 07:44 AM
Well, you could run tests like:


local iterations = 1000
local width, height = term.getSize()

sleep(0) --# call this before os.clock() for more accurate results

local start = os.clock()

for i = 1, iterations do
  for x = 1, width do
    for y = 1, height do
      term.setTextColor(2^math.random(0, 15))
      term.setBackgroundColor(2^math.random(0, 15))
      term.setCursorPos(x, y)
      term.write(string.char(math.random(33, 127)))
    end
  end
end

local stop = os.clock()

print("Total time: ", stop - start)
print("Average time: ", (stop - start) / iterations)

Run this code with and without your buffer applied to see the difference.
HPWebcamAble #4
Posted 27 October 2015 - 11:37 PM
Well, you could run tests like:

I briefly tried that, but I missed a few important things (like setting the cursor position before writing the randomized pixels)

(I had to lower the iterations to 100, otherwise I'd get too long without yielding in some tests)
My buffer API did pretty terrible, it added about a second to the total time (Which is an average of 0.0285. Got an average of 0.0175 without my API)

But my experimental program (which I'm calling 'smooth') reduced it from 1.75 seconds total to 1.6 seconds total ;)/>

The program catches term.write calls, and buffers them (with my buffer API). Then it draws the changes when the program it's smoothing yields.
You may have realized this means that the test you provided won't display anything when run by smooth, since it never yields. Which is why the time is reduced.
I'd argue this is good! Most programs draw their GUI, then wait for user input. This is kinda an exception.


I'll do some teaking to my API. It currently is only more efficient when less than half the screen is changed.
I'm using term.write instead of term.blit, I'd expect term.blit to be more efficient when more than half is changed.


If anyone has some programs that I could try to 'smooth', I'd love to experiment with them!
Edited on 27 October 2015 - 10:39 PM
Bomb Bloke #5
Posted 27 October 2015 - 11:44 PM
Heh, anything that uses textutils.slowPrint(), perhaps?
HPWebcamAble #6
Posted 28 October 2015 - 12:37 AM
Heh, anything that uses textutils.slowPrint(), perhaps?

If you're suggesting that my 'smooth' program breaks textutils.slowPrint().. Well it doesn't.

But I'll admit I was worried when you mentioned that, I thought it might not work. But it does work :D/>
Creator #7
Posted 28 October 2015 - 08:40 AM
slowPrint is just a bunch a prints with sleeps in between.
Bomb Bloke #8
Posted 28 October 2015 - 12:28 PM
… which is more or less what most "poorly optimized programs" suffer from: needless delays in between screen updates. Many BigReactor-related scripts, for example, perform a bunch of peripheral calls mid-screen update, which is effectively the same as intentionally sleeping in terms of what it does to the display.

Though I'm sorta guessing that this buffer caches screen updates and then paints the screen once per tick - that'd see it working just fine with slowPrint (in that it wouldn't "smooth it out" when it shouldn't), but it may also mean that it has no positive effect on eg the likes of those particular BigReactors scripts which take multiple ticks to perform a screen update.

If it is working like that, then it'd be pretty similar to the way RecGif figures out exactly what should go into each frame of the animations it creates.
HPWebcamAble #9
Posted 28 October 2015 - 11:27 PM
I'm sorta guessing that this buffer caches screen updates and then paints the screen once per tick

The buffer API itself doesn't draw to the screen automatically.
It requires the program implementing it to tell it when to update the screen.

Which is possibly a flaw, but it allows my program Smooth to work like so:

[Smooth] catches term.write calls, and buffers them (with my buffer API). Then [Smooth] draws the changes when the program yields.
To clarify, Smooth takes 1 argument, the program you want to force-buffer

Usage:
smooth <program path>


I'll probably release both the buffer API and Smooth soon (this weekend, when I finish up a few other things I'm working on)
First I'm going to experiment with different combinations of term.blit and term.write
Edited on 28 October 2015 - 10:28 PM
MKlegoman357 #10
Posted 29 October 2015 - 02:30 PM
I want to note that I have done some tests and the method that slows down drawing is only term.write/term.blit. Methods like setTextColor and setCursorPos don't really take that much time, so the idea here is to have as few write calls as possible.
Edited on 29 October 2015 - 01:30 PM
HPWebcamAble #11
Posted 29 October 2015 - 10:30 PM
I want to note that I have done some tests and the method that slows down drawing is only term.write/term.blit. Methods like setTextColor and setCursorPos don't really take that much time, so the idea here is to have as few write calls as possible.

Yes, thats the basis of my buffer ( and I assume others, though I only know the theory, I've never looked at code in detail )

And I assume doing one term.blit is better than 51 term.writes.
But what number of term.writes is more efficient than 1 term.blit?
Lyqyd #12
Posted 29 October 2015 - 10:42 PM
There isn't one, since you're going to re-send the whole line to the clients regardless of write/blit length. May as well just blit anywhere possible and write where it isn't, at least when dealing with buffers outputting to term objects.
HPWebcamAble #13
Posted 29 October 2015 - 11:17 PM
May as well just blit anywhere possible and write where it isn't

Hm, noted. I'm going to switch my Buffer API to use term.blit instead of term.write, and see how much more efficient it is
Bomb Bloke #14
Posted 30 October 2015 - 12:58 AM
The difference will depend on what you're actually drawing. The two functions operate at very nearly the same speed (I couldn't get any consistent results indicating one was faster than the other), but the number of calls required varies according to the number of colour changes you need to perform, and that will make a fair bit of difference for a sufficiently complex display. Assuming you were otherwise making as few term.write() calls as you needed to, a non-complex display (eg all white text on a black background) will render at about the same speed.
HPWebcamAble #15
Posted 30 October 2015 - 03:11 AM
Update: Using term.blit has improved the API a bunch, it now performs slightly better than without the API :)/>
('It' being MKLegoman's test program)


I'll experiment a bit with different methods of caching the screen, such as different table layouts.
This might actually turn out to be a useful API (at least for me heh heh)


The difference will depend on what you're actually drawing

Since they both technically update the entire line, I decided term.blit would be better, and just have it redraw the whole line even if just one pixel on that line was updated
(Remember that telling the API to buffer a pixel doesn't draw anything, you have to tell it when to draw the changes to the screen)
Edited on 30 October 2015 - 02:14 AM