<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Michal Sylwester</title>
	<atom:link href="http://arakilab.media.eng.hokudai.ac.jp/~msylw/feed/" rel="self" type="application/rss+xml" />
	<link>http://arakilab.media.eng.hokudai.ac.jp/~msylw</link>
	<description></description>
	<lastBuildDate>Wed, 26 Feb 2014 02:34:18 +0000</lastBuildDate>
	<language>en-US</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.8.1</generator>
	<item>
		<title>PPA: Create package with minor version upgrade</title>
		<link>http://arakilab.media.eng.hokudai.ac.jp/~msylw/2014/02/ppa-create-package-with-minor-version-upgrade/</link>
		<comments>http://arakilab.media.eng.hokudai.ac.jp/~msylw/2014/02/ppa-create-package-with-minor-version-upgrade/#comments</comments>
		<pubDate>Wed, 26 Feb 2014 02:30:39 +0000</pubDate>
		<dc:creator><![CDATA[Michal Sylwester]]></dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://arakilab.media.eng.hokudai.ac.jp/~msylw/?p=76</guid>
		<description><![CDATA[I used this before to remember all the necessary commands, without reading the whole guide again and again. As I don&#8217;t upload many packages, it&#8217;s easy to forget the details&#8230; This skips many one-time steps (like setting up launchpad access), &#8230; <a href="http://arakilab.media.eng.hokudai.ac.jp/~msylw/2014/02/ppa-create-package-with-minor-version-upgrade/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>I used this before to remember all the necessary commands, without reading the whole guide again and again. As I don&#8217;t upload many packages, it&#8217;s easy to forget the details&#8230;</p>
<p>This skips many one-time steps (like setting up launchpad access), error scenarios or even changed dependencies, but helps in trivial cases. For those more complex scenarios, check official docs.</p>
<ol>
<li>Go to some empty work directory<br />
<pre class="crayon-plain-tag">cd &lt;some dir&gt;</pre>
</li>
<li>Fetch previous version from repository. You will get some files and a directory &#8220;packagename-vesion&#8221;, called later &lt;old-version-dir&gt;<br />
<pre class="crayon-plain-tag">sudo apt-get source &lt;package-name&gt;</pre>
</li>
<li>Same place, download the new tarball.<br />
<pre class="crayon-plain-tag">wget &lt;url to new source&gt;</pre>
</li>
<li>Enter the old package directory<br />
<pre class="crayon-plain-tag">cd &lt;old-version-dir&gt;</pre>
</li>
<li>Use uupdate to prepare new version&#8217;s directory. You may need to specify the new version explicitly<br />
<pre class="crayon-plain-tag">uupdate -v &lt;new-version (just the upstream number)&gt; ../&lt;upstream-tarball&gt;</pre>
</li>
<li>Go there<br />
<pre class="crayon-plain-tag">cd ../&lt;new-version-dir&gt;</pre>
</li>
<li>Update the changelog. The version should be something like &lt;package-name&gt;-&lt;upstream-version&gt;-0ubuntu0ppa0 (increase last 0 for minor ppa upgrades). Remember to set target distro correctly<br />
<pre class="crayon-plain-tag">dch -i</pre>
</li>
<li>Check it builds fine<br />
<pre class="crayon-plain-tag">debuild</pre>
</li>
<li>Build source package<br />
<pre class="crayon-plain-tag">debuild -S</pre>
</li>
<li>Upload it to launchpad<br />
<pre class="crayon-plain-tag">dput ppa:&lt;username&gt;/&lt;ppaname&gt; &lt;long-new-version&gt;.changes</pre>
</li>
<li>You should get an email that the package was accepted. After a while check the build status to make sure there were no problems.</li>
</ol>
<p>Good luck!</p>
]]></content:encoded>
			<wfw:commentRss>http://arakilab.media.eng.hokudai.ac.jp/~msylw/2014/02/ppa-create-package-with-minor-version-upgrade/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using udev to trigger events in example</title>
		<link>http://arakilab.media.eng.hokudai.ac.jp/~msylw/2013/07/using-udev-to-trigger-events-in-example/</link>
		<comments>http://arakilab.media.eng.hokudai.ac.jp/~msylw/2013/07/using-udev-to-trigger-events-in-example/#comments</comments>
		<pubDate>Mon, 08 Jul 2013 04:09:58 +0000</pubDate>
		<dc:creator><![CDATA[Michal Sylwester]]></dc:creator>
				<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://arakilab.media.eng.hokudai.ac.jp/~msylw/?p=42</guid>
		<description><![CDATA[Find device (this works only with input devices): [crayon-6a10af6cc5e3b367858899/] Use the name to find system path of the device: [crayon-6a10af6cc5e47681812206/] Make a test run: [crayon-6a10af6cc5e4d373870540/] Look data that is specific to device you want to customize. ID_TYPE=hid is too general, &#8230; <a href="http://arakilab.media.eng.hokudai.ac.jp/~msylw/2013/07/using-udev-to-trigger-events-in-example/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Find device (this works only with input devices):</p><pre class="crayon-plain-tag">$ sudo lsinput

/dev/input/event5
 bustype : BUS_USB
 vendor : 0x46e
 product : 0x52cb
 version : 272
 name : &quot;BTC USB Multimedia Keyboard&quot;
 phys : &quot;usb-0000:00:06.1-4.3/input1&quot;
 uniq : &quot;&quot;
 bits ev : EV_SYN EV_KEY EV_MSC

/dev/input/event6
 bustype : BUS_USB
 vendor : 0x458
 product : 0x5e
 version : 272
 name : &quot;KYE ADNS6000 Optical Mouse&quot;
 phys : &quot;usb-0000:00:06.1-4.4/input0&quot;
 uniq : &quot;&quot;
 bits ev : EV_SYN EV_KEY EV_REL EV_MSC</pre><p>Use the name to find system path of the device:</p><pre class="crayon-plain-tag">$ udevadm info -q path -n /dev/input/event5
/devices/pci0000:00/0000:00:06.1/usb2/2-4/2-4.3/2-4.3:1.1/input/input5/event5</pre><p>Make a test run:</p><pre class="crayon-plain-tag">$ udevadm test /devices/pci0000:00/0000:00:06.1/usb2/2-4/2-4.3/2-4.3:1.1/input/input5/event5
(...)
udev_device_update_db: unable to create temporary db file '/run/udev/data/c13:69.tmp': Permission denied
ACTION=add
DEVLINKS=/dev/input/by-id/usb-BTC_USB_Multimedia_Keyboard-event-if01 /dev/input/by-path/pci-0000:00:06.1-usb-0:4.3:1.1-event
DEVNAME=/dev/input/event5
DEVPATH=/devices/pci0000:00/0000:00:06.1/usb2/2-4/2-4.3/2-4.3:1.1/input/input5/event5
ID_BUS=usb
ID_INPUT=1
ID_INPUT_KEY=1
ID_MODEL=USB_Multimedia_Keyboard
ID_MODEL_ENC=USB\x20Multimedia\x20Keyboard
ID_MODEL_ID=52cb
ID_PATH=pci-0000:00:06.1-usb-0:4.3:1.1
ID_PATH_TAG=pci-0000_00_06_1-usb-0_4_3_1_1
ID_REVISION=0110
ID_SERIAL=BTC_USB_Multimedia_Keyboard
ID_TYPE=hid
ID_USB_DRIVER=usbhid
ID_USB_INTERFACES=:030101:030000:
ID_USB_INTERFACE_NUM=01
ID_VENDOR=BTC
ID_VENDOR_ENC=BTC
ID_VENDOR_ID=046e
MAJOR=13
MINOR=69
SUBSYSTEM=input
UDEV_LOG=6
USEC_INITIALIZED=4552168
XKBLAYOUT=us
XKBMODEL=pc105
XKBOPTIONS=
XKBVARIANT=</pre><p>Look data that is specific to device you want to customize. ID_TYPE=hid is too general, but perhaps ID_VENDOR_ID or ID_MODEL_ID. Sometime there is some tip about device type like ID_INPUT_TOUCHPAD=1. If the data seems too general, it may be better to attach to parent device, run the command again without the last &#8220;event&#8221; part:</p><pre class="crayon-plain-tag">$ udevadm test /devices/pci0000:00/0000:00:06.1/usb2/2-4/2-4.3/2-4.3:1.1/input/input5</pre><p>Still, try to find something as close to the end of the chain as possible. Another way worth of trying is to run udevadm info:</p><pre class="crayon-plain-tag">$ udevadm info -a -p
/devices/pci0000:00/0000:00:06.1/usb2/2-4/2-4.3/2-4.3:1.1/input/input5/event5</pre><p>Finding the right filter rules seems to be always most difficult for me&#8230; Create a new file in /etc/udev/rules.d starting with 2-digit number (this is rule&#8217;s priority, I suggest a large one to keep the rule close to the end of the chain). My rules for detecting a Apple Bluetooth keyboard and  a touchpad are:</p><pre class="crayon-plain-tag">ACTION!=&quot;add|change&quot;, GOTO=&quot;apple_kbd_end&quot;
SUBSYSTEM!=&quot;input&quot;, GOTO=&quot;apple_kbd_end&quot;
KERNEL!=&quot;event[0-9]*&quot;, GOTO=&quot;apple_kbd_end&quot;

ATTRS{address}==&quot;60:fb:42:02:12:a9&quot;, RUN+=&quot;keymap $name apple&quot;
ENV{ID_INPUT_TOUCHPAD}==&quot;1&quot;, RUN+=&quot;/home/test/bin/send-command hostname slowgestures&quot;

&lt;span style=&quot;font-family: 'Courier 10 Pitch', Courier, monospace; font-size: 13px; font-style: normal; line-height: 1.5;&quot;&gt;LABEL=&quot;apple_kbd_end&quot;&lt;/span&gt;</pre><p>So I&#8217;m using Bluetooth address for keyboard and ID_INPUT_TOUCHPAD for the touchpad. When it is added to system, a script &#8220;send-command&#8221; will be run. After editing the file, save it and run the udevadm test again:</p><pre class="crayon-plain-tag">$ udevadm test /devices/pci0000:00/0000:00:06.1/usb2/2-4/2-4.3/2-4.3:1.1/input/input5/event5

USEC_INITIALIZED=150940194993
run: '/home/test/bin/send-command hostname slowgestures'</pre><p>Check the run command is there. If not, change the rules and try again. If it worked, run one last command to inform the udev daemon about the changes:</p><pre class="crayon-plain-tag">sudo udevadm control --reload-rules</pre><p>That&#8217;s it. Now it&#8217;s up to you to write the event handlers.</p>
]]></content:encoded>
			<wfw:commentRss>http://arakilab.media.eng.hokudai.ac.jp/~msylw/2013/07/using-udev-to-trigger-events-in-example/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python multiprocessing HOWTO</title>
		<link>http://arakilab.media.eng.hokudai.ac.jp/~msylw/2013/07/python-multiprocessing-howto/</link>
		<comments>http://arakilab.media.eng.hokudai.ac.jp/~msylw/2013/07/python-multiprocessing-howto/#comments</comments>
		<pubDate>Wed, 03 Jul 2013 07:09:11 +0000</pubDate>
		<dc:creator><![CDATA[Michal Sylwester]]></dc:creator>
				<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://arakilab.media.eng.hokudai.ac.jp/~msylw/?p=46</guid>
		<description><![CDATA[Using python multiprocessing module is quite simple, even though it has some pitfalls. But remembering how to avoid them it can help to really speed up some tasks. In the examples I will use a simple program calculating Fibonacci numbers &#8230; <a href="http://arakilab.media.eng.hokudai.ac.jp/~msylw/2013/07/python-multiprocessing-howto/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Using python multiprocessing module is quite simple, even though it has some pitfalls. But remembering how to avoid them it can help to really speed up some tasks.</p>
<p>In the examples I will use a simple program calculating <a title="Fibonacci number" href="http://en.wikipedia.org/wiki/Fibonacci_number">Fibonacci numbers</a></p><pre class="crayon-plain-tag">#!/usr/bin/python

import time

def fib(n):
    if n &lt; 0:
        raise ValueError
    if n &lt; 2:
        return n
    return fib(n-1)+fib(n-2)

def fibonacci(n):
    start = time.time()
    res = fib(n)
    end = time.time()
    return res

def main():
    start = time.time()
    for i in range(30, 37):
        res = fibonacci(i)
        print "fib(%3d) = %7d (took %0.3fs)" % ( n, res, (end-start))
    end = time.time() 
    print "Total time: %0.3fs" % (end - start) 

if __name__ == "__main__": main()</pre><p>main is the main function controlling the program. fib is doing the actual work. fibonacci is a wrapper we will change later to use multiprocessing withouth changing fib. Adjust the numbers in range(30, 37) to match speed of your computer, so the program takes about 10-20 seconds to run. Output should be like this:</p><pre class="crayon-plain-tag">fib( 30) = 832040 (took 0.406s)
fib( 31) = 1346269 (took 0.663s)
fib( 32) = 2178309 (took 1.069s)
fib( 33) = 3524578 (took 1.728s)
fib( 34) = 5702887 (took 2.798s)
fib( 35) = 9227465 (took 4.565s)
fib( 36) = 14930352 (took 7.373s)
Total time: 18.603s</pre><p>We need a way to make it possible to run the program starting fibonacci only once. I will use Queue to prepare the data for it. Add:</p><pre class="crayon-plain-tag">import multiprocessing</pre><p>and change the main and fibonacci functions to look like this:</p><pre class="crayon-plain-tag">def fibonacci(in_queue):
    while True:
        n = in_queue.get()
        if n == None: 
            break

        start = time.time()
        res = fib(n)
        end = time.time()
    return res

def main():
    start = time.time()
    in_queue = multiprocessing.Queue()

    for i in range(30, 37):
        in_queue.put(i)
    in_queue.put(None)

    res = fibonacci(in_queue)
    print "fib(%3d) = %7d     (took %0.3fs)" % ( n, res, (end-start))

    end = time.time()
    print "Total time: %0.3fs" % (end - start)</pre><p>What changed? The fibonacci is now a loop, taking values from queue and processing them one after another. This ends when it receives Null as value (&#8220;poison pill&#8221; &#8211; line 4-5). The data is inserted into the queue in the main function together with the poison pill (lines 16-18). </p>
<p>But wait! Now there is no way to send a reply from fibonacci! So let&#8217;s create another queue to receive the results. main and fibonacci change again:</p><pre class="crayon-plain-tag">def fibonacci(in_queue, out_queue):
    while True:
        n = in_queue.get()
        if n == None: 
            break

        start = time.time()
        res = fib(n)
        end = time.time()
        out_queue.put((n, res, end-start))

def main():
    start = time.time()
    in_queue = multiprocessing.Queue()
    out_queue = multiprocessing.Queue()

    for i in range(30, 37):
        in_queue.put(i)
    in_queue.put(None)

    fibonacci(in_queue, out_queue)

    while not out_queue.empty():
        n, res, spend_time = out_queue.get()
        print "fib(%3d) = %7d     (took %0.3fs)" % ( n, res, spend_time)
    end = time.time()
    print "Total time: %0.3fs" % (end - start)</pre><p>What&#8217;s going on: main puts requests into the first queue (17-19), calls fibonacci (21), and prints results taken from second queue (23-25). fibonacci gets data from first queue (3) until it encounters Null (4-5), and puts results into second queue (10). Now, as the fibonacci is separated from main using the queues we can put it into separate process.<br />
Change the line that calls fibonacci to:</p><pre class="crayon-plain-tag">multiprocessing.Process(target=fibonacci, 
                        args=(in_queue, out_queue)).start()</pre><p>Now the fibonacci starts after the first queue is full, but the program won&#8217;t wait for it to finish, it immediately goes to displaying the results. But it doesn&#8217;t work. Why?</p>
<p>Well, fibonacci wasn&#8217;t fast enough to compute any result, so the while loop (in line 23) started when results queue was still empty and quit too early. We can use second poison pill sent from fibonacci to solve this.</p>
<p>Another thing to keep in mind is that the main program waits for the worker to end. Luckily fibonacci ends (thank to the poison pill), but nobody is waiting any more for the results, so they don&#8217;t show up. This will be also solved with the poison pill. At the end of fibonacci add:</p><pre class="crayon-plain-tag">out_queue.put((None, None, None))</pre><p>and change the loop in main to:</p><pre class="crayon-plain-tag">while True:
        n, res, spend_time = out_queue.get()
        if n == None:
            break
        print &quot;fib(%3d) = %7d     (took %0.3fs)&quot; % ( n, res, spend_time)</pre><p>It works again! Now that is needed to have several processes work in parallel is to start them. Remember to add the necessary poison pills! Complete final version looks like this:</p><pre class="crayon-plain-tag">#!/usr/bin/python

import time
import multiprocessing

def fib(n):
    if n &lt; 0:
        raise ValueError
    if n &lt; 2:
        return n
    return fib(n-1)+fib(n-2)

def fibonacci(in_queue, out_queue):
    while True:
        n = in_queue.get()
        if n == None: 
            break
        start = time.time()
        res = fib(n)
        end = time.time()
        out_queue.put((n, res, end-start))
    out_queue.put((None, None, None))

def main():
    start = time.time()
    in_queue = multiprocessing.Queue()
    out_queue = multiprocessing.Queue()

    process_num = multiprocessing.cpu_count()
    for _ in range(process_num):
        multiprocessing.Process(target=fibonacci, 
                                args=(in_queue, out_queue)).start()

    for i in range(30, 37):
        in_queue.put(i)
    for _ in range(process_num):
        in_queue.put(None)

    while True:
        n, res, spend_time = out_queue.get()
        if n == None: 
            process_num -= 1
            if process_num == 0: break
        else:
            print "fib(%3d) = %7d   (took %0.3fs)" % ( n, res, spend_time)

    end = time.time()
    print "Total time: %0.3fs" % (end - start)

if __name__ == "__main__":
    main()</pre><p>Line 22 adds the poison pill to notify main that a fibonacci process has ended. Lines 30-32 start as many processes as we have cpus (determined in line 29). Lines 36-37 add poison pills for all fibonacci processes. Lines 41-43 keep track of how many processes are still running.</p>
<p>Remember, this is not the only solution. For example the results loop could simply count how many results it received. The optimal processes number depends on problem. If it&#8217;s just calculating data (like here) then CPU count is good bet. If there is substantial time spend on waiting for network operations, then more may be better. But if the slowdown is caused by some slow resource (like slow disk), then more processes can actually slow down performance. Usually it&#8217;s easiest to just try it out.</p>
<p>One more tip: when using multiple processes it is important to remember that one of them could raise exception when it encounters a problem. Always wrap all risky parts in except, and handle the exceptions. Also think of ways of terminating the program early when necessary. Remember: the program ends only, when all processes end.</p>
]]></content:encoded>
			<wfw:commentRss>http://arakilab.media.eng.hokudai.ac.jp/~msylw/2013/07/python-multiprocessing-howto/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Using SSH without password</title>
		<link>http://arakilab.media.eng.hokudai.ac.jp/~msylw/2013/06/using-ssh-without-password/</link>
		<comments>http://arakilab.media.eng.hokudai.ac.jp/~msylw/2013/06/using-ssh-without-password/#comments</comments>
		<pubDate>Sat, 22 Jun 2013 08:49:09 +0000</pubDate>
		<dc:creator><![CDATA[Michal Sylwester]]></dc:creator>
				<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://arakilab.media.eng.hokudai.ac.jp/~msylw/wp/?p=17</guid>
		<description><![CDATA[Using SSH often to login to remote systems? Sick of entering your password every few minutes? Consider logging using public key authentication. What is this? This authentication method uses 2 keys: private and public. Let&#8217;s use example: S is some &#8230; <a href="http://arakilab.media.eng.hokudai.ac.jp/~msylw/2013/06/using-ssh-without-password/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Using SSH often to login to remote systems? Sick of entering your password every few minutes? Consider logging using public key authentication.</p>
<h1>What is this?</h1>
<p>This authentication method uses 2 keys: private and public. Let&#8217;s use example:</p>
<ul>
<li>S is some remote server</li>
<li>C is your laptop</li>
</ul>
<p>The public key is put on server. It can be shared with anyone, it is of no use to anyone except the owner of the private key.</p>
<p>The private key is kept in safe place on laptop. During authentication server S verifies whether the secret key from C matches the public key on S. If so, user is allowed to log in. It is important to remember, keeping the private key secret is just as important as guarding your password.</p>
<h1>Preparation</h1>
<p>Simpler than it used to be&#8230; To generate the new key pair:</p><pre class="crayon-plain-tag">ssh-keygen</pre><p>and follow defaults. There will be a warning if the key already exists. For simplicity don&#8217;t specify a password (I will write how to use a password protected key without having to type too much another time).</p>
<p>Now, to copy the public key to remote sever run:</p><pre class="crayon-plain-tag">ssh-copy-id server</pre><p>Enter the password once more, and try:</p><pre class="crayon-plain-tag">ssh server</pre><p>Congratulations! And remember to protect the key!</p>
]]></content:encoded>
			<wfw:commentRss>http://arakilab.media.eng.hokudai.ac.jp/~msylw/2013/06/using-ssh-without-password/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Python profiling</title>
		<link>http://arakilab.media.eng.hokudai.ac.jp/~msylw/2013/06/python-profiling/</link>
		<comments>http://arakilab.media.eng.hokudai.ac.jp/~msylw/2013/06/python-profiling/#comments</comments>
		<pubDate>Sat, 22 Jun 2013 08:34:06 +0000</pubDate>
		<dc:creator><![CDATA[Michal Sylwester]]></dc:creator>
				<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://arakilab.media.eng.hokudai.ac.jp/~msylw/wp/?p=14</guid>
		<description><![CDATA[Introduction Is your python script running slow? Fear no more! Just follow these few steps, and you should be able to pinpoint the culprit. There are many ways to do this, this is the setup I use for quick profiling. Prerequisites &#8230; <a href="http://arakilab.media.eng.hokudai.ac.jp/~msylw/2013/06/python-profiling/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<h1>Introduction</h1>
<p>Is your python script running slow? Fear no more! Just follow these few steps, and you should be able to pinpoint the culprit.</p>
<p>There are many ways to do this, this is the setup I use for quick profiling.</p>
<h1>Prerequisites</h1>
<ul>
<li>pyprof2calltree: pip install pyprof2calltree</li>
<li>kcachegrind:
<ul>
<li>Debian/Ubuntu: apt-get install kcachegrind</li>
<li>Redhat/Centos: yum install kcachegrind</li>
</ul>
</li>
</ul>
<h1>Collecting profiling data</h1>
<p>The test run of the script should be with not too small, not too large amount of data. In my test runs I usually aim for about 10-20 seconds: it&#8217;s usually enough to get useful data without waiting too much. Make sure this is appropriate for you. It&#8217;s easiest if the script is runnable without any user interaction, then just:</p><pre class="crayon-plain-tag">python -m cProfile -o profile.dat test.py</pre><p>Where (change as appropriate):</p>
<ul>
<li>profile.dat will store the execution profile</li>
<li>test.py is the python script</li>
</ul>
<h1>Visualizing results</h1>
<p></p><pre class="crayon-plain-tag">pyprof2calltree -i profile.dat -k</pre><p>Sometimes it does not work (I saw it on a centos system), then try to do it in 2 steps:</p><pre class="crayon-plain-tag">pyprof2calltree -i profile.dat
kcachegrind profile.dat.log</pre><p>It may be overwhelming at first, but there are enough views to finally figure out what is what. Just play a bit with it!</p>
<h1>Tips</h1>
<ol>
<li><span style="line-height: 15px;">When using libraries the graphs will quickly get too detailed (as they show the internal library details). There are options to limit this if it get&#8217;s too distracting</span></li>
<li>Too complex code may get confusing for kcachegrind. If so, try to profile a simpler script with just just as little of the bottleneck code as necessary.</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://arakilab.media.eng.hokudai.ac.jp/~msylw/2013/06/python-profiling/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
