çekirdek etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
çekirdek etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

8 Eylül 2015 Salı

Git'te Yama Uygularken Oluşan Çakışmaları Çözmek


Yazma iznimizin olmadığı depodaki projeye katkı verme işlemini yama dosyası oluşturarak yaparız. Yama dosyaları karşı tarafa yaptığımız değişiklikleri insan okuyabilir şekilde özetler. Bu konu hakkında kısa bir yazı yazmışım, buradan bakabilirsiniz.

Github üzerinden geliştirdiğim kendi projelerime olan katkıları kabul ederken terminal kullanmadan, web sayfası üzerinden hallediyorum.

Linux çekirdeğinde her takım farklı alt dizinlere baktığından ve çoğu github kullanmadığından işlemleri konsol üzerinden yapmak gerekiyor.

Linux çekirdeğinde uzunca bir süredir büyük bir yama  setini kabul ettirmeye çalışıyorum. İnsanlık için küçük olabilir ama benim için büyük demeden geçmeyelim. Yamanın konusu özetle bellek üzerinde büyük bir baskı olduktan sonra swapten dönerken, ihtiyaç duyulmayan sayfaları da swapten belleğe getirip büyük sayfa oluşturarak, performans sağlamak.

Bu yama uzun bir sürece girdiğinden, linux çekirdeği sürekli güncelleniyor ve benim değişikliklerim deponun eski halindeki gibi kalıyor. Bu durumda karşı taraf uygulamaya çalışırken çakışma oluşacak, yama bu nedenle reddedilecek.

Eskiden hep küçük değişiklikler yaptığımdan ve daha kısa süreçte bittiğinden, kendi yamamı güncel depoya uygulama ihtiyacı duymadım. Her satırı tekrar kontrol ederek yeniden oluşturuyordum. Yama büyük olduğunda işler böyle olmadı. Her satırı tekrar oluşturmak çok zor ve derlemede hata almıyorsam bile mantıksal hata yapma ihtimalim çok yüksek.

Değişiklikleri uygulamadan önce git apply --check yama_dosyası şeklinde yamanın uygulanabilir olup olmadığını kontrol edebiliriz. Eğer git apply yama_dosyası komutunu verirsek, yamayı commit yapmadan depoya ekler. Bu durumda değişiklikler commitlenmediği için de git diff ile farkları görebiliriz. Bu bize yama dosyasını ekleyip, commit yapmayarak elle başka değişiklikler yapmaya olanak verir. Tüm değiştirmek istediğimiz dosyalar bittikten sonra kendimiz git commit -a komutuyla değişiklikleri loglayabiliriz.

Yamanın commit yapılarak depoya eklenmesini istiyorsak git am < yama_dosyası şeklinde uygulamalıyız.

Eğer daha önceden yaptığımız commitlerde düzenlemeler istiyorsak git rebase harika bir araç. Onunla ilgili daha önceden bir yazı yazmıştım, buradan bakabilirsiniz.

Yama uygularken geçenlerde karşılaştığım durum, yamanın (muhtemelen) güncel depoyla uyumlu olmamasından kaynaklıyordu. Hata aldığım makine çok sık kullandığım bir makine değildi, belki daha önceki başka bir şeyden kaynaklanıyor da olabilir. Hata mesajı şu şekilde:

Applying: mm: add tracepoint for scanning pages
error: include/trace/events/huge_memory.h: already exists in working directory
error: patch failed: mm/huge_memory.c:2673
error: mm/huge_memory.c: patch does not apply
Patch failed at 0001 mm: add tracepoint for scanning pages
The copy of the patch that failed is found in:
   /home/ebru/linux-stable/.git/rebase-apply/patch
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".

Bunu görünce daha önceden aynı commitler depoda vardı, bu yüzden bir yerde indeksleri tutuluyor düşündüm. mv linux-stable/.git/rebase-apply ..path/ ile rebase-apply dizinini başka bir yere taşıdım. Tekrar yamayı uygulamaya çalıştım yine aynı hatayı aldım (kaldırdığım dizin tekrar oluştu).

Bunun çözümü şu şekilde hatayı aldıktan sonra, git apply linux-stable/.git/rebase-apply/patch --reject komutunu veriyoruz. Bu sayede yamanın çakışma oluşturmayan kısımları depoda oluşturuluyor.

Checking patch include/linux/mm.h...
Checking patch include/trace/events/huge_memory.h...
error: include/trace/events/huge_memory.h: already exists in working directory
Checking patch mm/huge_memory.c...
Hunk #1 succeeded at 30 (offset 1 line).
Hunk #2 succeeded at 2270 (offset 53 lines).
Hunk #3 succeeded at 2307 (offset 53 lines).
Hunk #4 succeeded at 2319 (offset 53 lines).
Hunk #5 succeeded at 2327 (offset 53 lines).
....
       ........
Hunk #13 applied cleanly.
Hunk #14 applied cleanly.
Hunk #15 applied cleanly.
Hunk #16 applied cleanly.
Rejected hunk #17.
Hunk #18 applied cleanly

Bu şekilde uygulanan/uygulanamayan kısımları özetliyor. Uygulamada sorun oluşturan her dosya için uygulanamayan kısımları dosya_adı.rej uzantılı diff dosyası oluşturarak bize gösteriyor. Bu dosyaları git status ile bakarsak görebiliriz. Bu süreçte depo aslında rebase etme gibi git apply sürecinde oluyor. Yamanın uygulanmayan kısımlarına .rej uzantılı dosyalardan bakıp, kendimiz dosyaları açıp değişiklikleri yapıyoruz. git status ile tekrar bakıp eklememiz gereken dosyaları git add ile ekledikten git am --resolved ile işlemi sonlandırıyoruz. Bu şekilde çakışma oluşan yama dosyalarını depoya uygulamış olduk.

Çakışma çözme işlemini bu yazıdan okuyarak öğrendim. Umarım benim yazım da faydalı olmuştur.

5 Ağustos 2015 Çarşamba

Red Hat'te Linux Çekirdeği Geliştiriciliği

Geçtiğimiz kış Outreachy'de Linux çekirdeği üzerinde, Red Hat'te çalışan Rik van Riel'in danışmanlığında staj yaptım.

Staj bitiminde Rik istersen Red Hat'te birkaç pozisyona başvur, ileride seninle birlikte çalışmak isterim dedi. Aslında birkaç sene daha Türkiye'de kalma kararımı Google görüşmesinden sonra vermiştim ama Red Hat'te çalışma düşüncesi de geri çevirilemez bir şeydi, o yüzden kabul ettim.

İlk önce jobs.redhat.com adresinde ilgimi çekebilecek olan işlere baktım. Rik deneyimli çalışan aradıklarını söyleseler bile, yeni başlayan pozisyonunda da iş bulabiliriz dedi. Open Stack, Sanallaştırma ve Arm işlemciler için çekirdek geliştirimi olarak 3 farklı pozisyona başvurdum. Bu üç pozisyon üzerinde de hiç deneyimim yok ancak daha uygun pozisyonlar bulamadım. Zaten onlar da deneyimi olmayan eleman alacaklarını biliyorlardı.

Open Stack ekibi İstanbul'dan taşınman gerekir, bu gibi durumlarda deneyimsiz geliştriciler yerine kıdemli olanları tercih ediyoruz ama sen şansını deneyip mülakatlara gir dedi. Sonrasında kıdemli elemana daha çok ihtiyaçları olduğunu belirttiler, diğer görüşmeleri yapmadık.

Sanallaştırma ekibi aynı zamanda Rik'in çalıştığı ekip. KVM ve Qemu'yu geliştiriyorlar. Sanallaştırma pozisyonu için öncelikle başlangıç görüşmesi yaptık. 2 hafta sonrasına gün belirleyip ilk mülakata girdim. En fazla teknik soruyu ilk mülakatta aldım, sorular zor değildi. Glassador'dan okuduğum kadarıyla Red Hat için soruları zor olmuyor yazıyordu. İlk görüşmede spinlock, zamanlama gibi temel çekirdek kavramlarından sordu. Yeni bir konu olsa da gerçek zamanlı algoritmalar üzerinde yorum yapmamı istedi. Üniversitede en sevdiğim dersler, staj projemde neler yaptığım, bir yamayı kabul ettirene kadar en fazla kaç sürüm gönderdiğim, stajda kabul edilen yamaların çekirdeğin kaçıncı sürümünde olduğu, Rik'le nasıl çalıştığım, kodlamaya nasıl başladığım .. şeklinde devam eden staj sürecimin her evresinden sorular aldım. Görüşme sonunda bir sonraki adıma geçtiğimi öğrendim \0/.

Sonraki adım 5 farklı mühendisle görüşmeyi içeren bir paket gibi. Bu görüşmelerin hepsi aynı günde olmak zorunda değil ve her biri yaklaşık 50 dk sürüyor.

Red Hat görüşmeleri Google'ınki kadar zor değil ve görüşme zamanlarını istediğimiz kadar geniş bir süreye yayamıyoruz. İki görüşme arasındaki süreyi Google pek önemsemezken, Red Hat'teki arkadaş senin yerine başka birini işe alabilirler, bu yüzden görüşmelere ne kadar erken girsen o kadar iyi demişti.

Diğer görüşmeler çok az teknik soru içeriyordu. Genelde stajda neler yaptığım üzerine konuştuk. Bir gün iki görüşmeye birden girdim. O akşam pek yorucuydu diyebilirim. Birde Google görüşmelerinde bu kadar heyecanlanmadım. Sanırım 3. görüşmeden sonra normal heyecanda konuşabildim.

Son görüşmeyi Rik'in içinde bulunduğu takımın yöneticisi olan bir kadınla yaptık. Tüm görüşmeler içindeki tek kadındı. Görüşebileceğim en yüksek mercideki kişiydi.

Son görüşme çok eğlenceli geçti. Bir iş görüşmesinden ziyade bir arkadaşımla konuşuyormuşum gibiydi. Teknik sorular yok denecek kadar azdı. Çanakkale'den, şimdiki işimden, neden çekirdek üzerinde çalıştığımdan, Türkiye'den taşınma durumumdan konuştuk.

Bu görüşmeden bir iki hafta sonra Red Hat'te işe alındığımı öğrendim, Brno'da çekirdek geliştiricisi olarak çalışacaktım.

Birkaç aydır pek iyi değildim, rahatsızlığım zirveye ulaştığında doktora gittim. Şimdilik çok ciddi bir rahatsızlığım yok ancak İstanbul'dan taşınmaya yetecek kadar da iyi değilim, ülkeyi değiştirmek zaten zor bir durum .. Ben bu kararsızlıklar içerisindeyken Red Hat'e de bunu söyledim, taşınmam 4 ay sürer, ben birkaç ay daha geciktirsem gitmeyi derken Red Hat'ten gelen maaş teklifi çok az oldu. Birde taşınma masraflarını zaten karşılamıyorlar. Bir iki firmadan duyduğum kadarıyla taşınma konusunda çok yardımcı olan yerler de var ..

Brno netten gördüğüm kadarıyla pahalı bir yer değil, ancak Red Hat'in €1k'nın biraz altında maaş teklif etmesine şaşırdım. Mezuniyetten sonra bir seneye yakın bir zaman evden çalıştım ve bu zamanı çok da fazla karşılık almayarak geçirdim. Başarılı projelere bu şekilde katkı vermek bir süreliğine benim için kabul edilebilir bir şey. Ancak bunu yurtdışındayken ve sağlığım da şuan için çok iyi değilken kabul etmedim.

Aslında Red Hat kabul etmediğimde evden çalışmayı teklif etti, kabul ettim ancak sonrasında yeni başlayanların bir sene boyunca ofiste çalışması gerektiğini ve ilk yıldan sonra evden çalışma izinlerinin olduğunu söyledi. Neticede maaş ve rahatsızlığım nedeniyle kabul etmemiş oldum. İk'daki arkadaşa Brno'da çalışmayı İstanbul'da birkaç sene çalıştıktan sonra olsaydı kabul ederdim, dedim. Daha sonraki bir zamanda eğer çalışmak istersem kendisiyle iletişime geçmemi istedi.

Bugünlerde kendime iyi bakıp, daha sağlıklı yaşayarak hayatımı düzene oturtmaya çalışıyorum. Zaten öğrenciyken de yaşama şeklimi değiştireceğim diyerek kendime bu sözü vermiştim. Ben bu sözü tutmaya başlamadan önce, vücudum bana uyarıyı verdi :p. Aslında çok önemli şeyler değil ama çok geç saatlere kadar uyanık kalmamak, az tuzlu yemek, sağlıklı beslenmeye çalışmak gibi okul temposundan sonra daha normal koşullarda çalışmayı düşünüyorum :).

Yurtdışına yine giderim, sonraki zamanlarda karşıma daha iyi koşullarda başka fırsatlar çıkar diye ümit ediyorum.

25 Nisan 2015 Cumartesi

Linux Stajı Sonucunda


12 Mart sonunda Outreachy (OPW) kış dönemi stajları sona erdi. Ben bu süreçte bellek yönetiminde, THP (transparent huge page) kodları üzerinde çalıştım. Birlikte çalıştığım danışmanımın istersen bir süre daha birlikte çalışmaya devam edebiliriz demesiyle şimdi hala devam ediyorum :).

Staj sürecinde sadece okunur sayfalar, sıfır içerikli sayfalar (zero page, bellekte henüz eşleme yapılmamış sadece okuma isteği almış ve veri içermeyen sayfa) ve swap cache üzerinde çalıştım. Swapteki veriler için birini stajdayken diğeri stajdan sonra olmak üzere iki yama hazırladım. İkisininde ortak yanı do_swap_page kısmında takılıyor olmaları ^_^. Sistem bazen askıda kalıyor, bazen boot aşamasında bile bir panik oluyor gibi problemleri var hala. Koddaki sayaçların değerini daha iyi görebilmek için tracepoint yazdım. Tracepointi de ayrı bir yama olarak göndereceğiz. Askıda kalma problemleri için en iyi yöntemler ise serial console ya da netconsole kullanmak. Geçen gün Sarah Sharp'ın günlüğüne bakarken burada bir netconsole yazısı gördüm :). Askıda kalma olayı genelde spinlocklarda bir hata yaptıysak oluşuyor.

Outreachy'de, Linux Vakfı kendi stajerlerini 5 dakikalık kısa konuşma yapmak için Linuxcon'a davet ediyor. Ben Dublin'de olana katılacağım, Seattle'da olan biraz fazla uzak. Zaten bu ara hangi etkinliğe gitmek istesem hep Dublin'e denk geliyor, aslında ben mümkün olduğunca başka şehirler seçmeye çalışıyorum :).

Nisan başında lwn.net'te stajımla ilgili bir yazı yayınlayacaktık, yazının taslağı hazır, sanırım swaplerle olan işler bittikten sonra onları da ekleyip yayınlayacağız.

Bu staja alınmam benim için biraz sürpriz gibi oldu. Necdet hocanın hadi Ebru başvursana demesiyle başvurdum ve çok iyi oldu, çok da güzel oldu :).

Mezuniyetimden beri evden çalışıyorum, bu biraz değişik oldu. Muhtemelen bir ay daha evdeyim, sonra bir süre çekirdeğe ara verip başka işlere bakıp, sonrasında tekrar döneceğim :). Çekirdek üzerinde çalışmanın diğer alanlara göre daha fazla dikkat gerektirdiğini düşünüyorum. Çünkü bir yerde hata yaparsam o değişikliği geri almak daha uzun sürüyor, daha fazla şeyi kontrol etmem gerekiyor.

Staj sürecimde işini çok iyi yapan insanlarla birlikte çalıştım. Rik, 12 senedir Linux üzerinde çalışıyor. Bunun ilk duyduğumda bir yutkunma .. :).

Aslında üniversiteye başladığımdan beri hep işini çok iyi yapan, hayran olduğum insanlarla bir aradayım. "Harika insanlarla birlikte çalıştım" diyebilmek, bu hayattaki en güzel şeyler arasında ilk sıralarda yer alır. Çomü'de bilgi işleme gitmeye başladığımdan beri ben de bu sözü söyleyebiliyorum ve iş hayatında da böyle devam eder diye ümit ediyorum :).

17 Nisan 2015 Cuma

Linux Çekirdeğine Tracepoint Eklemek

Linux kaynak kodunda değişiklik yaptıktan sonra, bunları izlemek için farklı yollar var. Ben henüz çok değişik bir şey kullanmadım. Bu zamana kadar hep printk ile kern.log'a aktarıp, sonra grep, wc, tailsplit gibi komutlarla inceleme yapıyordum. Aslında çok farklı şeyler kullanırım sanmıştım :) ama danışmanım ilk olarak bu yöntemi önerdi.

kern.log'u incelemek sandığım kadar rahat olmuyor, her adımda kodun patlamadığından emin olmalıyım. Bu yüzden bir sürü şey yazdırıyorum, gerçi panik olduğunda otomatik olarak loglara düşüyor ama bazı askıda kalma durumlarında düşmeyedebilir. Birde her testten sonra log dosyasını boşaltıyorum sonra içinden bir şeyler parse etmek zorlaşıyor, sadece 1 test için dosya boyutunun 15M olduğunu hatırlıyorum. kern.log'u boşaltmak için bir yöntem olarak "sudo tee /var/log/kern.log < /dev/null", bunu kullanabiliriz. Hiç boşaltmadan test yapmaya devam ettiğimde dosya boyutu .. ^_^. Elbette inceleme yapılamayacak kadar büyük oluyor diye bir düşüncem yok ama zorlaştırmasak iyi olur.

Uzunca bir süredir yaptığım değişikliklerde beklenmedik sonuçlar görüyorum, aslında beklenmedik sonuçlar görmek elbette en beklendik şey :P, ilk zamanlar test yaparken her testte farklı bir sonuç görürdüm. Danışmanımın emin misin bunu gördüğüne, o zaman şunu da ekle demesine neden olmuşumdur, sonra başka bir testte ben yanlış bakmışım problem o değilmiş şeklinde döndüğüm çok olmuştur :). Ancak bu sefer öyle olmadı, ben uzunca bir süre hep aynı beklenmedik sonucu aldım. Bu durumda oluşabilecek ihtimaller, 1- ben yanlış bakıyorum, 2- pteleri swapten çektiğim halde hala bir şeyler onların swapte gibi loglanmasına neden oluyor, bunun nedeni belleği mantıklı kullanmak ya da tekrar swape gitmesi gerekirse daha az işlem yapmak istemeleri olabilir.

Test yaparken 800M'lık verinin üzerindeki değişimlere bakıyorum, büyük sayfalar 2M olarak tutuluyor. Tek bir büyük sayfa için 512 kere (normal sayfalar 4kB) döngü yapılıyor, benim de her döngüde 15 satıra yakın yazdırdığımı düşünürsek, bu durumda loglarda gözümden bir şey kaçmamıştır demek pek mümkün değil :). İşte tam bu gibi problemler için tracepoint'ler var.  Tracepoint eklediğimiz her fonksiyon için bir kez çalışıyor, aslında değişkenlerin son değerini, kodun sonuna printk ekleyerek de yazdırabiliriz. Ancak bu yöntem boş yere kern.log'u dolduruyor ve kendi testlerimiz için eklediğimiz printk'lar ile birlikte upstream'e yama gönderemeyiz zaten, yani göndermesek iyi olur :). Tracepointler; printk ekledim, eklemeyi unuttum (bir daha derle), upstreame göndermeden önce printk'ları kaldır bir daha derle - test et gibi şeyleri önlüyor. Tracepoint kodu yazıyoruz ve bir kere derliyoruz, sonra eğer o değişkenlerin değerine bakmak istersek perf aracı ile testleri çalıştırıyoruz ve değerleri görüyoruz :).

Tracepoint Nasıl Tanımlanır?

Daha önceden tanımlanmış tracepoint kodlarını inceleyebiliriz. Birde lwn.net'te çok açık anlatan yazılar var. Örneğin vmscan.c'deki birkaç fonksiyon için tracepoint ekleyeceğiz. Bunun için  include/trace/events/'de vmscan.h dosyası oluşturmalıyız. Tracepoint yazmak için yapmamız gerekenler: 1) temel tanımlamaları yapmak, 2) TRACE_EVENT() tanımlamak, 3) TRACE_EVENT içerisinde belirttiğimiz fonksiyonu kaynak kodda çağırmak.

#undef TRACE_SYSTEM
#define TRACE_SYSTEM vmscan

#if !defined(_TRACE_VMSCAN_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_VMSCAN_H

TRACE_EVENT(....
                             .....
);

#endif /* _TRACE_VMSCAN_H */
#include <trace/define_trace.h>

Şimdi TRACE_EVENT() içeriğini tanımlayalım:
TRACE_EVENT(name, proto, args, struct, assign, print)
name: Kaynak kod içerisinde çağırılacak fonksiyonun adı.
proto: Fonksiyon için prototip.
arg: Fonksiyonun alacağı değişkenler.
struct: Tracepoint içine geçen verilerin depolanması için yapı.
assign: Değişken ataması yapmak için kullanılıyor.
print: Değişkenleri yazdırmak için kullanılıyor.

Yazdırmak istediğimiz değişkenler sadece struct shrinker *shr ve unsigned long lru_pgs değişkenleri olsun:

TRACE_EVENT(mm_shrink_slab_start,
    /* proto */
    TP_PROTO(struct shrinker *shr, unsigned long lru_pgs),
    
    /* arg */
    TP_ARGS(shr, lru_pgs),

   /* struct */
    TP_STRUCT__entry(
        __field(struct shrinker *, shr)
        __field(unsigned long, lru_pgs)
    ),

    /* assign */
    TP_fast_assign(
        __entry->shr = shr;
        __entry->lru_pgs = lru_pgs;
     ),

     /* print */
     TP_printk("shr = %p,  lru_pgs = %ld",
                       __entry->shrink,
                       __entry->lru_pgs)
);

TRACE_EVENT içerisinde mm_shrink_slab_start şeklinde belirttiğimiz fonksiyonu, vmscan.c dosyasından, önüne trace_ ekleyerek bu şekilde çağırıyoruz: trace_mm_shrink_slab_start(shr, lru_pgs); Bu değişkenler için sırasıyla proto, arg, struct ve assing'ı tanımladık. Daha sonrasında print ile yazdırma kısmını ekledik.

vmscan.h dosyasının tüm içeriğine buradan bakabilirsiniz. Dosya içerisinde event_class, define_event gibi tracepoint'leri gruplayarak tekrara düşmeyi önleyen makrolar kullanılmış. Ben henüz bunlara gerek duymadım. Tracepoint kullanmak için yukarıda belirttiğim 3 temel maddeyi yapmak yeterli.

                   http://lwn.net/Articles/379903/