I missed one detail in my previous answer:

Lance Hendrix wrote:
> ...
> My current thinking is that the explicit garbage collection (which is 
> synchronous with the user request) is what is causing the (at least 
> perceived) performance problem 

The explicit garbage collection happens after the response is sent, so 
the user visible delay shouldn't be impacted by this. The gc in itself 
is usually reasonably fast (typically less than 0.1s, but of course this 
varies with the system).


Now I wanted to verify that doing this gc.collect after each request 
really helped, so I did a few experiments with tracd (--http11), on 
Windows using ActivePython 2.5 and python.org Python 2.6:

0.11-stable unmodified (i.e. calling gc.collect after each request):
  Python 2.5 (svn 1.6.2)   26-27M
  Python 2.6 (no svn)      24-25M

0.11-stable modified (i.e. without calling gc.collect):
  Python 2.5 (svn 1.6.2)   34-37M
  Python 2.6 (no svn)      40-41M

(SQLite backend in both cases, Genshi advanced-i18n)

The numbers were obtained by repeatedly getting the Timeline page until 
the memory growth stabilized (it's never a fixed number, but stays 
within a range). Now that was under "normal" operations, one request 
after the other.

This shows that using gc.collect helps to keep the memory usage at a low 
level.


Then I stressed the server a bit, doing lots of quick refreshes in the 
browser, which leads to connection interrupted errors:
 ...
    self._sock.sendall(buffer)
error: (10053, 'Software caused connection abort')

This is expected, though it could be handled more gracefully. But what 
was less expected was that the memory usage grew a lot more. I was able 
to get up to 70M quite fast using tracd without explicit gc, but also to 
60M when using the explicit gc.collect (this needed more efforts, e.g. 
many tabs opened in different browsers, doing some "Reload All" before 
the requests were actually finished).

Even worse, after the first experiment of that sort, when I tried to 
resume to "normal" requests after letting the server recover from the 
many interrupted requests, I kept getting back the dreaded 
"TimeoutError: Unable to get database connection within 20 seconds" from 
an otherwise inactive tracd... It looks like the PooledConnection 
instances never got gc'ed, for some reason.
It's really hard to reproduce, though. It even took me quite some time 
to get a simple "database is locked" error. To be continued...

The "good" news is that while doing all this heavy load tests, it was 
really hard to go above 80M, so there seems to be a limit in the overall 
memory usage, which is a good thing. Even after I managed to push it to 
85M, it went back to 67M a couple minutes later.

On Windows, Python is quite good at giving memory back to the OS. It 
would be interesting to redo the same kind of experiments on Linux (I 
remember from the #6614 days that the gc.collect trick was especially 
useful on that platform).

-- Christian


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "Trac 
Development" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/trac-dev?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to