Derleme Make Hata Ayıklama C. Ahmet MERCAN İ TÜ Bi l i şi m Enst i t üsü 12 Hazi r an 2012
2 Neler Anlatılacak? Derleme (Compiling) Make / Makefile Hata Ayıklama (Debug) Bu sunumu indirmek için: http://training.uhem.itu.edu.tr/docs/
3 Derleme (Compiling)
4 Intel/GNU Yazılım Geliştirme Araçları Intel Derleyiciler: Intel C Compiler (icc) Intel C++ Compiler (icpc) Intel Fortran Compiler (ifort) Intel Debugger (idb) GNU Derleyiciler: gcc g++ gfortran gdb Intel Performans Kütüphaneleri: Intel Math Kernel Library Intel Threading Building Blocks Intel Performance Primitive Muadilleri: Blas,Lapack,scalapack
5 İntel Derleyici ve MPI # for using intel compilers and mpi libs export INTEL_LICENSE_FILE=/RS/progs/intel/licenses:/opt/intel/licenses. /RS/progs/intel/Compiler/11.1/069/bin/iccvars.sh intel64. /RS/progs/intel/Compiler/11.1/069/bin/ifortvars.sh intel64. /RS/progs/intel/impi/3.1/bin64/mpivars.sh # Intel Trace Analyzer and Collector. /RS/progs/intel/itac/7.1/bin/itacvars.sh # Intel Thread Checker. /RS/progs/intel/Tcheck/bin/Tvars.sh # Intel Vtune Performance Analyzer. /opt/intel/vtune/bin/vtunevars.sh
6 Merhaba Dünya! merhaba.c: #include <stdio.h> int main() { printf("merhaba Dunya!\n"); exit(0); }
7 Basit Derleme İntel: C: icc merhaba.c -o merhaba.x C++: icpc merhaba.cpp -o merhaba.x Fort: ifort merhaba.f90 -o merhaba.x GNU: C: gcc merhaba.c -o merhaba.x C++: g++ merhaba.cpp -o merhaba.x Fort: gfortran merhaba.f90 -o merhaba.x g77 merhaba.f77 -o merhaba.x
8 Koddan Çalışan Program Oluşturma #include<stdio.h> () main int { printf( Merhaba ); } Derleme Derlenmiş Kod 1 #include<stdio.h> (...,* int printf(char {... } Derleme Derlenmiş Kod 2 Link Çalışan Uygulama
9 İki Adımda Derleme İntel: icc -c merhaba.c icc merhaba.o -o merhaba.x Derleme Aşaması Link Aşaması GNU: gcc -c merhaba.c gcc merhaba.o -o merhaba.x
10 Koddan Çalışan Program Oluşturma DEĞİŞEN KISIM! #include<stdio.h> () main int { printf( Merhaba ); } #include<stdio.h> (...,* int printf(char {... } Derleme Derleme Derlenmiş Kod 1 Derlenmiş Derlemeye Gerek Yok! Kod 2 Link Çalışan Uygulama
11 Birden Çok Dosyalı Kod Derleme Tek seferde: icc dosya1.c dosya2.c -o uygulama.x Her dosya ayrı: icc -c dosya1.c icc -c dosya2.c icc dosya1.o dosya2.o -o uygulama.x
12 En iyileme (Optimization) -O[n] parametresi ile verilir: O0 optimizasyon kapalı, gcc için standart bu. O1 Uygulamanın boyutunu büyütmeden optimizasyon yapar. Döngü ağırlıklı kodlar için uygun değildir. O2 icc'de standart optimizasyon bu. Genelde en hızlı kodu bu üretir. Uygulama boyutu büyür. O3 Standart optimizasyona ilaveten bazı ilave abartılı optimizasyonlar yapar. Özellikle büyük veri dizileri üzerinde çalışan ve/veya çokca döngü içeren kodlar için uygundur (YBH gibi). Os O2 gibi ama boyutu büyütenler hariç (gcc).
13 En iyileme (Optimization): FAST *** Sadece İntel Derleyicilerde -fast parametresi ile en hızlı yapacağı varsayılan parametreler seçilir: O3 Abartılı optimizasyon yap ipo birden fazla dosyaya bölünmüş kısımları da gözeterek optimizasyon yapar. static shared kütüphaneleri kullanmaz. xhost CPU'a özel kod üretir. Bazı cpu'lar için bu desteklenmediğinden bu eklenmez. no-prec-div Bölmede hassasiyeti azaltıp hızlan.
14 Hata Ayıklama (Debuging) -g ile hata ayıklama için kod bilgisi programa eklenir. Ayrıca optimizasyon kapatılır ( -O0 ). icc -g merhaba.c -o merhaba.x gcc -g merhaba.c -o merhaba.x Artık programımızı bir debugger ile kullanabiliriz.
15 Parametre Sırası Sonraki parametre öncekinin etkisini kaldırır: icc -fast -g dersek: icc -ipo -static -xhost -g -O0 demiş oluruz. icc -g -O2 -g ile kapatılan optimizasyon açılır.
16 -mtune :İşlemciye özel optimizasyon *** Diğer işlemciler de çalıştırır. -mtune=pentium Intel Pentium için optimizasyon yapar (gcc/icc). Alternatif ifadeler: generic native i386 i486 i586 pentium pentium-mmx pentiumpro i686 pentium2 pentium3 pentium3m pentium-m pentium4 pentium4m prescott nocona core2 corei7 corei7-avx core-avx-i atom k6 k6-2 k6-3 athlon athlon-tbird athlon-4 athlon-xp athlon-mp k8 opteron athlon64 athlon-fx k8-sse3 opteron-sse3 athlon64-sse3 amdfam10 barcelona bdver1 bdver2 btver1 winchip-c6 winchip2 c3 c3-2 geode
17 -march :İşlemciye özel kod üretir *** Diğer işlemciler de ÇALIŞMAYABİLİR -march=pentium Intel Pentium için kod üretir (gcc/icc). Alternatif ifadeler: native i386 i486 i586 pentium pentium-mmx pentiumpro i686 pentium2 pentium3 pentium3m pentium-m pentium4 pentium4m prescott nocona core2 corei7 corei7-avx core-avx-i atom k6 k6-2 k6-3 athlon athlon-tbird athlon-4 athlon-xp athlonmp k8 opteron athlon64 athlon-fx k8-sse3 opteron-sse3 athlon64-sse3 amdfam10 barcelona bdver1 bdver2 btver1 winchip-c6 winchip2 c3 c3-2 geode
18 İşlemciye özel optimizasyon (intel) -x<tür> Diğer işlemciler de hatalı çalışır / reddeder Host, AVX, SSE4.2, SSE3_ATOM, SSE4.1, SSSE3, SSE3, SSE2, S, T, P, O, B, N, W, K -ax<tür> Optimize kodun normal versiyonunu da tutar SSE4.2, SSE3_ATOM, SSE4.1, SSSE3, SSE3, SSE2,S, T, P, O, B, N, W, K Örnek: icc -axsse4.1,ssse3 merhaba.c
19 Uyarılar -w Tüm uyarıları kapa -Wall Tüm (aslında çoğu) uyarıları göster -Wextra İlave uyarıları göster (gcc) -Wcheck Kodu derlerken ilave kontroller yap (intel) -Weffc++ Effective C++ programming kitabındaki önerilere göre kontrol et. -pedantic ISO standartına uymayanlar için uyar
20 Otomatik Paralelleştirme (intel) -parallel ile SMP makineler için paralelleştirme yapılır: icc -parallel merhaba.c -o merhaba.x OMP_NUM_THREADS değişkeni ile kaç thread ile çalıştırılacağı kontrol edilir: export OMP_NUM_THREADS=4./merhaba.x
21 Otomatik Paralelleştirme (intel) Fortran 'da sadece DO döngüleri paralelleştirilir. C/C++ 'da sadece for döngüleri paralelleştirilir. Pointer aritmetiği içeren döngüler paralelleştirilmez! Diğer döngü yapıları (while vb.) paralelleştirilmez! Diğer döngü olmayan kodlar da paralelleştirilmez! OpenMP ile paralelleştirilir, SMP şart!
22 Raporlar (intel) -opt-report{0 1 2 3} Optimizasyon bilgisi -par-report{0 1 2 3} Otomatik paralelleştirme bilgisi 0 bilgi verme - 1 default - 2-3 en fazla bilgi -vec-report{0 1 2 3 4 5} SSE3 vektörleştirme bilgisi 0 bilgi verme 3 en fazla bilgi 5 neden yapmadı bilgisi icc -vec-report3 -fast matmul.c -o matmul.x
23 Vec-report icc -vec-report3 -fast matmul.c -o matmul.x matmul.c(13): (col. 2) remark: loop was not vectorized: not inner loop. matmul.c(15): (col. 3) remark: loop was not vectorized: vectorization possible but seems inefficient. matmul.c(22): (col. 2) remark: loop was not vectorized: not inner loop. matmul.c(22): (col. 2) remark: loop was not vectorized: not inner loop. matmul.c(22): (col. 2) remark: loop was not vectorized: not inner loop. matmul.c(22): (col. 2) remark: loop was not vectorized: not inner loop. matmul.c(26): (col. 4) remark: loop was not vectorized: not inner loop. matmul.c(24): (col. 3) remark: PERMUTED LOOP WAS VECTORIZED. matmul.c(32): (col. 2) remark: LOOP WAS VECTORIZED.
24 Ne?
25 #include<stdio.h> #define SIZE 1000 double a[size][size]={0}; double b[size][size]={0}; double c[size][size]={0}; Matriks Çarpımı int main(int argc, char ** argv) { long i,j,k; double top=0; printf ("Bir matrisin boyutu= %.2lf MB\n",SIZE*SIZE*sizeof(double)/1048576.0); for (i=0;i<size;i++){ for (j=0;j<size;j++){ a[i][j]=i-j; b[i][j]=j-i; c[i][j]=0; }} for (i = 0; i < SIZE; i++){ for (j = 0; j < SIZE; j++){ for (k = 0; k < SIZE; k++){ c[i][j] += a[i][k] * b[k][j]; }}} for (i=0;i<size;i++){ for (j=0;j<size;j++){ top+=c[i][j]; }} printf ("C toplamı= %.2lf\n",top); }
26 Basit Matris Çarpımı - C Tek Dosya, Sadece Main Fonksiyonu Derleyici Parametreleri Gcc o3 static Gcc o2 Gcc o3 Gcc g Gcc nopar * Autopar (2 cpu) * ipo static o2 * ipo static o3 * o2 * fast o2 * fast * o3 g * nopar 119 263 153 263 263 152 151 263 4205 4195 4129 * Farklı Sonuç D: 260416656250007040.00 F: 260416656250009984.00 41 Kat Hızlanma 6290 6249 6198 0 1000 2000 3000 4000 5000 6000 7000 Geçen Süre (Saniye olarak)
27 Bağımlılığı Fazla C++ Kodu Birçok dosyada, pek çok fonksiyon mevcut Gcc o2 Gcc o3 Gcc g Gcc nopar 12716 12486 18767 18718 Derleyici Parametreleri o2 inline 16344 ipo static o2 16492 ipo static o3 16795 o2 16543 fast o2 16655 fast 16785 o3 16490 g 21686 nopar 16656 0 5000 10000 15000 20000 25000 Geçen Süre (Saniye olarak)
28 Örnek bir iyileştirme (optimizasyon) Derleyiciler nasıl kodumuzun hesapladığı şeyi değiştirmeden bu kadar hızlandırabiliyorlar. Bazı öneriler: Daha iyi önbellek (cache) kullanımı: Ardışık işlemlerin verileri yanyana yerleşince cache miss azalır. Daha iyi vektörleştirme kodu: Tek tip işlem tekrar ederken veriler yanyana yerleşince vektörleştirme mümkün olur. Daha iyi pipeline doldurma: Döngüler bir seferde uygun sayıda işlem yaparsa mümkün.
29 Matrix Çarpımı Cij = Aik * Bkj for ( i = 0; i < SIZE; i++ ) { for ( j = 0; j < SIZE; j++ ) { for ( k = 0; k < SIZE; k++ ) { C [ i ] [ j ] += A [ i ] [ k ] * B [ k ] [ j ]; } } }
30 Matris Çarpımı - Cij = Aik * Bkj 350 300 İcc 11.1 fast Gcc4.1 O3 İcc 11.1 g Gcc4.1 g Döngü Sıralamasının Etkisi 288 313 250 221 239 200 Saniye 150 100 86 110 94 124 50 22 60 61 42 0 i k j k i j j i k i j k j k i k j i
31 Bilgisayar Hafızaları İşlemci (Socket).......... L2 L3 Dış Dünya.. Core L1 Cache Hafıza(RAM) HardDisk/SSD Hızlı, Pahalı, Küçük Yavaş, Ucuz, Büyük
32 Matrix Çarpımı Cij = Aik * Bkj C [ i ] [ j ] += A [ i ] [ k ] * B [ k ] [ j ]; for 3x3 and i, k, j c[0][0]+=a[0][0]*b[0][0] => c[0] += a[0] *b[0] c[0][1]+=a[0][0]*b[0][1] => c[1] += a[0] *b[1] c[0][2]+=a[0][0]*b[0][2] => c[2] += a[0] *b[2] c[0][0]+=a[0][1]*b[1][0] => c[0] += a[1] *b[3] c[0][1]+=a[0][1]*b[1][1] => c[1] += a[1] *b[4] c[0][2]+=a[0][1]*b[1][2] => c[2] += a[1] *b[5] c[0][0]+=a[0][2]*b[2][0] => c[0] += a[2] *b[6] c[0][1]+=a[0][2]*b[2][1] => c[1] += a[2] *b[7] En Hızlı c[0][2]+=a[0][2]*b[2][2] => c[2] += a[2] *b[8]...
33 Matrix Çarpımı Cij = Aik * Bkj C [ i ] [ j ] += A [ i ] [ k ] * B [ k ] [ j ]; for 3x3 and j, i, k c[0][0]+=a[0][0]*b[0][0] => c[0] += a[0] *b[0] c[0][0]+=a[0][1]*b[1][0] => c[0] += a[1] *b[3] c[0][0]+=a[0][2]*b[2][0] => c[0] += a[2] *b[6] c[1][0]+=a[1][0]*b[0][0] => c[3] += a[3] *b[0] c[1][0]+=a[1][1]*b[1][0] => c[3] += a[4] *b[3] c[1][0]+=a[1][2]*b[2][0] => c[3] += a[5] *b[6] c[2][0]+=a[2][0]*b[0][0] => c[6] += a[6] *b[0] c[0][1]+=a[2][1]*b[1][0] => c[6] += a[7] *b[3] En Yavaş c[0][2]+=a[2][2]*b[2][0] => c[6] += a[8] *b[6]...
34 Make
35 Birine bağımlı 30 kod dosyası varsa? DEĞİŞEN KISIM! #include<stdio.h> () main int { printf( Merhaba ); } #include<stdio.h> (...,* int printf(char {... } Derleme Derleme Derlenmiş Kod 1 Derlenmiş Derlemeye Gerek Yok! Kod 2 Link Çalışan Uygulama
36 Makefile <hedef> : <bağımlılık> <bağımlılık>... (tab)<yapılacak işlem> (tab)<yapılacak işlem> program.exe: program.c gcc program.c -o program.exeexe
37 Makefile merhaba.x : merhaba.c icc -fast merhaba.c -o merhaba.x uygulama.x : dosya1.c dosya2.c dosya1.h icc -g dosya1.c dosya2.c -o uygulama.x
38 Make $ make merhaba.x icc -fast merhaba.c -o merhaba.x $ make uygulama.x icc -g dosya1.c dosya2.c -o uygulama.x $ make icc -fast merhaba.c -o merhaba.x
39 Makefile (birden fazla dosya) uygulama.x : dosya1.o dosya2.o genel.h icc dosya1.o dosya2.o -o uygulama.x dosya1.o: dosya1.c dosya1.h genel.h icc -c dosya1.c dosya2.o: dosya2.c dosya2.h genel.h icc -c dosya2.c
40 Make (birden fazla dosya) $ make icc -c dosya1.c icc -c dosya2.c icc dosya1.o dosya2.o -o uygulama.x $ make make: `uygulama.x' is up to date. $ touch dosya1.c ; make icc -c dosya1.c icc dosya1.o dosya2.o -o uygulama.x
41 Uygulama cp -r /RS/projects/workshop/mercan/debugme ~/ Bu debugme dizinindeki programı derleyen bir makefile yazınız. Elle derlerken: gcc -c vektor.c gcc -c debugme.c gcc debugme.o vektor.o -o debugme.x
42 Makefile (DEĞİŞKENLER) CC=icc CFLAGS= -O3 -ipo uygulama.x : dosya1.o dosya2.o genel.h $(CC) $(CFLAGS) dosya1.o dosya2.o -o uygulama.x dosya1.o: dosya1.c dosya1.h genel.h $(CC) $(CFLAGS) -c dosya1.c dosya2.o: dosya2.c dosya2.h genel.h $(CC) $(CFLAGS) -c dosya2.c
43 Makefile (DEĞİŞKENLER) CC=gcc CFLAGS= CXX=g++ CXXFLAGS= FC = g77 FFLAGS= CPP= $(CC) -E CPPFLAGS= LD = ld LDFLAGS = LFLAGS = LOADLIBS = MAKE = make MAKEARGS = 'SHELL=/bin/sh' SHELL = /bin/sh *Ayrıca tüm çevre değişkeleri makefile'a aktarılır.
44 Makefile (DEĞİŞKENLER) # = işareti ile atama değişik davranır AA= Nerede BB= $(AA) Burada AA= Hersey # Artik BB = Hersey Burada AA=$(BB) # Hata, makefile sonsuz döngüye girecekti # Olası çözüm := AA= Nerede BB:= $(AA)_Burada AA:=$(BB) # Sorun yok, AA = Nerede_Burada
45 Makefile (PHONY) all: uygulama.x merhaba.x clean: rm *.o rm uygulama.x merhaba.x.phony: all clean
46 Make (Parametreler) $ make -B icc -c dosya1.c icc -c dosya2.c icc dosya1.o dosya2.o -o uygulama.x $ make -f gcc_ile_derle gcc -c dosya1.c gcc -c dosya2.c gcc dosya1.o dosya2.o -o uygulama.x
47 Otomatik Değişkenler $@ hedefin adını tutar $* hedef ile bağımlılıkların ortak başlangıç bölümü $^ bağımlılıkların tümünü tutar $< bağımlılıklardan ilkini tutar $? hedeften yeni olan tüm bağımlılıklar
48 Makefile (Otomatik Değişkenler) CC=icc CFLAGS= -O3 -ipo uygulama.x : dosya1.o dosya2.o $(CC) $(CFLAGS) $^ -o $@ dosya1.o: dosya1.c dosya1.h genel.h $(CC) $(CFLAGS) -c $< dosya2.o: dosya2.c dosya2.h genel.h $(CC) $(CFLAGS) -c $<
49 Makefile (Tür kuralları) CC=icc CFLAGS= -O3 -ipo % : %.o $(CC) $(CFLAGS) $^ -o $@ %.o: %.c %.h genel.h $(CC) $(CFLAGS) -c $<
50 Makefile (Fonksiyonlar) CC=icc CFLAGS= -O3 -ipo ( c.* SOURCES = $(wildcard (( c,%.o,$(sources.% OBJS = $(patsubst ( OBJ )$ : % $(CC) $(CFLAGS) $^ -o $@ %.o: %.c %.h genel.h $(CC) $(CFLAGS) -c $<
51 Hata Ayıklama
52 Hata Ayıklama (Debuging) -g ile hata ayıklama için kod bilgisi programa eklenir. Ayrıca optimizasyon kapatılır ( -O0 ). icc -g merhaba.c -o merhaba.x gcc -g merhaba.c -o merhaba.x Artık programımızı bir debugger ile kullanabiliriz.
53 Hata Ayıklama (Debuging) Gnu debugger'ı kullanmak için: $ gdb./merhaba.x (gdb) run Intel debugger'ın gnu debugger modunda açılışı: $ idb -gdb./merhaba.x (idb) run $ idb -gdb (idb) file./merhaba.x (idb) run
54 Hata Ayıklama (Debuging) Çalışan uygulamaya bağlantı: $./merhaba.x & [1] 3742 $ idb -gdb./merhaba.x -pid 3742 (idb) $./merhaba.x & [1] 3742 $ idb -gdb (idb) file./merhaba.x (idb) attach 3742
55 Hata Ayıklama (RUN) $ idb -gdb./merhaba.x (idb) run (idb) run parametreler (idb) run parametreler <girdi-dosyası (idb) run parametreler >cikti-dosyası (idb) r
56 Hata Ayıklama (Durma) $ idb -gdb./a.out (idb) run ^C Program received signal SIGINT, Interrupt. 0x00001d75 in matrixmultiply (C=0xf624000, A=0x200000, B=0x7c12000, awcw=4000, ahbw=4000, bhch=4000) at matrixoperations.c:33 33 C[((h*awcw)+w)]+=A[((k*awcw)+w)]*B[((h*ahbw)+k)]; (idb) run Program received signal EXC_BAD_ACCESS, Could not access memory. Reason: KERN_PROTECTION_FAILURE at address: 0xbf3072f8 0x00001f53 in main () at merhaba.c:20 20 fillwith(a, asize, 1.2);
57 Hata Ayıklama (Durma) $ idb -gdb./merhaba.x (idb) break main (idb) run Breakpoint 1, main (argc=4, argv=0xbffff894) at merhaba.c:8 8 int awcw=4; (idb) run (idb) break main (idb) watch bhch (idb) continue Hardware watchpoint 2: bhch Old value = 0 New value = 8 main (argc=4, argv=0xbffff89c) at merhaba.c:12 ( argc==4 ) 12 if
58 Break (idb) break main (idb) break 17 (idb) break matrixoperations.c:100 (idb) break matrixoperations.c:fillwith (idb) break (idb) break 100 if awcw>12 (idb) br
59 Backtrace (bt) Stack yapısını gösterir, programın nerede durduğunu ve oraya nereden geldiğini görürüz: (gdb) bt #0 fillwith (A=0x100120, asize=4, x=1.2) at matrixoperations.c:6 #1 0x00001f20 in main (argc=4, argv=0xbffff8a4) at merhaba.c:28 (gdb) bt #0 fillwith (A=0x100140, asize=4, x=0) at matrixoperations.c:6 #1 0x00001c9b in makeidentity (B=0x100140, ahbw=2, bhch=2) at matrixoperations.c:18 #2 0x00001f39 in main (argc=4, argv=0xbffff8a4) at merhaba.c:29
60 Backtrace (bt) (gdb) bt full #0 fillwith (A=0x100120, asize=4, x=1.2) at matrixoperations.c:6 s = 214748364 #1 0x00001f20 in main (argc=4, argv=0xbffff8a4) at merhaba.c:28 awcw = 2 ahbw = 2 bhch = 2 asize = 4 bsize = 4 csize = 4 A = (double *) 0x100120 B = (double *) 0x100140 C = (double *) 0x100160
61 Diğer Komutlar <enter> son girilen komutu tekrar eder (idb) continue bir olay olana kadar çalış (idb) continue n n adet olay olana kadar çalış (idb) next bir sonraki satırı çalıştır,fonksiyonun içine girmez (idb) nexti bir sonraki komutu çalıştır,fonksiyonun içine girmez (idb) next n n adet satırı çalıştır (idb) step bir sonraki satırı çalıştırır, fonksiyonun içine girer (idb) stepi bir sonraki komutu çalıştırır, fonksiyonun içine girer (idb) step n n adet satırı çalıştırır (idb) finish bu stack'e tekrar dönene kadar devam eder (idb) print <değişken> değişkenin değerini yazar (idb) del n breakpoint'i siler
62 Diğer Komutlar (idb) help (idb) help break (idb) quit (idb) info source (idb) list (idb) list 10,+30 (idb) list 20,45 (idb) list matrixoperations.c:fillwith (idb) list matrixoperations.c:10,20
63 Uygulama cp -r /RS/projects/workshop/mercan/debugme ~/ Bu debugme dizinindeki programı -g ile derleyip, çalıştıralım. Çalıştırırken vektor boyutu vereceğiz:./debugme 8./debugme 32./debugme 4000 Debugging için: gdb debugme.x (gdb) run 32
64 IDE - Eclipse
65
66 SON Teşekkürler