9 Mart 2016 Çarşamba

Memory Mapped File

Giriş
Bu yazı ile ilgili olarak Segmentation Fault ve IPC (Inter Process Communication) başlıklı yazıları okuyabilirsiniz.

Memory Mapped I/O genellikle iki iş için kullanılır. Bunları Memory Mapped File ve Memory Mapped I/O olarak ayırdım. Aslında her ikisi de bir dosyaya yazmak gibi düşünülebilir ancak anlam olarak farklı olduklarını düşündüğüm için iki kısımda inceledim.

Memory Mapped File
Memory Mapped File ile çalışırken açılan dosya byte array gibi kullanılıyor. Dosya RAM'e sayfalar şeklinde yükleniyor.

Memory Mapped I/O ile Yapılan Değişikliklerin Senkronizasyonu

Eğer mmap ile bir dosya açılmış ise, RAM üzerinde yapılan değişiklikler mysnch() veya munmap() metodlarıdan birisi çağırılıncaya kadar diske aktarılmaz.

POSIX
Temel iki metod mmap() ve munmap()'tir.

mmap metodu
mmap ile Memory Mapped File yazısına taşıdım.

msynch metodu
msynch() ile kullanılabilen bazı parametreler aşağıdaki gibidir. mysnch() sadece değişmiş sayfaları diske aktarır.
MS_ASYNC : Performs asycnhronous write
MS_SYNC    : Performs sycnhronous write
MS_INVALIDATE : Invalidate cached data

munmap metodu
mmap'in sonucu olan bellek alanını ve büyüklüğünü parametre olarak geçeriz. Şöyle yaparız
munmap(buf, fs.st_size);

Java
Java ile bu kadar detayı bilmeye de gerek yok. Aşağıdakine benzer bir kod parçası ile çok büyük bir dosya yaratılabilir. Kullanılan önemli sınıflar RandomAccessFile ve FileChannel. Buffer sınıfları olarak ta ByteBuffer veya MappedByteBuffer kullanılabiliyor. ByteBuffer zaten abstract bir sınıf ! Bu yüzden ByteBuffer.allocate() ve ByteBuffer.allocateDirect() metodları var.Örnek:


Write için örnek:
static int length = 0x8FFFFFF; // 128 Mb
FileChannel
channel = new RandomAccessFile("test.dat", "rw").getChannel();
ByteBuffer buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, length );
for (int index=0;index< lenght; index++)
buffer .put (1)
Read için örnek:

How to read files quickly sayfasından aldığım bir başka örnek ise aşağıda. Aşağıdaki kod parçası tüm dosyayı yüklüyor. Burada dikkat edilmesi gereken nokta Android gibi platformlarda çok büyük dosyaları okumamak.

FileInputStream f = new FileInputStream( name );
FileChannel ch = f.getChannel( );
MappedByteBuffer mb = ch.map( ch.MapMode.READ_ONLY, 0L, ch.size( ) );
byte[] barray = new byte[SIZE];
long checkSum = 0L;
int nGet;
while( mb.hasRemaining( ) )
{
    nGet = Math.min( mb.remaining( ), SIZE );
    mb.get( barray, 0, nGet );
    for ( int i=0; i<nGet; i++ )
        checkSum += barray[i];
}
Boost
mapped_file_source sınıfı ile salt okunur erişim sağlamak mümkün. Portable Large File Access By Memory Mapped I/O in C++ Using Boost sorusunda çok büyük dosyaları, tamamen hafızaya yüklemeden okuma örneği verilmiş.

C#
MemoryMappedFile Sınıfı yazısına taşıdım.

Memory Mapped I/O (Hafızaya eşlenmiş giriş/çıkış)

Bazen bir cihaz (peripheral) ile haberleşmek için de kullanıldığı olur. Özellikle Linux'ta device driver kernelspace'te çalıştığı için userspace'te çalışan uygulamalarla haberleşmek için bu yöntemi kullanabilir. Örneğin sabit bir hafıza alanı belli bir cihaza tahsis edilir ve cihaz/sürücü bu alanı dinleyerek verilen komut ve verileri çalıştırır. How does the OS interact with peripherals like sound cards/ video cards etc sorusunda benzer bir cevabı görebilirsiniz. memory mapped i/0 working in linux sorusunda da anlatıldığı gibi I/O bus'ın hızının düşük olması (örneğin hızlı grafikler için yetersiz kalabilir) veya CPU mimarisinin yeterince pin'e sahip olmaması (microcontroller CPU'larda az sayıda pin bacağı bulur) gibi sebepler de Memory Mapped I/O yapılmasını tetikleyen etkenlerdir. Bu işlem için mmap metodunu MAP_FIXED parametresi ile kullanmak gerekir.Aşağıdaki örnekte /dev/mem'in başladığı adresten sonra gelen 0x48000000 offsetinden başlayarak  0x10000 uzunluğundaki hafıza alanı bizim uygulamamıza getiriliyor.
MAP_FIXED ile dikkat edilmesi gereken nokta, verilen adresin page size değerinin tam katı olması.


Bir başka örnekte mmap'e geçilmesi gereken en büyük bellek alanının (2. parametre) kernel içinde ayrıldığı için bir üst sınır olduğu belirtilmiş ve değerinin ne olacağı gösterilmiş.

Memory Mapped Mutex
Aşağıdaki örnekte fork() ile ikiye ayrılan uygulamaların aynı mutex'i kullanması gösterilmiş.

MAP_ANONYMOUS ile file descriptor kullanılmamış. Bu bayrak POSIX standardında tanımlı bir parçası değil!


1 yorum: