Perl 中的 OS 页面对齐分配

Posted

技术标签:

【中文标题】Perl 中的 OS 页面对齐分配【英文标题】:OS Page aligned allocation in Perl 【发布时间】:2018-10-18 16:17:34 【问题描述】:

驱动程序通过 ioctl 接口公开其 API。

ioctl 调用的参数是一个内存缓冲区,它的地址 必须与操作系统页面大小对齐。

例如,C 中的分配会调用 valloc(或 posix_memalign)

像这样简单的 Perl 缓冲区分配:

 $buffer = "\0" x  BUFFER_SIZE ;

还不够,因为很可能是标量的起始地址 不会与操作系统页面大小对齐。

有没有简单的方法来实现这一点?

注意:我将缓冲区转换为 C 地址,如下所示:

 my $c_address = unpack('Q', pack('P', $buffer));

谢谢! 埃亚尔

【问题讨论】:

只要分配BUFFER_SIZE * 2,就可以在缓冲区中找到一页内存。 你也许还可以使用(古老的)Mmap 模块 【参考方案1】:

有多种解决方案,但按照书本,您可以使用IO::AIO 模块,该模块具有IO::AIO::mmap 功能。基本上,你会做这样的事情(未经测试):

    use IO::AIO

    IO::AIO::mmap
          my $buffer, BUFFER_SIZE, IO::AIO::PROT_READ | IO::AIO::PROT_WRITE,
          IO::AIO::MAP_PRIVATE | IO::AIO::MAP_ANONYMOUS, undef
       or die "mmap failure: $!";

$buffer 将在您 undef 或超出范围时自动取消映射,或者您可以使用 IO::AIO::munmap $buffer

您也可以通过调整一些更大的内存分配以其他方式自行完成,但您至少需要查询页面大小,因此如果没有模块的帮助,纯 perl 解决方案无法移植,和/或浪费内存。

【讨论】:

感谢您的回答。 IO::AIO 或 File::Map 或 Sys::Mmap 的 mmap 解决方案很好,当然是首选方式。但是在我的生产环境中,我不能(暂时)将模块添加到 perl 安装(本地编译)中,并且安装中不存在这些模块。所以我想对我来说唯一的方法是分配更多的内存并计算对齐的地址。【参考方案2】:

这是一个不使用 mmap 解决问题的示例。

基本上,代码完成了 posix_memalign() 的工作。

# Required for 'syscall' below
#
require 'syscall.ph';

use strict;
use warnings;

# Linux / unix specific
#
my $PAGE_SIZE = `getconf PAGE_SIZE`;

# Arg = size of requested buffer
#
# return = 1. allocated buffer
#          2. C address of allocated buffer
#          3. Offset for aligned buffer
#
# Code is not portable and tested on x86_64 only.
#
sub valloc

    my ($size, $ALIGN) = @_;

    $ALIGN = $PAGE_SIZE
        unless ($ALIGN);

    my $buffer = "\0" x ($size + $ALIGN - 1);

    my $address = unpack('Q', pack('p', $buffer));
    my $aligned_address = (($address + $ALIGN - 1) & (-$ALIGN));
    my $offset = $aligned_address - $address;

    return ($buffer, $address, $offset);

#-------------------------------------------------------------

# Example to a function that accepts C address
#
sub cat

    my ($path) = @_;

    open (my $fh, '<', $path) || die "$path: $!\n";

    my $size = -s $fh;
    my ($buffer, $address, $offset) = valloc($size);
    syscall(&SYS_read, fileno($fh), $address + $offset, $size);
    close $fh;

    return substr($buffer, $offset, $size);

#-------------------------------------------------------------

my $content = cat(__FILE__);
print $content;

【讨论】:

尚未运行您的脚本,但 getconf 没有在任何地方定义,而且它不是来自 syscall.ph。 另外,这不是 posix memalign 所做的——您的示例将内存过度分配了两倍,而 posix_memalign 没有(在实际实现中)这样做。当然,这在很多情况下都是可以接受的。 这不是两倍,只是页面的额外大小。它是(大小 + 对齐 - 1)。 cat() 函数示例需要 syscall.ph。不是 valloc 实现的一部分。 确实 - 我错误地认为对齐是问题中缓冲区的大小,但事实并非如此。

以上是关于Perl 中的 OS 页面对齐分配的主要内容,如果未能解决你的问题,请参考以下文章

分配粒度和内存页面大小(x86处理器平台的分配粒度是64K,内存页是4K,所以section都是0x1000对齐,硬盘扇区大小是512字节,所以PE文件默认文件对齐是0x200)

我可以在 OS X 10.5 上使用 dtrace 来确定我的哪个 perl 子程序导致的内存分配最多吗?

操作系统页面置换FIFO算法中的Belady现象

操作系统页面置换FIFO算法中的Belady现象

OS中的Belady和抖动现象

OS中的Belady和抖动现象