Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

split header and data functions #244

Closed
wants to merge 5 commits into from
Closed

split header and data functions #244

wants to merge 5 commits into from

Conversation

totaam
Copy link
Contributor

@totaam totaam commented Aug 6, 2016

Main benefits:

  • the functions can be re-used and tested more easily
  • it is possible to send the data without first concatenating the header and data together, which can make quite a bit of difference for performance - but note that this depends on a number of factors: size of the payload, memory pressure, network speed, naggle enabled or not, etc..
    The threshold is set arbitrarily at 4KB, you could turn it into a constant and if this is set high enough you would not see any difference with the current version of the code, except it will perform better with large packets.


self.send_parts.append(encbuf)
opcode = 2-int(self.base64) #based64: opcode=1, binary: opcode=2
encbufs = self.send_hybi(buf, opcode, base64=self.base64, record=self.rec)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You dropped the recording functionality. Also, the condition opcode calculation, while more concise, obfuscates the actual logic that is happening; the original is preferable to me.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, nevermind about the record functionality, I'm just blind I guess.

@kanaka
Copy link
Member

kanaka commented Aug 10, 2016

I'm okay with this change (apart from my inline comment). Have you tested with python 2.4 and python 3.X?

@kanaka
Copy link
Member

kanaka commented Aug 10, 2016

@totaam out of curiosity, how has the html5 interface in xpra been working out? I assume this was a performance enhancement discovered as part of using websockify in xpra?

@totaam
Copy link
Contributor Author

totaam commented Aug 11, 2016

Have you tested with python 2.4 and python 3.X?

Can't remember about 2.4, will re-check and get back to you.

apart from my inline comment

The opcode thing, sure. Back to a simple "if-else" instead?

how has the html5 interface in xpra been working out?

Great. In order to support some of the best features of xpra (sound forwarding, video encodings, etc), we've had to make a lot of drastic changes to the html5 code recently.
Many of those changes are due to land for the next release... overdue by 2 months already... Real soon now I am told.

The network performance issues we found turned out to be in the xpra html5 network code, but looking into websockify was useful anyway. I was going to quantify the benefits of this patch, but moved on to other things.

@kanaka
Copy link
Member

kanaka commented Aug 11, 2016

Yeah, simple if-else is preferable to me.

It's been a couple years since I've played with xpra, I'll have to try it again soon.

@totaam
Copy link
Contributor Author

totaam commented Aug 12, 2016

Done.
Also changed the header and data merge code back to using "+" as this works on all versions of Python.
Tested on CentOS5 (Python 2.4) and Fedora 24 (Python 2.7.12 and 3.5.1)


self.send_parts.append(encbuf)
opcode = 2
encbufs = self.send_hybi(buf, opcode, base64=self.base64, record=self.rec)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

send_hybi doesn't look like it returns anything. Also, doesn't this make the whiel self.send_parts below redundant?

@DirectXMan12
Copy link
Member

LGTM modulo the comment above. Will merge once that's addressed.

@samhed
Copy link
Member

samhed commented Aug 23, 2016

but note that this depends on a number of factors: size of the payload, memory pressure, network speed, naggle enabled or not, etc..

Nagle was disabled for websockify in f23780e how does this affect things here?

@totaam
Copy link
Contributor Author

totaam commented Aug 24, 2016

@DirectXMan12 right you are, the send_parts code wasn't used at all either.
The commit above gets rid of it. (removes 17 lines of unused code)

@samhed this shouldn't make much of a difference even with naggle disabled: the packet join size of 4K is high enough that you won't be sending just the packet header alone. Even then, it may or may not cost an extra TCP packet for payload sizes above 4K. (depending on the OS network stack, send queue levels, etc..)
If you're concerned about the network traffic vs cpu trade-off of this change, we can bump the threshold to 32KB or higher. (at which point the potential network cost increase becomes completely negligible, whereas the extra memory copy becomes an unnecessary burden on the CPU)

What some transports do is to disable naggle when sending multiple chunks and re-enable it immediately after. (I don't think it is worth the hassle - could be worth a try)

* no daemonizing support
* no SIGCHLD signal
* no multiprocessing support
* override copyfile so we can retry on WSAEWOULDBLOCK
if record:
record.write("%s,\n" % repr("{%s{" % tdelta + encbufs[1]))
if len(buf)<=4096:
self.request.send(header+buf)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't catch this earlier, but it looks live we've lost detection of partial sends here, which could be bad.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How so?
I don't see it in the quoted lines.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because socket.send isn't guaranteed to have sent all the requested data, and it returns however much it sends. Previously, the related methods here would return the result of self.request.send, and we would check to make sure the entirety of the buffer was sent. If not, we'd remember the rest, and send it later. This patch removes that functionality entirely (it can be seen here in the fact that we don't do anything with the result of self.request.send).

@CendioOssman
Copy link
Member

I'm a bit sceptical about this. Can you share some tests that show the performance issue/improvement?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants