Search This Blog

Saturday, November 22, 2008

Porting to “Intel C Compiler”

In this post, I will explain how to easy it is to compile/port C programs and makefiles designed for GCC(GNU compiler collection) can be used with ICC(intel c compiler)

The necessity for using ICC happened to me because gcc was generating much bigger object files. Ace is using ACPI-CA(http://acpica.org/) as it is ACPI driver. After compilation the ACPI library is around 7M in debug version and around 500K in non-debug version. But from http://acpica.org/download/changes.txt it seems Microsoft C compiler produce smaller code.
    Non-Debug Version:  81.2K Code, 17.0K Data,  98.2K Total
    Debug Version:     155.8K Code, 49.1K Data, 204.9K Total

So I decided to try “Intel Compiler” as replacement for GCC. Things were easy, since icc has options which is similar to gcc.

You can get the details of portability options from icc documentation -http://www.intel.com/software/products/compilers/docs/clin/main_cls/index.htm.

I just changed my make.conf file to check the compiler in use and use appropriate options. I removed -fno-leading-underscore and –Wall. I removed –Wall because it was giving lot of warnings, we have to fix our code sometime soon. I removed -fno-leading-underscore because there is no equivalent option in icc, however icc does not adds underscores to symbols anyway. 

I added –O1 option because the kernel was panicked during boot with invalid opcode exception, I believe it was because of some MMX register usage by icc. So I settled with –O1 now.

ifeq ($(CC),gcc)
    DEBUG_FLAGS= -gdwarf-2 -g3
    CFLAGS+= -Wall -Wno-multichar $(DEFINES) -nostartfiles -ffreestanding -funsigned-char -fno-leading-underscore -c -fno-stack-protector $(DEBUG_FLAGS) $(CUSTOM_FLAG)
else
    DEBUG_FLAGS= -gdwarf-2 -g
    CFLAGS+= -O1 -Wno-multichar $(DEFINES) -nostartfiles -ffreestanding -funsigned-char -c -fno-stack-protector $(DEBUG_FLAGS) $(CUSTOM_FLAG)
endif

I also made some static variables in kernel/i386/gdb_stub.c to non-static because icc appends .0 to static variables but it forgets the same name when referenced in a inline assembly code in the same file. After removing the static attribute it is working fine.

gcc compiler took the following time to compile Ace source code.
real    0m51.125s
user    0m36.975s
sys     0m11.185s

icc compiler took the following time to compile Ace source code.
real    1m44.366s
user    0m59.107s
sys     0m20.946s

Gcc produced double the size of kernel.sys produced by icc. (I used GNU linker(ld) and ar).

gcc output size:
[samuel@linux Ace3]$ ls -lh /home/samuel/Projects/Ace3/obj/
-rw-rw-r-- 1 samuel samuel 372K 2008-11-22 18:17 acpi.a
-rw-rw-r-- 1 samuel samuel 545K 2008-11-22 18:17 arch.a
-rwxrwxr-x 1 samuel samuel 1.3M 2008-11-22 18:17 kernel.sys
-rw-rw-r-- 1 samuel samuel  62K 2008-11-22 18:17 libds.a
-rw-rw-r-- 1 samuel samuel  40K 2008-11-22 18:17 libheap.a
-rw-rw-r-- 1 samuel samuel  39K 2008-11-22 18:17 libstring.a
-rw-rw-r-- 1 samuel samuel 9.5K 2008-11-22 18:17 libsync.a
-rw-rw-r-- 1 samuel samuel  91K 2008-11-22 18:17 pic.a
-rw-rw-r-- 1 samuel samuel  23K 2008-11-22 18:17 pit.a
-rw-rw-r-- 1 samuel samuel  21K 2008-11-22 18:17 rtc.a

icc output:
[samuel@linux Ace3]$ ls -lh /home/samuel/Projects/Ace3/obj/
-rw-rw-r-- 1 samuel samuel 352K 2008-11-22 16:25 acpi.a
-rw-rw-r-- 1 samuel samuel 230K 2008-11-22 16:24 arch.a
-rwxrwxr-x 1 samuel samuel 528K 2008-11-22 16:25 kernel.sys
-rw-rw-r-- 1 samuel samuel  38K 2008-11-22 16:23 libds.a
-rw-rw-r-- 1 samuel samuel  22K 2008-11-22 16:23 libheap.a
-rw-rw-r-- 1 samuel samuel  21K 2008-11-22 16:23 libstring.a
-rw-rw-r-- 1 samuel samuel  11K 2008-11-22 16:23 libsync.a
-rw-rw-r-- 1 samuel samuel  19K 2008-11-22 16:24 pic.a
-rw-rw-r-- 1 samuel samuel 8.4K 2008-11-22 16:24 pit.a
-rw-rw-r-- 1 samuel samuel  13K 2008-11-22 16:24 rtc.a

So it is easy to use icc instead of gcc. However since I am using Windows and icc is free only for Linux for non commerical purposes. I stick to gcc to compile Ace in Windows. 

Thursday, November 06, 2008

GNU make slow build process

While building one my project it was taking too much time; the project was taking around 40-60 seconds to build and around 20 seconds to clean. I was frustrated with this because the debugging cycle time for my project was going high.

So I decided to stop debugging my project and start debugging the build process. In my makefile I had .SILENT option and I removed it to see what is going.  The following was the output
make[1]: Entering directory `/cygdrive/g/Projects/Ace3/src/lib'
make[2]: Entering directory `/cygdrive/g/Projects/Ace3/src/lib/string'
make[2]: Nothing to be done for `all'.
..
make[1]: Leaving directory `/cygdrive/g/Projects/Ace3/src/lib'
make[1]: Entering directory `/cygdrive/g/Projects/Ace3/src/kernel'
..
make[2]: Leaving directory `/cygdrive/g/Projects/Ace3/src/kernel/pic'
New kernel is at /cygdrive/g/Projects/Ace3/obj/kernel.sys
/cygdrive/g/Projects/Ace3/img/create_bootcd.sh
Everything was fast, however there was huge delay before getting the output “make[1]: Leaving directory `/cygdrive/g/Projects/Ace3/src/lib'”

Then I tried invoking make with –d (debug) option and it gave the following output
This program built for i686-pc-cygwin
Reading makefiles...
Reading makefile `makefile'...
Reading makefile `/cygdrive/g/Projects/Ace3/make.conf' (search path) (no ~ expansion)...
Reading makefile `boot_module.d' (search path) (don't care) (no ~ expansion)...
Reading makefile `interrupt.d' (search path) (don't care) (no ~ expansion)...
Reading makefile `ktrace.d' (search path) (don't care) (no ~ expansion)...
Reading makefile `main.d' (search path) (don't care) (no ~ expansion)...
And it took lot of time before continuing the from the above step, so I knew something wrong with the main.c dependency file, so I opened it and it had too many entries. I casually checked the size of the file and it was 50MB. That explained why make was slow. I carefully examined the dependency entries and found they were repeating. I opened make.conf and checked the rule for making dependency file and found the culprit 
%.d:    %.c
@$(CC) -c -M $< -I$(INCLUDE) $(CFLAGS) >> $@
The output redirection symbol >> caused the problem. It appended the dependency rules every time I compiled and increased the size of .d file.  I replaced >> with > and now incremental build process completes in 3 seconds.