Thursday, October 29, 2009

SLOC

Recently I was browsing some open source project's(as usual I forgot the name) web site and the author has put SLOC report for his project. It was pretty cool. I wanted to try it on some of my projects and tried sloccount(http://www.dwheeler.com/sloccount/) in my office but since my office PC doesnt have my personal project sources I was not able to get SLOC report for my projects.


Today I suddenly, I remembered about SLOC and tried it on my Ace project. And here is the output
Sam@samxp /cygdrive/e/Projects
$ sloccount ace_test/src
Creating filelist for app
Creating filelist for drivers
Creating filelist for include
Creating filelist for kernel
Creating filelist for lib
Have a non-directory at the top, so creating directory top_dir
Adding /cygdrive/e/Projects/ace_test/src/wscript to top_dir
Categorizing files.
Finding a working MD5 command....
Found a working MD5 command.
Computing results.


SLOC Directory SLOC-by-Language (Sorted)
13716 include ansic=13699,sh=17
9045 kernel ansic=8810,asm=221,python=14
3712 lib ansic=3691,sh=11,python=10
1062 drivers ansic=1051,python=11
41 top_dir python=41
10 app ansic=6,python=4


Totals grouped by language (dominant language first):
ansic: 27257 (98.81%)
asm: 221 (0.80%)
python: 80 (0.29%)
sh: 28 (0.10%)

Total Physical Source Lines of Code (SLOC) = 27,586
Development Effort Estimate, Person-Years (Person-Months) = 6.51 (78.15)
(Basic COCOMO model, Person-Months = 2.4 * (KSLOC**1.05))
Schedule Estimate, Years (Months) = 1.09 (13.10)
(Basic COCOMO model, Months = 2.5 * (person-months**0.38))
Estimated Average Number of Developers (Effort/Schedule) = 5.97
Total Estimated Cost to Develop = $ 879,761
(average salary = $56,286/year, overhead = 2.40).
SLOCCount, Copyright (C) 2001-2004 David A. Wheeler
SLOCCount is Open Source Software/Free Software, licensed under the GNU GPL.
SLOCCount comes with ABSOLUTELY NO WARRANTY, and you are welcome to
redistribute it under certain conditions as specified by the GNU GPL license;
see the documentation for details.
Please credit this data as "generated using David A. Wheeler's 'SLOCCount'."
Pretty cool isnt it? :)

Tuesday, October 27, 2009

Funny numbers

Freebsd kernel source files count vs Makefile count. Just from the numbers it looks like for every 4 source files there is an Makefile. I ran these commands when I thought of converting FreeBSD build system(make) to use waf(http://code.google.com/p/waf/) or scons(http://www.scons.org/).

root@freebsd-sam:/sys#find . -name "*.c" | wc -l
3171
root@freebsd-sam:/sys#find . -name "*.h" | wc -l
3004
root@freebsd-sam:/sys#find . -name "*.s" | wc -l
44

root@freebsd-sam:/sys#find . -name "Makefile*" | wc -l
746

And yes, after seeing this number I let me thought to stay inside for sometime.

Sunday, October 04, 2009

Call Trace without modifying the source

While investigating about gcc flag "-fprofile-arcs", I came to know about a new(to me) gcc flag and this blog entry is about it. For any large C project it is hard to learn/find call graph through code walk. From C prospective unless otherwise you put a printf in each function entry/exit it is hard to find the call trace.

GCC and ICC has a wonderful option "-finstrument-functions" to solve this. This option instructs the compiler to emit instructions to call a external function on each function's entry/exit. Defining these two functions like the following and adding the above option -finstrument-function to your makefile will do the magic.

void noinstrument
__cyg_profile_func_enter(void *this_fn, void *call_site)
{
printf("%p called from %p\n", this_fn, call_site);
}

void noinstrument
__cyg_profile_func_exit(void *this_fn, void *call_site)
{
printf("%p returns\n", this_fn);
}

Of course, you can do anything in these functions, for simplicity sake I just defined them as printfs.

Friday, September 04, 2009

Tracing ld

I was trying to do something with customized FreeBSD kernel which required constructors(.ctors) and destructor(.dtors) sections to be included in the final binary. So I used the normal gnu practice of including the following code into my linker script(/sys/conf/ldscript.i386).
.data.gcov :
{
__CTOR_LIST__ = .;
LONG((__CTOR_END__ - __CTOR_LIST__) /
(__CTOR_LIST2__ - __CTOR_LIST__) - 2 )
__CTOR_LIST2__ = .;
KEEP(*(.ctors))
LONG(0)
__CTOR_END__ = .;
__DTOR_LIST__ = .;
LONG(( __DTOR_END__ - __DTOR_LIST__ )/
(__CTOR_LIST2__ - __CTOR_LIST__) - 2)
KEEP(*(.dtors))
LONG(0)
__DTOR_END__ = .;
}
But when I tried to see the contents of of the linked kernel there were no constructors. Because
__CTOR_LIST__ and __CTOR_END__ are placed next to each other, from the linker script you can see the .ctors comes in between them.
$objdump -t kernel | grep __CTOR
c049cb8c g .data.gcov 00000000 __CTOR_LIST__
c049cb94 g .data.gcov 00000000 __CTOR_END__
c049cb90 g .data.gcov 00000000 __CTOR_LIST2__

$objdump -s -j .data.gcov kernel | head

kernel: file format elf32-i386-freebsd

Contents of section .data.gcov:
c049cb8c 00000000 00000000 00000000 00000000 ................
c049cb9c 5f090000 e7124ac0 e7124ac0 1b4a4ac0 _.....J...J..JJ.
c049cbac 1b4a4ac0 085c4ac0 085c4ac0 06234bc0 .JJ..\J..\J..#K.
c049cbbc 06234bc0 1f374bc0 1f374bc0 d43b4bc0 .#K..7K..7K..;K.
c049cbcc d43b4bc0 b1414bc0 b1414bc0 b2494bc0 .;K..AK..AK..IK.
c049cbdc b2494bc0 d77b4bc0 d77b4bc0 0e894bc0 .IK..{K..{K...K.
I tried to find what ld is doing by enabling --verbose option in SYSTEM_LD (/sys/conf/kern.pre.mk) but it did not help. Then I tried -Map option to ask ld to generate map file and it helped me.

In my environment the kernel is generated in step. First all system objects are partially linked(-r/-Ur option) to generate relocatable kernel. Then this relocatable kernel is linked with some other static modules to create the kernel. From the map files I could see the constructors are present in the relocatable kernel and dropped while creating the proper kernel. I guess it is a bug with ld. So I merged the two step process into one and it worked.

$objdump -t kernel | grep __CTOR
c049cf50 g .data.gcov 00000000 __CTOR_LIST__
c049f4e4 g .data.gcov 00000000 __CTOR_END__
c049cf54 g .data.gcov 00000000 __CTOR_LIST2__

$objdump -s -j .data.gcov kernel | head

kernel: file format elf32-i386-freebsd

Contents of section .data.gcov:
c049cf50 63090000 a7164ac0 a7164ac0 db4d4ac0 c.....J...J..MJ.
c049cf60 db4d4ac0 c85f4ac0 c85f4ac0 c6264bc0 .MJ.._J.._J..&K.
c049cf70 c6264bc0 df3a4bc0 df3a4bc0 943f4bc0 .&K..:K..:K..?K.
c049cf80 943f4bc0 71454bc0 71454bc0 724d4bc0 .?K.qEK.qEK.rMK.
c049cf90 724d4bc0 977f4bc0 977f4bc0 ce8c4bc0 rMK...K...K...K.
c049cfa0 ce8c4bc0 bbf74bc0 bbf74bc0 bb0a4cc0 ..K...K...K...L.

Friday, August 28, 2009

Debugging gcc behavior

While compiling a FreeBSD kernel I encountered the following error message from GNU assembler
Error: suffix or operands invalid for `mov'

I was not sure whether the error is because of my changes are not. But still I have to debug the problem and solve it, so I decided to find what is wrong with the mov instruction. But since gcc created a temporary file and invoked as to assemble it, I couldn’t find the temp file anymore.
Googled and find the following gcc options to find what gcc does.
gcc –v is verbose mode, which prints all the action/scripts gcc is doing.
gcc -### similar to –v but wont execute any commands.
gcc –save-temps saves all the temporary files generated by the gcc. Useful if you want to see the assembly output passed to gnu assembler.
gcc –E Just preprocess the c file
gcc –S generate assembly file.
With gcc –v –save-temps, I got the temporary assembler file used by assembler. Since reading machine generated assembly file is difficult, I tried to find the C source code corresponding to the error. From nearest .file assembler directive I found the C file name and from the .loc directive I found the line number. And the following was the inline assembly in the C file.
__asm __volatile("movl %%ss,%0" : "=rm" (sel));

Was surprised what is wrong with this and why my assembler giving error. Googled again and found this link - http://kerneltrap.org/node/5785. It seems newer gnu assembler(>=2.16) wont support long read/write operations(mov) on segment registers(ds,ss...). So changed the above source to movw %%ss, %o and it compiled perfectly. :)