Mario.Tapilouw

Tuesday, December 22, 2015

Debugging Multi-Thread Application

Most of the application I develop are running more than one thread with different task for each thread. It might sound ok if the threads are running properly, all the critical sections are not dead locked, and memory are well controlled.

But, sometimes due to deadlines, we forget some parts of the codes and it leads to application crash, memory leak, and the most difficult part is data race problem. These are sorted based on difficulty in debugging.

These several months, I've been struggling hard to read others' code, interpret what they are trying to achieve with the code, how the threads work, how do they synchronize, and how to add another feature to the existing program. And here because it's almost the end of the year, I want to summarize what I learned so far this year.

  1. Application crash is the easiest to debug among all of the three problems I mentioned above. This can be traced quite easily by setting debug points on object creations, every function calls, and object destructions. Usually the error messages gives a clue on what to debug, it takes experience to know what the problem is from the error messages. The more mistakes you make, the more experience you have in interpreting error codes :), but this is not a justification for making mistakes.
  2. Memory leaks is more difficult when it comes to multi threaded applications because the problem might spread with the thread instantiation. The only way to debug this is by checking the source code line by line, making sure that there's always a delete or delete [] for every new or new[].
  3. The data race can be traced by checking all the critical sections and writing a log file for every threads. This is difficult to check because the more threads in the software the more complicated the debugging process is. It become more complicated when the thread is dealing with arrays. Some compilers are not very good in debugging multi threaded application, because the application itself might crash. So, what I did is writing the algorithm into dll, then write some debugging string then use another software to catch the debug strings. In this way, the main threads are not interrupted during debugging and it's much easier to debug the software. The software I am using is called DebugView (https://technet.microsoft.com/en-us/sysinternals/debugview.aspx). It's very convenient to use in debugging algorithm, especially when it is run in thread.

Labels: , , , , ,

Monday, May 09, 2011

Plane Fitting using OpenCV


As what I've promised, I'm going to write about plane fitting using OpenCV. It's quite straight away and quite similar to my previous post, the difference is only about the physical representation of the variables in the equations. This time it's only a plane fitting, so it's a linear least square fitting. Later I would like to explore non-linear fitting as well and share it here when I have made it.

Let's say that we have a set of data that represents a plane in 3D coordinate X-Y-Z and modeled as Axi + Byi + C = zi. where i is the enumerator of the data (0~n).

Using the same approach, we can use matrix to represent the simultaneous equation and solve it.I will directly show you how.
1. prepare the matrices for the data.
CvMat *res  = cvCreateMat(3, 1, CV_32FC1);
CvMat *matX = cvCreateMat(10000, 3, CV_32FC1);
CvMat *matZ = cvCreateMat(10000, 1, CV_32FC1);
2. input the data into the matrices.
for(int row=0;row<100;row++)
{
for(int col=0;col<100;col++)
{
int idx = row * col;
double val = cvmGet(filteredMat, row, col);

cvmSet(matX, idx, 0, col*pixScale);
cvmSet(matX, idx, 1, row*pixScale);
cvmSet(matX, idx, 2, 1);
cvmSet(matZ, idx, 0, val);
}
}
3. solve the equation
cvSolve(matX, matZ, res, CV_SVD);
A = cvmGet(res, 0, 0);
B = cvmGet(res, 1, 0);
C = cvmGet(res, 2, 0);

4. calculate the distance between the plane and the real data.


double sqrtc = sqrt(pow(A, 2) + pow(B, 2) + pow(C, 2));

float min = 100;
float max = -100;

// plane generation, Z = Ax + By + C
// distance calculation d = Ax + By - z + C / sqrt(A^2 + B^2 + C^2)
// pointlist generation
for(int row=0;row<filteredMat->rows;row++)
{
for(int col=0;col<filteredMat->cols;col++)
{
double Zval = cvmGet(filteredMat, row, col);
double val = col*pixScale*A + row*pixScale*B - Zval + C;
double distance = val / sqrtc;

if(min > distance)
min = distance;

if(max < distance)
max = distance;

cvmSet(planeMat, row, col, distance);
}
}
Here is an example of this plane fitting, this is the surface before fitting, this is measurement result of a flat surface using white light interferometry:
and after fitting the result is:
The color represents the height, so we can see that after fitting the color of the surface is almost the same only a small variation of the surface. The sample should be flat and smooth, however it's not smooth anymore due to wear. However, the real scale is nanometer, the variation that we see in the result is around 100 nm.

Labels: , , , ,

Wednesday, May 12, 2010

Linear Least Square Fitting using GSL

Sometimes for scientific calculation we need to do a least square fitting to a set of data. Depends on the usage, if you need to fit with a line then you need to perform a linear least square fitting, and if you need to fit with a polynomial with higher order, you need to perform non-linear least square fitting.

I have been trying to do this in C++ for a period of time, until I found that I can do it using Gnu Scientific Library. This really helps me a lot and make my job easier.

So, here's how it goes:
1. Make sure Gnu GSL library is configured with your compiler. Please Google it out to find out how.

2. Include the libraries into your program. You might need to visit this site to see how to configure it in Borland C++ Builder 6.

3. Include the header file for fitting into your source code:
#include < gsl/gsl_fit.h >

4. Basically, the function for linear least square fitting is (quoted from this website):
int gsl_fit_linear (const double * x, const size_t xstride, const double * y, const size_t ystride, size_t n, double * c0, double * c1, double * cov00, double * cov01, double * cov11, double * sumsq)

This function computes the best-fit linear regression coefficients (c0,c1) of the model Y = c_0 + c_1 X for the dataset (x, y), two vectors of length n with strides xstride and ystride. The errors on y are assumed unknown so the variance-covariance matrix for the parameters (c0, c1) is estimated from the scatter of the points around the best-fit line and returned via the parameters (cov00, cov01, cov11). The sum of squares of the residuals from the best-fit line is returned in sumsq. Note: the correlation coefficient of the data can be computed using gsl_stats_correlation (see Correlation), it does not depend on the fit.

5. So, we have to use that function. Before that, we should make our data for testing the algorithm. A simple array with random values will be enough, something like this:

spreadData[i] = (double)(rand() % 20 + 1) + (0.5 * i);


6. Then, finally call the line fitting function with the respective input and output arguments:

gsl_fit_linear (dataAxis, 1, spreadData, 1, 100, &c0, &c1, &cov00, &cov01, &cov11, &chisq);

Finally, you can plot the fitted value together with the data. The output that I got is something like this, for this example I plot the residue values together with the data and the line.


Hope it will be useful for you too. Good luck.

Labels: , ,

Wednesday, April 28, 2010

implib

If you're working with Borland C++ Builder compiler and you want to use functions from a DLL file, usually you have to make a library file first. Otherwise your compiler will produce an error message showing that there's an error in linking with the library. Something like this:

[Linker Error] Unresolved external 'name_of_the_function_from_the_library' referenced from E:\TEST\MAINFORM.OBJ

Then in order to resolve this problem, you need to build a library that is suitable with your compiler. Most of the library files shipped with the product are made for Microsoft's compiler, so you need to make some modification to the library file.

These are some possible steps that you need to do before using the library/dll file:
1. If you have the library file for Microsoft Visual C++, then you have to convert it into Borland C++ Builder library by using 'coff2omf' command line program.

example: coff2omf cv.lib cv2.lib

2. If you have the dll file together with the header file and you have to generate the library file by yourself, you have to use 'implib' command line program.

example: implib -a fftw3-3.lib libfftw3-3.dll

These programs are provided by Borland C++ Builder, you can find them in the installation directory. For example, mine is in "C:\Program Files\Borland\CBuilder6\Bin" and it depends on where you installed your compiler, they will be available in the Bin\ directory. My compiler is a rather old compiler because I'm having difficulties in upgrading to newer version. Some of my hardwre doesn't support the new C++ Builder version. So I stick with this version.

Hope this tip will be useful for you. It works with me, so if it doesn't apply to your situation, just let me know. I might be able to explain what's wrong.

Good luck!

Labels: , ,

Sunday, May 24, 2009

State Machine

Managing multiple-threaded application is quite tricky.. I spent a lot of time trying to do this and I ended up with an idea of a solution which is based on my previous experience designing hardware on an FPGA, using a state machine which is running on another thread and publishing the state to all the application.

The state machine controls all the thread activity inside the application and all the running thread must send a message to the state machine to change the state. Therefore the state machine acts as the manager of all the threads and by doing so we can control the activity of the threads.

I don't know the correct way of doing such thing, does anybody knows? however, this solution works for me..

Labels: , , ,

Thursday, February 26, 2009

writing a well-written code is faster than debugging a badly written code...

Debugging is a pain in the ass..
It can make you sleepless in the evening, lose your mood in the morning, decrease your appetite, and even a nightmare, hahaha...

Lesson learned: It's better to write a well-written code than you have to spend time in debugging your code in the end.. Sometimes, after you wrote the code, you don't even remember why you wrote it that way. This is what makes debugging a difficult job.

This is the most efficient way to develop a software, trust me hehe..

Labels: , , ,