[Linux] IO: memory map
memory map(mmap)์ Linux์์ ์ง์ํ๋ ์ปค๋ ์์ค์ ํน์ํ I/O ์ต์ ํ ๊ธฐ๋ฒ ์ค ํ๋๋ค.
๋งค์ฐ ํฐ ๋ฐ์ดํฐ๋ฅผ ๋์คํฌ๋ก๋ถํฐ ์ฝ์ด์ฌ๋ ๋งค์ฐ ์ ์ฉํ๋ค.
์ผ๋ฐ ์ฝ๊ธฐ(fread)์ ์๋ฆฌ
Linux์์ ์ผ๋ฐ์ ์ผ๋ก ํ์ผ Read๋ fread๋ผ๋ ๋ช
๋ น์ ํตํด์ ์ฒ๋ฆฌํ๋ค.
๊ทธ ๊ฒฝ์ฐ์๋ ์๋์ ๊ฐ์ ํ๋ก์ธ์ค๋ค์ ๊ฑฐ์ณ์ ํ์ผ์ ์ฝ๊ณ , ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฌํ๋ค.
์กฐ๊ธ ๋ณต์กํด๋ณด์ด๊ธด ํ๋๋ฐ, ์๋ฌดํผ ์ฌ๊ธฐ์ ์ฑ๋ฅ ๋ถํ๊ฐ ๋ฐ์ํ๋ ์ง์ ์ 2๊ฐ์ง๋ค.
-
DMA๊ฐ ํ์ผ์ ์ฝ์ด์ ์ปค๋ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํ๋ ์๊ฐ
-
ํ๋ก์ธ์๊ฐ ์ปค๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฝ์ด์ ํ๋ก์ธ์ค ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํ๋ ์๊ฐ
mmap์ ์ฌ๊ธฐ์ 2๋จ๊ณ์์ ์๋ชจ๋๋ ์๊ฐ์ ์ค์ผ ์ ์๋ ๋ฐฉ๋ฒ๋ก ์ด๋ค.
mmap์ ์๋ฆฌ
mmap ๊ธฐ๋ฐ์ read๋ ์๋ถ๋ถ์ fread์ ํฌ๊ฒ ๊ณผ์ ์ด ๋ค๋ฅด์ง๋ ์๋ค.
OS๊ฐ DMA์ ์์ฒญํด์ ๋์คํฌ๋ฅผ ์ฝ์ด ์ปค๋ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํ๋ ๊ฒ์ ๊ฐ๋ค.
์ปค๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๋ค์ ๋ณต์ฌํ๋ ๋ถํ์ํ ๋ถํ๊ฐ ์๋ค๋ ๊ฒ์ด ๋ค๋ฅด๋ค.
๋์ ์ปค๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ๋ก์ธ์ค ๋ฉ๋ชจ๋ฆฌ์ ์ง์ ์ฐ๊ฒฐํ๋ค.
mmap์ ์ฅ๋จ์
์ฅ์
-
GB ์์ค์ ๋์ด๊ฐ๋ ํฐ ํ์ผ์ ์ฝ์ ๋ ํจ์ฌ ๋น ๋ฅด๊ฒ ์ฒ๋ฆฌํ ์ ์๋ค.
-
์บ์๊ฐ ๋งค์ฐ ์ ๋จนํ๋ค. ์ด๋ฏธ load๋ ํ์ผ์ ๋ค์ ์ฝ์ผ๋ฉด ๋งค์ฐ ๋น ๋ฅธ ์๋๋ก ์ฝ์ ์ ์๋ค.
๋จ์
-
๊ธฐ๋ณธ์ ์ธ ๋น์ฉ์ด ํฐ ํธ์ด๋ค. ์ ๋นํ ์์ ํ์ผ๋ค์ ์์ฃผ ์ฝ๋ ์ผ๋ฐ์ ์ธ ํจํด์์๋ ์คํ๋ ค ๋๋ฆด ์ ์๋ค.
-
OS ํ์ด์ง ๋จ์๋ก ์ ์ฅ์ ํ๊ธฐ ๋๋ฌธ์ ํ์ผ์ด ์์ ๊ฒฝ์ฐ ๊ณต๊ฐ์ ๋ญ๋น๋ ๋ฐ์ํ๋ค. ์๋ฅผ ๋ค์ด, ํ์ด์ง ๋จ์๊ฐ 4KB์ธ ์์คํ ์์ 50๋ฐ์ดํธ์ง๋ฆฌ ๋ฐ์ดํฐ๋ฅผ ์๋ฆฌ๊ฐ๋ฆฌํ๋๊ฑฐ๋ฉด 3950๋ฐ์ดํธ์ฏค์ ๊ทธ๋ฅ ๋ญ๋นํ๋ ๊ฒ์ด๋ค.
๋ฒค์น๋งํนํด๋ณด๊ธฐ
๋ง๋ก๋ง ๋ ๋๋๊ฑด ์๋ฏธ๊ฐ ์์ผ๋ ์ง์ ๋๋ฆฌ๋ฉด์ ์ฑ๋ฅ ํ
์คํธ๋ฅผ ํด๋ณด์.
์์ ๋ ๋ ๊ฒ์ ๋ง์ ๋๋ผ๊ธฐ ์ํด์ C๋ฅผ ์ฌ์ฉํ๋ค.
https://github.com/myyrakle/benchmarks/tree/master/fread_vs_mmap
๋จผ์ ํฐ ํ์ผ๋ถํฐ ํ ์คํธํด๋ณด์. ๋ 17GB์ง๋ฆฌ ํฐ ํ ์คํธํ์ผ์ ์ค๋นํ๋ค.

fread ๋จผ์ ์ง๋ดค๋ค.
๊ทธ๋ฅ ์ ์ฒด ๋ค ์ฝ๊ธฐ๋ง ํ๊ณ , ์๊ฐ์ ์ธก์ ํ๋ค.
์๋๋ ์ ์ฒด ์ฝ๋๋ค.
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE *file = fopen("measurements.txt", "r");
// ํ์ผ ํฌ๊ธฐ๋ฅผ ์ป์ต๋๋ค.
fseek(file, 0, SEEK_END);
long filesize = ftell(file);
rewind(file);
// ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋นํฉ๋๋ค.
char *buffer = (char *)malloc(filesize);
clock_t start = clock();
// ํ์ผ์ ๋ด์ฉ์ ์ฝ์ด์ต๋๋ค.
size_t readsize = fread(buffer, 1, filesize, file);
if (readsize != filesize)
{
printf("Failed to read file\n");
return 1;
}
// NULL ์ข
๋ฃ ๋ฌธ์๋ฅผ ์ถ๊ฐํฉ๋๋ค.
buffer[filesize] = '\0';
fclose(file);
clock_t end = clock();
printf("Len %ld\n", strlen(buffer));
double cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
printf("Execution time: %f seconds\n", cpu_time_used);
return 0;
}
๊ทธ๋ฆฌ๊ณ ๋๋ ค๋ณด๋ฉด
10์ด ์ฆ์์ด ๊ฑธ๋ ธ๋ค.
๊ทธ๋ผ mmap์ ์ ์ฉํ๋ฉด ์ด๋จ๊น?
ํ์ผ ๋์คํฌ๋ฆฝํฐ๋ฅผ ์ด๊ณ mmap ํจ์๋ฅผ ์ฌ์ฉํด์ mmap ์ด๊ธฐํ๋ฅผ ํด์ฃผ๋ฉด ๋ฐ๋ก ์ฝ์ด์จ๋ค.
์ด๊ฑด lazyํ๊ฒ ์ฝ์ด์ฌ ์ ์๊ธฐ ๋๋ฌธ์ ์ฑ๋ฅ ์ธก์ ์ ์ํด ์๋์ ์ผ๋ก ๊ฐ์ฅ ๋ง์ง๋ง ๊ธ์๋ฅผ ์ถ๋ ฅํ๋๋ก ํ๋ค.
์๋๋ ์ ์ฒด ์ฝ๋๋ค.
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
// ํ์ผ ํฌ๊ธฐ๋ฅผ ์ป์ต๋๋ค.
FILE *file = fopen("measurements.txt", "r");
fseek(file, 0, SEEK_END);
long filesize = ftell(file);
rewind(file);
clock_t start = clock();
int file_descriptor = open("measurements.txt", O_RDONLY);
if (file_descriptor == -1)
{
perror("Error opening file for reading");
exit(EXIT_FAILURE);
}
char *buffer = mmap(0, filesize, PROT_READ, MAP_SHARED, file_descriptor, 0);
if (buffer == MAP_FAILED)
{
close(file_descriptor);
perror("Error mmapping the file");
exit(EXIT_FAILURE);
}
printf("Len %ld\n", strlen(buffer));
printf("Last Character %c\n", buffer[filesize - 1]);
clock_t end = clock();
double cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
printf("Execution time: %f seconds\n", cpu_time_used);
return 0;
}
๊ทธ๋ฆฌ๊ณ ๋๋ ค๋ณด๋ฉด
๋์ ๋๊ฒ ์ฑ๋ฅ์ด ํฅ์๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
์ต์ด ํธ์ถ์์๋ 5์ด๊ฐ ์๊ฑธ๋ ธ๊ณ , ์ดํ์๋ ์บ์๋ฅผ ํ์ 2์ด๋ ๊ฑธ๋ฆฌ์ง ์์๋ค.
๊ทธ๋ผ ์์ ํ์ผ์ ๋ค๋ฃฐ ๋๋ ์ด๋จ๊น?
์ข ์ ๋นํ ์์ ํ
์คํธ ๋ฐ์ดํฐ๋ฅผ ์ค๋นํด์ ๋ฐ๋ณต์ ๋๋ ค๋ดค๋ค.

๋จผ์ fread๋ 5000๋ฒ ์ ๋๋ง ๋ฐ๋ณต์ ๋๋ ค๋ดค๋ค.

fread๋ 0.15์ด ์ ๋๊ฐ ๊ฑธ๋ ธ๋ค. ๋ฌด๋ํ๋ค.

mmap๋ ๋น์ทํ๊ฒ 0.15์ด ์ ๋๊ฐ ๊ฑธ๋ ธ๋ค.
ํ๋ฒํ ๋ ๋ฒจ์์๋ ์ฑ๋ฅ์ฐจ๊ฐ ๊ฑฐ์ ๋์ง ์๋๋ค.
์ด๋ฒ์๋ ๋จ์๋ฅผ ์ข๋ ์ฌ๋ ค๋ดค๋ค.

์ด๋ฌ๋ฉด ์ด์ ์กฐ๊ธ์ฉ fread๊ฐ ๋ ๋นจ๋ผ์ง๊ธฐ ์์ํ๋ค. ํ์ผ์ด ์๊ณ , ์ฝ๊ธฐ๊ฐ ๋น๋ฒํ ์๋ก ๊ฒฉ์ฐจ๋ ๋ ๋ฒ์ด์ง๋ค.
๊ทธ๋์ ์ผ๋ฐ์ ์ธ usecase์์๋ ๊ตณ์ด mmap์ ์ฐ์ ์ ์ผ๋ก ๊ณ ๋ คํ ํ์๋ ์๋ค.
์ฐธ์กฐ
https://coder-in-war.tistory.com/entry/Linux-Kernel-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EB%A7%B5-%ED%8C%8C%EC%9D%BCmmap
https://www.researchgate.net/post/What_is_the_actual_difference_between_fread_and_mmap_functions_in_linux_unix
https://wallmusings.in/2020/03/20/fread-vs-mmap/
https://wallmusings.in/2020/03/05/when-not-to-use-mmaps/