26 Mart 2013 Salı

Paralel Örüntüler

Aşağıda paralel çalışırken karşıma çıkan örüntülerle ilgili notlarım var.

ThreadPool ile Birbirinden Bağımsız İşlerin Çalıştırılması
Bu en kolay örüntü. ExecutorService'e verilen işin sonucu beklememiz gerekmiyor. Özellikle execute() metodu bu örüntü ile kullanmak için yazılmış.

ThreadPool Olmadan Çalıştırılan Tek Bir İşin Bitmesinin Beklenmesi
Hemen hemen tüm thread kütüphaneleri join isminde bir metod sağlıyorlar. Aşağıdaki bir kaç örnek var.
C#
Örneği buradan aldım.

ThreadPool ile Çalıştırılan Tek Bir İşin Bitmesinin Beklenmesi
C#
Örneği buradan aldım.

Eğer TPL kullanılıyorsa aşağıdaki gibi yapılabilir.

Task t = Task.Factory.StartNew(() => Console.WriteLine("Started"););
t.Wait();

ThreadPool ile Çalıştırılan Tek Bir İşin Bitmesinin Beklenmesi ve Sonucunun Alınması
Java

Executor.execute metodu ile
Bu örüntüde FutureTask kullanılıyor. FutureTask ile işin bitip bitmediği kontrol edilebilir ve gerekirse iş iptal de edilebilir ancak dikkat edilmesi gereken bir nokta var. FutureTask tekrar tekrar kullanılamaz

 FutureTask ya Runnable ya da Callable arayüzününden birisini saran bir sınıf. Runnable arayüzü en eski arayüz ve bir sonuç tipi döndüremiyor çünkü sadece void run() metoduna sahip. Callable arayüzü ise bir sonuç döndürebiliyor çünkü V call() metoduna sahip.

Buradan aldığım örnekte cache içinde önceden hesaplanmış bir sonuç varsa kullanılıyor. Yoksa hesaplam işleminin bitmesi bekleniyor.

public class Cache<K, V> {
    ConcurrentMap<K, FutureTask<V>> map = new ConcurrentHashMap();
    Executor executor = Executors.newFixedThreadPool(8);
   
    public V get(final K key) {
        FutureTask<V> f = map.get(key);
        if (f == null) {
            Callable<V> c = new Callable<V>() {
            public V call() {
                // return value associated with key
            }
        };
        f = new FutureTask<V>(c);
        FutureTask old = map.putIfAbsent(key, f);
        if (old == null)
            executor.execute(f);
        else
            f = old;
        }
        return f.get();
    }
}
Executor.submit metodu ile
Örneği buradan aldım.Future.get() metodu bu sefer timeout mekanizması ile beraber kullanılıyor.

ThreadPool ile Çalıştırılan Birden Fazla İşin Sonucunun Alınması
Java
Bu örüntüde CompletionService kullanılıyor. Buradan aldığım örnekte tek bir işin sonucunun gelmesi ile diğer görevler iptal ediliyor.
void solve(Executor e, Collection<Callable<Result>> solvers)
    throws InterruptedException {
        CompletionService<Result> ecs = new ExecutorCompletionService<Result>(e);
        int n = solvers.size();
        List<Future<Result>> futures = new ArrayList<Future<Result>>(n);
        Result result = null;
        try {
            for (Callable<Result> s : solvers)
                futures.add(ecs.submit(s));
            for (int i = 0; i < n; ++i) {
                try {
                    Result r = ecs.take().get();
                    if (r != null) {
                        result = r;
                        break;//Diğer işlerin bitmesini bekleme
                    }
                } catch(ExecutionException ignore) {}
            }
        }
        finally {
            for (Future<Result> f : futures)
                f.cancel(true);
        }
        if (result != null)
            use(result);
}
Yukarıdaki kodda dikkat edilmesi gereken nokta Future.cancel() metodunun çağırılması. Bu metod alt tarafta Thread.interrupt() metodunu çağırır. Eğer bizim threadimiz aşağıdaki gibi çalışmıyorsa aslında Future.cancel() metodu işe yaramayabilir.

while(!Thread.currentThread().isInterrupted()){
    try{
        // birşeyler yap
    }
    catch(InterruptedException e){
        Thread.currentThread().interrupt();
    }
}

Paralel For ve ForEach Döngüleri
“Parallel.For” for Java? sorusunda bazı döngülerin nasıl paralel çalıştırılabileceği gösterilmiş.Aşağıdaki soruda C# ile for each döngüsü kurulurken, döngüdeki değişkenin kullanılmaması gerektiği gösterilmiş. Örnek:

24 Mart 2013 Pazar

Kod İçinde Harcanan Zamanın Ölçümü

boost
auto_cpu_timer ile kod parçası içinde geçen zamanı ölçmek mümkün.

#include <boost/timer/timer.hpp>
#include <cmath>

int main()
{
  boost::timer::auto_cpu_timer t;

  long total = 0;

  for (long i = 0; i < 100000000; ++i)
    total + =std::sqrt(123.456L); // burn some time

  return 0;
}
C
Buradaki soruda gösterildiği gibi yapılabilir.

Guava
Stopwatch sınıfı ile kod parçası içinde geçen zamanı milisaniye olarak ölçmek mümkün.
Stopwatch stopwatch = new Stopwatch();
stopwatch.start();
//Process
stopwatch.stop();
stopwatch.toString();

stopwatch.reset();
stopwatch.start();
//Process
stopwatch.stop();
stopwatch.toString();
Buradaki örnekte Stopwatch sınıfına Ticker verilerek nasıl test yapılabileceği gösterilmiş.

 

17 Mart 2013 Pazar

EINTR

EINTR ne işe yarar ?
Uygulamamıza bir signal gönderilirse, POSIX bu sinyali hemen işlenmesini istiyor. Ancak bazen uygulamamız bir sistem çağrısı içinde bloke olmuş durumda bekliyor olabilir. Bu gibi durumlarda sistem çağrısı iptal ediliyor ve signal işleniyor. Sistem çağrısını yapan kod parçasına da işlemi tekrarlaması için hata kodu olarak EINTR atanıyor.

Hangi metodlarda EINTR'ya bakmak lazım.
Anladığım kadarıyla liste bayağı uzun. Örnek olarak Sleep, Posix Eşzamanlılık Yapıları başlıklı yazılara göz atabilirsiniz.


5 Mart 2013 Salı

DDS ve Reliable Multicast

RTPS Nedir?
Data Distribution Service (DDS) ile gelen ve beraber çalışabilirliği sağlayan "Real Time Publish Subsribe (RTPS)" standardı sayesinde farklı DDS yazılımları arasında iletişim kurulabiliyor. Bu konuyu gösteren örnek bir resimi buradan aldım. RTPS'in yeni ismi DDSI olarak değiştirildi, yani Data Distribution Service (DDS) Interoperability Spec oldu.



RTPS, DDS yazılımları piyasaya çıktıktan sonra, ihtiyaç üzerine yaratıldı. Örneğin 2006 senesinde kaleme alınan bu yazıdaki DDS Limitations bölümünde RTPS'e olan ihtiyaç açıkça yazılmış.

RTPS ile Kullanılabilen İletişim Yöntemleri
RTPS standardında Best-Effort ve Reliable iletişimden bahsediliyor. Benim anladığım her iletişim yöntemi için de Multicast UDP kullanılıyor. Ancak Reliable Multicast için gönderen ve alan tarafın, Acknowledgement mesajları ile haberleşmeleri gerekiyor.

Best-Effort Nedir?
Best-effort iletişimini gösteren bir şekli buradan aldım. Kabaca UDP'ye benziyor. Gönderilen verinin gidip gitmediği kontrol edilmiyor.

Bir başka şekilde Best-Effort ile gönderilen verinin ağda kaybolması durumunda, verinin tekrar gönderilmediği görülebilir.

Reliable Nedir?
Reliable iletişimini gösteren bir şekli buradan aldım. Kabaca TCP'ye benziyor. Gönderilen verinin gittiği kontrol ediliyor. Eğer gitmediyse tekrar gönderiliyor.


Ancak RTPS standardında best-effort ve reliable iletişimden bahsedilmesine rağmen reliable multicast ile iletişim kurulmasından bahsedilmiyor. Bu durumda da DDS yazılımları arasında uyumsuzluklar halen olabiliyor.

Esasen reliable multicast yapmak için bir çok protokol var. Örneğin "Pragmatic General Multicast" popüler multicast protokollerinden birisi. DDS üreticileri de reliable multicast yapabilmek için anladığım kadarıyla kendi kendilerin protokoller hazırlamışlar.

OpenDDS
OpenDDS ile gelen reliable multicast protokolü ve açıklaması da burada.

Öncelikle anlatılan reliable multicast ile klasik multicast protokolü arasındaki farka dikkat etmek lazım. Klasik multicast protokolünde, mesaj dağıtım görevi, gruba üye olan IPleri bilen switch üzerine yüklenmiş durumda. Ancak RTPS protokolünde switch yok ve mesajların gidip gitmediği MULTICAST_NAK (Negative Acknowledgement) mesajı ile pasif olarak mesajları dinleyen aboneye yüklenmiş durumda. Aşağıdaki şekil bu durumu gösteriyor.



OpenSplice
OpenSplice forumundaki http://forums.opensplice.org/index.php?/topic/1212-multicast-communication/ adresinde kendi Native networking service'lerinin nasıl çalıştığını söylemiş.

Dedikleri de :

data will be retransmitted (point-to-point) to those nodes that have not sent an acknowledgement


Anladığım kadarıyla OpenDDS ve OpenSplice arasında reliable multicast uygulaması arasında önemli farklar var.

DDS "History QoS" - Tarihçe

Giriş
Benim gibi DDS'e aşina olmayan insanların karşılaştıkları sıkıntılardan birisi de History QoS'in nasıl çalıştığı konusundaki kafa karışıklığıdır.

History Qos, DataWriter ve DataReader sınıflarının etkiler. Bu sınıflar daha ellerindeki veriyi gönderip almamış iken DDS ara katmanına yeni bir güncelleme mesajı gelince o instance için kaç tane geçmiş güncelleme mesajını saklamak istediğimizi bildirir.

Aşağıda CorexDDS'in sayfasında bunu gösteren güzel bir resim var. Eğer Topic bir anahtar (key) alanına sahipse History Qos resimde de gösterildiği gibi instance başına kaç tane mesajın bellekte tutulacağını belirtir.
 
Yine aynı şekilde benzer bir çizimi burada buldum .



KEEP_ALL Seçeneği
Eğer History QoS KEEP_ALL ise DataWriter ve DataReader cacheleri birer LinkedList gibi çalışırlar ve en son gelen mesajları saklamaya devam ederler.

Keep_All ile Reliable Reliability beraber kullanılırsa etkileri aşağıdaki gibi olur.
Keep_All + Reliable : Tüm mesajlar mutlaka gönderilir. Gerekirse DataWriter bir süre bloke edilir. Buna absolute veya strict reliability deniyor. Güncellik problemi olmayan ve mutlaka işlenmesi gereken durumlarda kullanır. Örneğin bir müşterinin verdiği sipariş emirleri hiç bir zaman kaybolmamalıdır ve uygulama okuyuncaya kadar saklanmalıdır. JMS tabanlı ara katman yazılımları genellikle bu modeli benimsemişlerdir ve gönderilen mesajlar birisi okuyuncaya kadar saklanılır.
Keep_All ile Unreliable Reliability beraber kullanılırsa etkileri aşağıdaki gibi olur.
Keep_All + Unreliable : Tüm mesajlar gönderilmeye çalışılır. Güncellik problemi olmayan ve mesajın mutlaka işlenmesi de gerekmeyen durumlarda kullanılabilir. Kullanım şekli biraz UDP broadcast'i andırıyor. Broadcast için gönderilen tüm paketlerin mümkün olduğunca gönderilmeye çalışılması gibi.
KEEP_LAST Seçeneği
Eğer History QoS KEEP_LAST ise DataWriter ve DataReader cacheler birer circular buffer gibi çalışırlar ve en son gelen N tane mesajı  saklamaya devam ederler.

Keep_Last ile Reliability beraber kullanılırsa etkileri aşağıdaki gibi olur.
Keep_Last + Reliable    : En son N tane mesaj mutlak gönderilir. Eğer henüz gönderilmemiş mesaj varsa silinir ve gönderilmeye çalışılmaz. Buna reduced reliability deniyor.
Bu kısmı daha iyi açıklayan bir cümleyi şuradan aldım
"Or, as a tradeoff for less memory, CPU, and network usage, you can choose a reduced level of reliability where only the last N values are guaranteed to be delivered reliably to DataReaders (where N is user-configurable). In the reduced level of reliability, there are no guarantees that data sent before the last N are received; only the last N data packets are monitored and repaired if necessary."
Keep_Last ile Unreliable Reliability beraber kullanılırsa etkileri aşağıdaki gibi olur.  
Keep_Last + Unreliable : En son N tane mesaj gönderilmeye çalışılır. Eğer henüz gönderilmemiş mesaj varsa silinir ve gönderilmeye çalışılmaz. Örneğin radardan gelen en son N tane plot'ın tracker'a sokulması için kullanılabilir.
KEEP_LAST kullanılırken OpenDDS'te circular buffer dolu ise ve yer açmak gerekiyorsa bu durum kabaca şöyle kodlanmıştır.
DataWriterImpl::write()->
WriteDataContainer::obtain_buffer()->
WriteDataContainer::remove_oldest_sample()->//En eski instance silinir
WriteDataContainer::enqueue()->//Silinen instance'a ait daha gönderilmemiş mesaj silinir
PublicationInstance->enqueue_tail_next_instance_sample ()//listenin sonuna eklenir







22 Şubat 2013 Cuma

DDS ResourceLimits QoS - Kaynak Sınırı

Giriş
DDS'in amacı her zaman dağıtılan veriyi bazı ölçütlere göre süzmek ve süzgeçten geçemeyenleri dağıtmamaktır.

ResourceLimits kaynak kullanımını sınırlandırır. Arzu edilenden çok daha fazla veri geliyorsa, fazlalığı dağıtmaz.

ResourceLimits QoS ile max_samples, max_instances ve max_samples_per_instance parametrelerini ayarlamak mümkün.

max_samples Alanı
OpenDDS'i incelerken sadece max_samples parametresinin kodlandığını gördüm. Diğer parametrelerin nasıl çalıştıklarını da anlamadım.

max_samples'ın nasıl çalıştığını gösteren şekli buradan aldım ve aşağıda bulabilirsiniz. max_samples QoS parametresi atanmış iken (örneğin 2) üst sınırı aşmamıza sebep olacak yeni bir key numarası  ile örnek yaratmaya çalışırsak DDS bunu reddedecektir.Eğer bu parametre atanmaz ise elimizdeki hafıza miktarı kadar yeni key numarasına sahip yeni örnek yaratabiliriz.Bu parametre hafızanın sınırlı olduğu gömülü sistemlerde işe yarayabilir.


3 Şubat 2013 Pazar

IMSS

Integrated Maritime Surveillance Systems (IMSS) projesi nedir ?

IMSS (Integrated Maritime Surveillance Systems) projesi anladığım kadarıyla Ege ve Akdenizi gözetleyecek radar sistemlerinin kurulması, bu sistemlerden gelen verilerin birleştirilerek Tanımlanmış Deniz Resminin (TDR) çıkarılmasını hedefliyor. Ege'deki artan Yunan tehditine karşılık düşünülen projenin ihale süreci 1999 yılınan kadar uzanıyor. İhale sürecinden sonra 2003 yılında proje başlamış ve 50 milyon dolar değerinde.

Türkiye'nin 3 tane denize kıyısı var ancak anladığım kadarıyla proje sadece Ege ve Doğu Akdeniz ile ilgili. Karadeniz kapsama dahil değil.

Bu projenin diğer ismi ise Uzun Ufuk. Proje kapsamındaki en önemli unsur 180 km menzile sahip Fransız Thales ürünü Suricate Mk2 2 Boyutlu X-Band hava ve satıh gözetleme radarı. Bu radar anladığım kadarıyla normalde gemide kullanılırken, istek üzerine karada çalışacak şekilde değiştirilmiş.

Projenin Taktik Veri İşleme ve Haberleşme altyapısına sadece Türk firmalarının teklif vermesi istenmiş.

Aşağıdaki şekilde bu projenin izleyeceği Kuzey Ege'nin haritası var.


Uzun Ufuk ve Yunus Projelerinin Birbiri ile İlgisi Nedir?
Uzun Ufuk su üstü resmini çıkartmaya yarıyor. Yunus projesi ise üs güvenliği ve su altı resminin çıkartılması işlevini yerine getiriyor. Böylece Ege ve Akdeniz'in bir kısmında su altı ve üstü güvenliği sağlanıyor.

Radarlar nerede ?
Bu konunun cevabını bilmiyorum. Ama anladığım kadarıyla radarlardan bir tanesi İzmir'de.

Savunma ve Havacılık Dergisi No : 135'te yazan bilgilere göre bu projede kullanılan veri füzyon merkezi Yenikale/İzmir'de bulunuyor.