- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我想将物理内存写入文件。内存本身不会再被触及,因此我想使用 O_DIRECT
来获得最佳的写入性能。
我的第一个想法是打开 /dev/mem
并映射内存并将所有内容写入一个文件,该文件使用 O_DIRECT
打开。对 mmap 返回的内存地址的写入调用失败 (EFAULT
)。如果我不使用 O_DIRECT
,它会生成一个 memcpy
。
#include <cstdint>
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <malloc.h>
#include <sys/mman.h>
#define PRINT_ERRNO_REASON(reason) \
case reason: { std::cout << #reason << std::endl; } break;
void write_page_aligned_buffer(int out_fd)
{
const ssize_t PAGE_SIZE = getpagesize();
void* page_aligned_buffer = memalign(PAGE_SIZE, PAGE_SIZE);
if(!page_aligned_buffer)
{
std::cout << "Could not allocate page aligned buffer." << std::endl;
return;
}
std::cout << "Allocated a buffer at address " << page_aligned_buffer << "." << std::endl;
if(write(out_fd, page_aligned_buffer, PAGE_SIZE) < 0)
{
std::cout << "Could not write page-aligned user buffer to tmp-file. Quitting..." << std::endl;
std::cout << "Reason of fail is ";
switch(errno)
{
PRINT_ERRNO_REASON(EAGAIN);
PRINT_ERRNO_REASON(EBADF);
PRINT_ERRNO_REASON(EFAULT);
PRINT_ERRNO_REASON(EFBIG);
PRINT_ERRNO_REASON(EINTR);
PRINT_ERRNO_REASON(EINVAL);
PRINT_ERRNO_REASON(EIO);
PRINT_ERRNO_REASON(ENOSPC);
PRINT_ERRNO_REASON(EPIPE);
default:
std::cout << "Unknown" << std::endl;
}
}
else
{
std::cout << "Successfully written user-page-aligned buffer." << std::endl;
}
free(page_aligned_buffer);
}
int main()
{
const ssize_t PAGE_SIZE = getpagesize();
// number of pages to copy
const uint32_t PAGES_TO_COPY = 1;
char* tmp_file_name = 0;
int tmp_file_fd = -1;
ssize_t bytes_copied = 0;
std::cout << "Copying " << PAGES_TO_COPY << " pages with PAGE_SIZE = " << PAGE_SIZE << std::endl;
std::cout << "Copying " << PAGES_TO_COPY * PAGE_SIZE / 1024 << " kBytes." << std::endl << std::endl;
uid_t user_id = geteuid();
if(user_id)
{
std::cout << "We need to be root. I am euid == " << user_id << ". Quitting..." << std::endl;
return 0;
}
else
{
seteuid(0);
setuid(0);
}
// get the file descriptor
int mem_fd = open("/dev/mem", O_RDONLY);
if(mem_fd < 0)
{
std::cout << "Could not open /dev/mem. Quitting..." << std::endl;
std::cout << "Reason of fail is ";
switch(errno)
{
PRINT_ERRNO_REASON(EACCES);
PRINT_ERRNO_REASON(EEXIST);
PRINT_ERRNO_REASON(EINTR);
PRINT_ERRNO_REASON(EINVAL);
PRINT_ERRNO_REASON(EIO);
PRINT_ERRNO_REASON(EISDIR);
PRINT_ERRNO_REASON(ELOOP);
PRINT_ERRNO_REASON(EMFILE);
PRINT_ERRNO_REASON(ENFILE);
PRINT_ERRNO_REASON(ENOENT);
PRINT_ERRNO_REASON(ENOSR);
PRINT_ERRNO_REASON(ENOSPC);
PRINT_ERRNO_REASON(ENOTDIR);
PRINT_ERRNO_REASON(ENXIO);
PRINT_ERRNO_REASON(EOVERFLOW);
PRINT_ERRNO_REASON(EROFS);
PRINT_ERRNO_REASON(EAGAIN);
PRINT_ERRNO_REASON(ENAMETOOLONG);
PRINT_ERRNO_REASON(ENOMEM);
PRINT_ERRNO_REASON(ETXTBSY);
default:
std::cout << "Unknown" << std::endl;
}
return 0;
}
// get read pointer
uint8_t* mem_ptr = static_cast<uint8_t*>(mmap(0,
PAGE_SIZE,
PROT_READ,
MAP_SHARED,
mem_fd,
PAGE_SIZE));
if(mem_ptr == MAP_FAILED)
{
std::cout << "Could not mmap /dev/mem. Quitting..." << std::endl;
std::cout << "Reason of fail is ";
switch(errno)
{
PRINT_ERRNO_REASON(EACCES);
PRINT_ERRNO_REASON(EAGAIN);
PRINT_ERRNO_REASON(EBADF);
PRINT_ERRNO_REASON(EINVAL);
PRINT_ERRNO_REASON(ENFILE);
PRINT_ERRNO_REASON(ENODEV);
PRINT_ERRNO_REASON(ENOMEM);
PRINT_ERRNO_REASON(EPERM);
PRINT_ERRNO_REASON(ETXTBSY);
default:
std::cout << "Unknown" << std::endl;
}
goto CLEANUP_FD_DEV_MEM;
}
tmp_file_name = tempnam("/tmp", "prefix");
if(!tmp_file_name)
{
std::cout << "Could not get a free tmp-filename";
goto CLEANUP_MMAP_DEV_MEM;
}
// if O_DIRECT is omitted the example will work
tmp_file_fd = open(tmp_file_name,
O_WRONLY | O_CREAT | O_DIRECT | O_TRUNC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if(tmp_file_fd < 0)
{
std::cout << "Could not create tmp file with O_DIRECT." << std::endl;
goto CLEANUP_MMAP_DEV_MEM;
}
write_page_aligned_buffer(tmp_file_fd);
// everything worked so lets start the copying
for(uint i = 0; i < PAGES_TO_COPY; i++)
{
// check memory
// snip
for(int i = 0; i < PAGE_SIZE; i += 32)
{
printf("%02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X %02X%02X%02X%02X\n",
mem_ptr[i + 0], mem_ptr[i + 1], mem_ptr[i + 2], mem_ptr[i + 3],
mem_ptr[i + 4], mem_ptr[i + 5], mem_ptr[i + 6], mem_ptr[i + 7],
mem_ptr[i + 8], mem_ptr[i + 9], mem_ptr[i + 10], mem_ptr[i + 11],
mem_ptr[i + 12], mem_ptr[i + 13], mem_ptr[i + 14], mem_ptr[i + 15],
mem_ptr[i + 16], mem_ptr[i + 17], mem_ptr[i + 18], mem_ptr[i + 19],
mem_ptr[i + 20], mem_ptr[i + 21], mem_ptr[i + 22], mem_ptr[i + 23],
mem_ptr[i + 24], mem_ptr[i + 25], mem_ptr[i + 26], mem_ptr[i + 27],
mem_ptr[i + 28], mem_ptr[i + 29], mem_ptr[i + 30], mem_ptr[i + 31]);
}
std::cout << "\n";
// endsnip
bytes_copied = write(tmp_file_fd, mem_ptr, PAGE_SIZE);
if(bytes_copied < 0)
{
std::cout << "Could not write to tmp-file. Quitting..." << std::endl;
std::cout << "Reason of fail is ";
switch(errno)
{
PRINT_ERRNO_REASON(EAGAIN);
PRINT_ERRNO_REASON(EBADF);
PRINT_ERRNO_REASON(EFAULT);
PRINT_ERRNO_REASON(EFBIG);
PRINT_ERRNO_REASON(EINTR);
PRINT_ERRNO_REASON(EINVAL);
PRINT_ERRNO_REASON(EIO);
PRINT_ERRNO_REASON(ENOSPC);
PRINT_ERRNO_REASON(EPIPE);
default:
std::cout << "Unknown" << std::endl;
}
goto CLEANUP_FD_TMP_FILE;
}
}
CLEANUP_FD_TMP_FILE:
if(tmp_file_name)
{
if(close(tmp_file_fd))
{
std::cout << "Could close tmp-file " << tmp_file_name << "." << std::endl;
}
if(remove(tmp_file_name))
{
std::cout << "Could remove tmp-file " << tmp_file_name << "." << std::endl;
}
free(tmp_file_name);
}
CLEANUP_MMAP_DEV_MEM:
if(munmap(mem_ptr, PAGE_SIZE))
{
std::cout << "munmap failed." << std::endl;
}
CLEANUP_FD_DEV_MEM:
if(close(mem_fd))
{
std::cout << "Could not close /dev/mem filedescriptor." << std::endl;
}
return 0;
}
下一步是编写处理内存传输的字符设备或 block 设备。但是如何绕过copy_to_user呢?目标系统是一个嵌入式 PowerPC 架构,缺点是将用户内存写入硬盘(使用 DMA Controller )比从 RAM 到 RAM 的 memcpy 更快。因此我必须绕过页面缓存。
最好的问候
弗里德里希
最佳答案
你的问题看起来有点奇怪。由于您的编程非常接近硬件,因此您可以考虑使用直接内存访问 (DMA)。这可能有点棘手,因为您需要了解分页和部分 I/O 机制。您可能想阅读:
http://www.linuxjournal.com/article/7104
(这只是为了理解这个想法的介绍。)
关于linux - 如何使用 O_DIRECT 将内核空间内存(物理地址)写入文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6439082/
我正在运行一个支持 O_DIRECT 的 IO 密集型进程。有没有办法判断进程运行时是否使用了 O_DIRECT? 我尝试了“iostat -x 1”,但不确定哪个字段对我有帮助。 谢谢。 最佳答案
如果我用 O_DIRECT 打开文件标志,这是否意味着每当对该文件的写入(阻塞模式)返回时,数据都在磁盘上? 最佳答案 (此答案适用于 Linux - 其他操作系统可能有不同的警告/语义) 让我们从子
Apple LLVM 版本 10.0.0 (clang-1000.10.44.4) 目标:x86_64-apple-darwin18.0.0 #include #include #include
你能告诉我下面的代码有什么问题吗?由于某种原因,编译器拒绝识别 O_DIRECT 标志。 #define _GNU_SOURCE #include #include #include #incl
董事会介绍: 我正在开发一 block 带有 ST40 芯片的电路板,主要用于捕获 DVB 流并将其显示在电视上。该板在 Linux 操作系统上运行。 问题描述: 我正在尝试使用 O_DIRECT 标
open(2) 的手册页仅建议 O_DIRECT 绕过页面缓存,但网络上的许多描述将其描述为导致用户缓冲区直接通过 DMA 访问驱动器。如果是这种情况,我想它也会绕过文件系统(例如 xfs、ext4
我正在用 C 为 Linux 2.6.X 内核编写自定义数据库引擎,我需要知道对于使用 O_DIRECT 标志打开的文件的 write() 系统调用的最小写入大小是多少?在文档中说,自 linux 2
我想知道进程是否使用 O_DIRECT 打开了任何文件,但我只能在进程启动后检查它(即 strace 不是一个选项)。我试着查看/proc/$pid/fd/看看是否有任何有用的东西,但没有。我的目标是
使用 POSIX 异步 I/O 时,使用 O_DIRECT 和 AIO_RAW 有什么区别吗?或者我应该/我可以同时使用两者吗?我们正在开发 NoSQL 数据库服务器,并正在寻找使异步 I/O 在 P
我正在为 Linux 开发一个数据库引擎,我对通过对内核的一次系统调用写入多个 block 的一致性有疑问。我用 O_DIRECT 打开设备。 设备以 block 为单位写入数据,具体取决于硬件,它可
我有一个 C++ 程序,它使用 POSIX API 编写一个用 O_DIRECT 打开的文件。同时,另一个线程正在通过不同的文件描述符从同一个文件中读回。我注意到偶尔从文件中读回的数据包含全零,而不是
有一句著名的 Linus 名言,说 O_DIRECT 是无用的,甚至是 hell 。 如果一个人对速度有超强的需求,那么在 Linux 中真的没有合理使用这个标志来处理常规文件的场景吗? 编辑:日志文
假设我有一个执行以下操作的简单程序: fdWrite = open("file", O_WRONLY); fdRead = open("file", O_RDONLY | O_DIRECT); wri
我们想尽最大努力避免断电时数据丢失。所以我决定使用 O_DIRECT 标志打开一个文件将数据写入磁盘。 O_DIRECT 是否意味着数据完全绕过操作系统缓存?如果请求成功返回应用程序,是否意味着数据一
我正在尝试编写一个需要非常快速地写入磁盘的应用程序。我已经达到写入磁盘的性能目标,这很棒。 但是,我注意到如此快速地写入磁盘会占用大量 CPU 时间:一个内核已用尽,另一个内核已达到 80%,另外两个
据我了解,当您映射文件时,您基本上是将该文件的页面缓存中的页面直接映射到您的进程中,而当您使用 O_DIRECT 时,您将绕过页面缓存。将两者一起使用是否有意义?如果我的理解是正确的,它甚至会如何工作
我正在四处寻找以解决我们的数据库速度问题。 当我尝试使用时: innodb_flush_method=O_DIRECT 在我的 my.ini 文件中,MySQL 服务无法启动。我在 Google 上找
以下代码在缓冲区在堆栈上时失败,但在堆上分配时成功。我使用 Raid 驱动器在 RHEL 5.3 上对其进行了测试。是否可以将 O_DIRECT 与堆栈缓冲区一起使用? #define _GNU_SO
在 Linux 上(Linux 3.16.0-38-generic#52~14.04.1-Ubuntu x86_64 GNU/Linux),当尝试使用 O_DIRECT 通过直接 io 写入文件时 f
我遇到了 LVM 和我正在处理的磁盘驱动程序的竞争条件。看起来 vgcreate 和 lvcreate 之类的东西在 O_DIRECT 模式下执行它们的 IO。我在使用 -vvv 运行这些命令时发现了
我是一名优秀的程序员,十分优秀!