After print job completes issue

def testfunc3(cmd): if cmd[:1] != 'O': return

And then again, there's this.

@foosel I figured it would be some overhead but not 7x!

@OutsourcedGuru Ran it just to see and yeah not much diff there.

100000000   11.742    0.000   11.742    0.000 test.py:12(testfunc3)
100000000   12.606    0.000   12.606    0.000 test.py:2(testfunc)
100000000   27.575    0.000  141.491    0.000 test.py:7(testfunc2)

Well, now you know why I do precompile all regexes and why there are so many string checks followed by regex matching on success in the comm layer :wink:

Well, it's a 7% reduction in this case. It just highlights the difference between a single character comparison with that of strings.

And where does startswith fall in that list?

def testfunc4(cmd):
    if not cmd.startswith("OCTO"):
        return

My money would be on "on par with substring comparison" as I suspect it's pretty much the same as cmd[:4] == 'OCTO'.

Def some overhead w/ startswith() but it's not terrible.

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
100000000   10.210    0.000   10.210    0.000 test.py:12(testfunc3)
100000000   18.220    0.000   27.262    0.000 test.py:16(testfunc4)
100000000   11.285    0.000   11.285    0.000 test.py:2(testfunc)
100000000   31.945    0.000  181.042    0.000 test.py:7(testfunc2)
import re
def testfunc(cmd):
    if cmd[:4] != 'OCTO':
        return


def testfunc2(cmd):
    match = re.search(r'^(OCTO[0-9]+)(?:\s(.*))?$', cmd)
    if match is None:
        return

def testfunc3(cmd):
    if cmd[:1] != 'O':
        return

def testfunc4(cmd):
    if cmd.startswith('OCTO'):
        return

i = 0
while i < 100000000:
    testfunc('OCTO999')
    i += 1

i = 0
while i < 100000000:
    testfunc2('OCTO999')
    i += 1

i = 0
while i < 100000000:
    testfunc3('OCTO999')
    i += 1


i = 0
while i < 100000000:
    testfunc4('OCTO999')
    i += 1

Just for ducks...

testfunc5 = lambda x: x[:1] != 'O'

testfunc6 = lambda x: ord(x[:1]) - 79

Now you've gone too far. TOO FAR

1 Like

http://www.sizecoding.org/wiki/Main_Page

1 Like

@b3st0fth3w0rst v1.0.0 was released.

:+1: I'll update and give it a go on my next print, then report back.

Alright...did a few prints with version 1.0.1. All is working as expected!
Thanks a lot everyone!

Question in regard to the gcode phases. So far it seems that queuing may be preferred to sending based on @OllisGit findings, but if you don't have to discard or modify the commands is the sent phase the best place to not interrupt the serial buffer/queue as that is a callback rather than being in the middle of the communication?

@jneilliii It really depends on what is required. In the case of this plugin the order of execution does and should matter which is why I fixed it. If you need to intercept or check the command prior to anything else manipulating it then queuing would be better than sent which would be after all other hooks/manipulations occur.

The trick is to figure out a way to bail out of the hook as early as possible whilst accomplishing the task. That could mean dumping the required data to a buffer and processing it in anther thread.

1 Like

Thanks @kantlivelong, so basically enqueue the line sent/received/queued, etc. and use a separate thread to monitor the queue and process similar to how Gina did in the TerminalStats plugin on the live streams? I think I should probably do that with BedLevelVisualizer. now.

I didn't think the received phase would have effected the serial communication since it was coming back to octoprint and thought it might already be in a separate thread, but now that I go back and look at the docs, it clearly states it.

@jneilliii I'm not aware of all use cases for BLV but in my case I only view the results when not printing. The recent PR I submitted will bail out early in the process for the processGCODE hook if the processing flag is set. flagMeshCollection could certainly be changed to queuing. If you wanted to shave down cputime you could do

def flagMeshCollection(self, comm_instance, phase, cmd, cmd_type, gcode, *args, **kwargs):
	if cmd[:1] != "@":
		return

	if cmd != "@BEDLEVELVISUALIZER":
		return

	self.mesh = []
	self.box = []
	if not self.mesh_collection_canceled and not self.processing:
		self.processing = True
	if self.mesh_collection_canceled:
		self.mesh_collection_canceled = False
		return
	self._bedlevelvisualizer_logger.debug("mesh collection started")
	self.processing = True

Might just be splitting hairs though.

Cool! :+1:

Yeah, I merged your changes because I see where it would benefit when flagMeshCollection was enabled in processGCODE but didn't think about the received phase impacting the serial comm. I don't think it's ever been an issue before.

I was previously flagging mesh collection on queuing, but thought it should be as close to the printer receiving the command as possible to avoid stopping collection on a received ok due to an overlap of communication.