Showing posts with label debugging. Show all posts
Showing posts with label debugging. Show all posts

Saturday, August 20, 2011

How to print stack trace anywhere in Javascript

It's well know how to print a stack trace after catching an exception/error in Javascript. But what if you are not catching anything? You see something happening at a particular line in code, but you want to know what's the code path through which the control flow reached that line when that interesting thing happened. In other words, you want to know what's the stack trace (series of function calls, starting from beginning of the program), at that particular line of code.

It's quite easy. If you don't have an exception, create one. Then you can print the stack trace off of it. Like this (gist) ...



Tuesday, August 16, 2011

How to debug WebWorker threads?

WebWorkers offer your Web app a way to do multithreading. If your advanced web app does some number crunching keeping the CPU busy for a while, then it makes sense to do it in a separate thread instead of doing it in the main thread, which may lead to blocking the browser tab (Chrome) or the entire browser (Firefox and others). One of the troubles of writing programs in WebWorkers is, they are hard to debug. Two key mechanisms required for debugging a program are not available in WebWorkers - print statements (console.log is not available) and breakpoints (even if you manage to place breakpoints in the code running in WebWorker, they won't be hit).

During my work on 3DTin, I have learnt couple of techniques that help me debug my WebWorker code.

1. Use postMessage as replacement for console.log
postMessage is how you send some data from the WebWorker thread to the main thread. This is the primary way of returning the result of the computation you perform in WebWorker. But we can use it for other purposes too. Here is how you can use the postMessage mechanism for communicating both the successful response as well as debug messages.


2. Catch exceptions and send their stack trace over postMessage
When an exception occurs in the code running in WebWorker, the debugger will print the line at which exception occurred, but not the entire stack trace. In most cases the whole stack trace can help you find the root cause quickly. To achieve that, place most of your code that runs in the WebWorker inside a try-catch statement. Then in the catch clause extract the stack trace of the exception, format it nicely and send it to the main thread using postMessage, as discussed in the first technique above. Here is the exception handling code that helps you extract stack trace at least on Google Chrome and other Webkit browsers. I have cherry-picked it from the stacktrace.js library. If you need a browser agnostic solution, paste the stacktrace.js library at the beginning of your WebWorker code.


I hope this makes your life easy while debugging WebWorker code.

Sunday, March 01, 2009

Static IP configuration on Fedora 10

Until last week Hathway (my ISP in Mumbai) was asking me to do DHCP discovery for IP address. After the n/w stopped working yesterday I called their service rep. One of them couldn't resolve it yesterday, so he forwarded me to another guy who turned out to be a funny experience - he gave me all the static IP config valus - and when the network still won't work he started blaming it on computer virus and ultimately rust on my network cable (!) Fortunately for me (and also for him) the modem was little sluggish in picking up the change and the network started working.

I had booted my new computer in Vista (yeah I know! argh!) and it worked fine. Surprisingly my Fedora 10 on Macbook and also the Fedora 10 on desktop won't respond to the static IP information. It took me 4 hours to figure out that there was nothing wrong in my knowledge of the network scripts. I got the clue when I found the system doing DHCP discovery even when I had set it to static IP. I figured it was because of the NetworkManager (seen as that taskbar network icon). When I googled, it became clear that configuring Fedora 10 with static IP is a known problem and the culprit is NetworkManager and/or system-config-network utility. This thread (#14) is pretty much helpful, but the working solution (or workaround) is not definite.

Here is what worked for me (at least for this box).

# Stop NetworkManager
sudo service NetworkManager stop

# Disable NetworkManager service
sudo chkconfig NetworkManager off

# Enable netwok service
sudo chkconfig network on

# Run system-config-network
# Edit the ethernet device under Device tab
# Under "Manual IP Address settings" put static IP Address.
# Leave Subnet mask and Default Gateway blank
# Change to Route tab
# Add route Dest 0.0.0.0 Netmask 0.0.0.0 Gateway
# Add route Dest Netmask Gateway
# Change to DNS tab to put addresses of DNS servers
# Check "Activate device when computer starts" same as ONBOOT=yes (I guess)
# Save the settings

sudo service network restart

At this point network should be working. If it doesn't don't get surprised. The same steps don't help me setup my Macbook Fedora 10 with static IP. Maybe I have screwed it beyond repair. I will wait for the router to arrive, to get my macbook online.



Ads:
* Linux Administration Handbook (2nd Edition) (Best tips on Linux administration I found in this book. Own it myself.)
* Fedora Bible 2010 Edition: Featuring Fedora Linux 12
* Linux Networking Cookbook

Saturday, December 20, 2008

Debugging python reference counts

If you are wondering about the progress of inkface, it's coming soon. I was planning to release version 0.1.2 couple weeks ago with a cool app demonstrating the improvements in the library (A twitter client), but after I saw the abysmal memory performance of the app on my n810, I decided to wait. Past two weeks I spent understanding the memory leaks in the library. In this post I would like to share my experiences while debugging reference count leaks in my python bindings.

The primary documentation on the subject from python.org is the first stepping stone. Considering how daunting the task of memory debugging is - some inspiration always helps. Read this post from Guido which explains how to approach the task.

In most of the cases we start debugging the memory leak after we have seen the program crawling or ever-increasing heap profile graph from valgrind massif. Whichever is the case, the theory of reference counts as explained in above docs, doesn't make sense in this scenario. In such case, the following steps may help you get started.
  • Put debug statements in the dealloc functions of your Python Type objects. This will tell you when are they getting called, if at all. They will be called when Py_DECREF call on your python object decrements its refcount to zero.
  • Identify the python objects that you suspect to be leaking (i.e. the objects whose ref counts are not reaching zero when you expect them to) and write a simple routine that dumps their refcounts. You can write this routine inside your C module or in python - depending upon how your code is organized. In C you can find PyObject's refcount by its member ob_refcnt. In python you can do the same by passing the object to sys.getrefcount() function. Call this refcount-dump routine from various places in your code and monitor how the reference count of these objects varies.
  • By calling the refcount-dump routine at strategic points you will soon narrow down to the area that is increasing the ref counts unexpectedly (or more correctly forgetting to decrease it when the job is done). Now look in the Python-C API docs for the behavior of the API calls you are making in this particular code segment. Understand the meanings of borrowed reference and new reference. Soon, you will find the places where you are supposed to call Py_DECREF, but you haven't.
While debugging my code I had following observations.
  • The ref counts on my objects were astronomical. After a while I figured that they were increasing with time. This observation clearly showed that the bug was in a loop structure. Soon I found the problematic code and put Py_DECREFs.
  • One common place of forgetting to release the ownership of an object is while iterating over a sequence using PyIter. Note that, PyIter_Next returns a new reference and you have to release it (roughly at the end of the iteration)
  • Sometimes Heisenberg's law kicks in ("you can't observe something without influencing it" as mentioned by Guido in above post). In my case, the python objects I was tracking were saved as values in a dictionary. So the only way to refer to them was
    sys.getrefcount(dict.values()[index])
    This leads to a creation of list of values, thus incrementing the reference count of the object I am monitoring. There is no easy way that I know of to work around this, but just taking into consideration these additional refcounts helps.
  • In my code, I have a pure python class which encapsulates the objects created by C library. So the deallocation of C objects was dependent on the deallocation of pure python object. So I had to track its refcounts as well. One surprising thing I noticed was this object had very high refcount immediately after its instantiation. e.g.
    o = someclass()
    print sys.getrefcount(o) # 11
    This was very unexpected. The reason behind it lied inside its constructor of course. This class has several methods. And inside the constructor I register these method objects as callback handlers. This understandably increases the refcount of method objects; however as it turns out it also increases the refcount of the parent object. So in my case, I got rid of these references by unregistering the callback handlers when I wanted to release the object.
After the whole exercise, I concluded that debugging memory leaks by means of debugging reference count leaks is a more useful way, compared to going through valgrind logs of a misbehaving C/C++ program.

These are my findings based on less than one day's work. If you find any mistakes in my understanding, please do point out.

And yes... an update on Inkface is coming soon.