利用者:Z0r/PyDevAndProfiling

提供: wiki
< 利用者:Z0r
2012年11月11日 (日) 14:47時点におけるwiki>Ideasman42による版 (moved User:Z0r to User:Z0r/PyDevAndProfiling)
(差分) ← 古い版 | 最新版 (差分) | 新しい版 → (差分)
移動先: 案内検索

Using PyDev for Blender Script Development

PyDev is an extension for Eclipse that adds support for editing Python code. It's a good way to develop scripts for Blender and the Blender Game Engine: it has syntax highlighting, code completion (to some extent), and an interactive debugger.

After installing a minimal version of Eclipse (the standard "Eclipse IDE for Java Developers" will do), you will need to install PyDev.

Configuring PyDev for Game Development

First, set up your directory structure. It should look something like this:

 MyGame/
   Game/
     *.blend
     src/
       __init__.py
       *.py
     textures/
     audio/
     etc/

The nesting of the MyGame, Game and src directories are important, but you can name them whatever you like. When you start Eclipse, it will ask you which workspace to use; choose the MyGame directory. The Game directory will be known to Eclipse as your project.

Before importing your project, make sure you have a Python 3 interpreter configured in PyDev. In choose Window > Preferences > Pydev > Interpreter. If you don't see "Python 3" or similar in the top panel, click on New to add it. Then, because the BGE API is unknown to PyDev, turn off some error markers: still in the Preferences dialogue, choose Pydev > Editor > Code Analysis. In the Undefined tab, set Undefined variable from import to Warning. In the Imports tab, set Import not found to Ignore.

Now you can import your project.

  1. Switch to the PyDev perspective: choose Window > Open Perspective > Other > Pydev.
  2. Right-click in the Pydev Package Explorer view, and choose New > Project > Pydev > Project.
  3. Click Next. In the Project name field, enter Game (or whatever you have called your project directory). If it doesn't exist yet, it will be created; but it shouldn't be overwritten (but make a backup first). Set the Grammar Version to 3.0, and the Interpreter to the one configured above (Python 3). Un-tick Create adefault 'src' folder; it will be added later.
  4. Right-click on your new project directory in the Pydev Package Explorer, and choose Properties > PyDev - PYTHONPATH > Source Folders. Click Add source folder, and choose the Game directory itself - this sets up the modules to mimic how they are imported within Blender.

That's it! Now any .py files that you have in the src directory will be available as modules in the game engine. For example, a Python controller set to run src.foo.bar would run the bar() function in src/foo.py.

Debugging

PyDev comes with an interactive debugger. This section explains how to use it in Blender; for detailed usage see the official PyDev documentation.

First, Switch to the Debug perspective in Eclipse: choose Window > Open Perspective > Other > Debug. Then create an External Tool to start Blender: choose Run > External Tools > External Tools Configurations. Right-click on Program on the left, and choose New. Configure the tool as follows:

  • Main > Name: Blender PyDebug
  • Main > Location: /usr/bin/blender (or wherever your Blender executable is).
  • Environment> Vaiable > PYTHONPATH: /path/to/.eclipse/org.eclipse.platform_VERSION/plugins/org.python.pydev.debug_VERSION/pysrc, i.e. create a new environment variable to set the PYTHONPATH. For this variable, you will need to find the directory that contains pydevd.py, which is distributed with PyDev. This allows Blender to import the pydevd module.

Now add this code to the start of one of your files, e.g. src/__init__.py:

try:
	import pydevd
	pydevd.settrace(stdoutToServer=True, stderrToServer=True, suspend=False)
except ImportError:
	pass

That code will happily run without the debugger if you don't start Blender using the external tool created above.

Now you're all set. To debug your code:

  1. Set breakpoints by double-clicking in the grey side-bar on the left of the text editor view.
  2. Choose Pydev > Start Debug Server.
  3. Choose Run > External Tools > Blender PyDebug (you may need to run it from the Configure External Tools dialogue if it's not in the menu).
  4. Start your game normally. Execution should stop whenever the interpreter reaches one of your breakpoints.

Profiling Blender Games

Instrumented

One of the most basic ways to measure the speed of your program is to surround interesting blocks of it with timing collection code. The following code lets you time the execution of some functions.

import time
prof = {}

class profile:
	'''Function decorator for code profiling.'''

	def __init__(self, name):
		self.name = name

	def __call__(self, fun):
		def profile_fun(*args, **kwargs):
			start = time.clock()
			try:
				return fun(*args, **kwargs)
			finally:
				duration = time.clock() - start
				if not fun in prof:
					prof[fun] = [self.name, duration, 1]
				else:
					prof[fun][1] += duration
					prof[fun][2] += 1
		return profile_fun

def print_stats(c):
	'''Prints profiling results to the console. Run from a Python controller.'''

	if not c.sensors[0].positive:
		return

	def timekey(stat):
		return stat[1] / float(stat[2])
	stats = sorted(prof.values(), key=timekey, reverse=True)

	print('=== Execution Statistics ===')
	print('Times are in milliseconds.')
	print('{:<55} {:>6} {:>7} {:>6}'.format('FUNCTION', 'CALLS', 'SUM(ms)', 'AV(ms)'))
	for stat in stats:
		print('{:<55} {:>6} {:>7.0f} {:>6.2f}'.format(
				stat[0], stat[2],
				stat[1] * 1000,
				(stat[1] / float(stat[2])) * 1000))

Then you need to decorate the functions you are interested in with the profile decorator:

@profile('foo_func')
def foo_func(c):
	c.owner.worldPosition.z += 1

Finally, hook up the print_stats function to a Python controller so that it prints the statistics when a key is pressed (for example).

Statistical

Profiling a game can be tricky: your code may be called via several Python controller logic bricks, so there is no single entry point. Therefore you can't use the built-in profile module - and instrumenting each function manually can be a pain.

Another method that works very well is statistical (or stochastic) profiling. This method uses interrupts to stop the interpreter at regular intervals and record what piece of code is executing. To do this, you can use the 3rd-party statprof module.

First, download ファイル:Statprof.3k.txt and place it next to your .blend file. Remember to rename it to statprof.py. Then add the following code to one of your scripts (or create a new text block for it, e.g. "profiling.py").

import statprof
statprof.start()

def start_profiling(c):
	if c.sensors[0].positive:
		statprof.start()

def print_stats(c):
	if c.sensors[0].positive:
		statprof.stop()
		statprof.display()

Then all you need to do is bind those functions to a Python controller. start_profiling should probably be run on the first frame; print_stats should be bound to some later event such as a key-press. Because the profiler collects samples periodically, the longer you let your game run for, the more accurate the results will be. But in practical terms, print_stats can be run 20-30 seconds after start_profiling. Note that in its current form, print_stats will only return useful results for the first time it is run.