memory mapped file etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
memory mapped file etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

29 Haziran 2018 Cuma

mmap ile Memory Mapped File

Giriş
POSIX ile Memory Mapped File işlemi yapmak için temel iki metod mmap() ve munmap()'tir.

mmap metodu
1. Dosya açılır.
int myfd = open("hello.txt", O_RDWR);
2. Bu dosyanın büyüklüğünü alırız.
struct stat mystat = {};
fstat(myfd,&mystat);
3. Büyüklüğü bir değişkene aktarırız.
off_t myfsz = mystat.st_size;
4. Daha sonra dosyayı mmap ile Memory Mapped File haline getiririz.
void*ad = mmap(NULL, myfsz, PROT_READ|PROT_WRITE, MAP_SHARED,myfd, 0);
if (ad == MMAP_FAILED) { perror("mmap"); exit(EXIT_FAILURE); };
Eğer istenirse dosyanın belli bir kısmı belleğe alınabilir.
/* Map the first 1 MB of the file. */
pMap1 = (char *)mmap(0, 1024*1024, PROT_READ, MAP_SHARED, fd, 0);
Örnek
Tam bir örnek için şöyle yaparız.
int fd = open(filename, O_RDONLY); // open file
struct stat fs;
fstat(fd, &fs);

char *buf = (char*)mmap(0, fs.st_size, PROT_READ, MAP_SHARED, fd, 0));

char *buff_end = buf + fs.st_size;

munmap(buf, fs.st_size);

close(fd);
Örnek
Eğer dosya büyüklüğü ile mmap büyüklüğü farklı ise SIGBUS hatası alınır. Elimizde şöyle bir kod olsun. dosya açılırken truncate edildiği için hata alırız.
struct rgn_desc
{
  size_t end_;
  char data[];
};

int main(int argc, const char *argv[])
{
  int fd = open("foo.mm", O_RDWR|O_CREAT|O_TRUNC, (mode_t)0700);

  assert(fd != -1);

  void * ptr = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
                    MAP_SHARED | MAP_POPULATE, fd, 0);

  assert(ptr != (void*) -1);

  rgn_desc * rgn_ptr = (rgn_desc*) ptr;
  rgn_ptr->end_ = 0; // <-- bus error
}

31 Mayıs 2016 Salı

boost iostreams memory mapped device

Memory Mapped File Device Sınıfları
Bu sınıflar stream'in memory mapped bir dosyaya  yazmasını veya okumasını sağlar.

mapped_file Sınıfı- Read ve Write
constructor - string
Şöyle yaparız.
mapped_file mmap("C:\\test.bin", mapped_file::readonly);
const_begin metodu
Şöyle yaparız.
char const * it = mmap.const_begin();
const_data metodu
Şöyle yaparız.
const char* data = mmap.const_data();
const_end metodu
Şöyle yaparız.
char const * endit = mmap.const_end();

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!