views:

226

answers:

3

I would like to profile a custom management command that is relatively CPU intensive (renders an image using PIL). When I use the following command I get all sorts of Django modules (admin, ORM etc) in my profiling results:

python -m cProfile manage.py testrender

I have removed all imports that can potentially import Django but I am guessing the following is the culprit:

from django.core.management.base import BaseCommand, CommandError

Is there a way to filter out cProfile results? (only filenames are shown, no paths) Or, is there any other way to exclude/include respective modules/packages from profiling?

A: 

If I can't find any answers. Gprof2Dot as explained here can be an acceptable hack.

It doesn't filter out modules I'm not interested, but hopefully it will make it easier to inspect the results visually seperating my code and Django modules.

muhuk
A: 

Separate the PIL functionality into its own function/class in its own module, and import it from your management command. Then you can test/profile the PIL functionality independently of Django.

Carl Meyer
It is just like you said, in a seperate module and being imported from the command. The problem is how to profile independently. I don't even need super isolation, I just don't want 50 related entries and 950 unrelated ones. Would you like me to post some code?
muhuk
I don't understand where the problem is. If you have it separated out into its own module (which has no references to Django at all), can't you write a simple test harness to exercise that module, and profile that? I can't see how there would be any Django code in your profile output then.
Carl Meyer
Creating another executable you mean? That would be a solution. I am just trying to find out if it would be possible somehow, using a Django management command.
muhuk
+3  A: 

I solved this problem the following way:

from cProfile import Profile
from django.core.management.base import BaseCommand


class Command(BaseCommand):
    ...

    def _handle(self, *args, **options):
        # Actual code I want to profile
        pass

    def handle(self, *args, **options):
        if options['profile']:
            profiler = Profile()
            profiler.runcall(self._handle, *args, **options)
            profiler.print_stats()
        else:
            self._handle(*args, **options)

This way profiling statistics are gathered within the scope of _handle. So instead of:

python -m cProfile manage.py testrender

I'll have to run:

python manage.py testrender --profile

which is even better.

muhuk