A very interresting entry is the update_view in torrentview.py. This function is called 23 times where the total time spent in the function is 27 seconds. Each call takes 1.18 seconds. For the short time the client was connected this is a lot of time!
### line_profiler
Lets examine this function using another tool; [line_profiler](http://packages.python.org/line_profiler/).
After installing line_profiler, we add `@`profile to the function update_view in torrentview.py like this:
```
@profile
def update_view(self, columns=None):
```
and run deluge with kern_prof:
```
kernprof.py -l -v ./deluge -l ~/deluge.log -L info
```
Then connecting to the daemon to load the torrent list and letting it run a few seconds and then close the client.
The output from line_profiler will be printed to the terminal:
Here we see the cummulative stats for this function, i.e. the stats for all the calls to this function combined.
On line 407 we that Hits is 16, which means this method was called 16 times in total. Executing this line 16 times took 206 microseconds.
Looker further down we see some more interesting numbers. Executing line 414 34592 times took a total of 5.3 seconds. Executing line 417 34592 times took 10.5 seconds.
The lines that have no stats, e.g. line 415, were never executed.
Lets do two simple changes:
* Call status.keys() before the for-loop and use the cached results inside the for-loop.
* Add an if-test before line 417 to test if the value is False before setting to True.
Now you can see that line 414 uses 1.5 seconds instead of the previous 5.3.
Also, line 418 (previously 417) uses 400ms instead of 10 seconds in the original code. Most importantly the line is now executed only 2162 times, and not 34592 times as it used to be. Including the the new if-test, the new code uses 560ms compared to 10 seconds in the old.
The reason this is faster can be seen when comparing the time it takes to execute each of the lines one time. The if-test takes 4.4 microseconds on average, while setting the row value to True takes 189 microseconds.
### cProfile and Run Snake Run revisited
Lets do a new profile with the changes to the code:
```
python -m cProfile -o deluge.profile deluge -l deluge.log -L info
We can now see how update_view has dropped significantly on the list. Each call to update_view now takes 0.37 seconds on average compared to 1.18 in the original code.
## Profiling Deluge daemon with
The daemon can be profiled using the command line option --profile.
```
deluged --profile
```
Deluge 1.3.X uses [hotshot](http://docs.python.org/2/library/hotshot.html). You can convert hotshot profiling data to [KCachegrind](http://kcachegrind.sourceforge.net/html/Home.html) calltree format using hotshot2calltree:
git-master uses cProfile so the output can be opened directly by [RunSnakeRun](http://www.vrplumber.com/programming/runsnakerun). To open this in KCachegrind (-k option opens the result in KCachegrind automatically):
```
pyprof2calltree -i deluged.profile -k
```
## Profiling memory usage on the Deluge daemon with valgrind (massif)
Be aware that this makes the daemon very slow!
```
valgrind --tool=massif deluged -l ~/deluged.log -L info -d
```
After exiting the daemon, a file named massif.out.<pid> (e.g. massif.out.26034) should've been writen to the working dir.
Lets open that with [massif-visualizer](https://projects.kde.org/projects/extragear/sdk/massif-visualizer)
Here we see a nice graph showing the memory usage at snapshots taken at regular intervals. It's clear that a lot of the memory used by the daemon is in fact used by libtorrent. It's possible to get a more detailed view of the memory usage of the different categories shown in the list on the right.