首页 > 系统相关 >内存管理-41-highatomic预留内存

内存管理-41-highatomic预留内存

时间:2024-11-09 16:21:59浏览次数:1  
标签:highatomic zone pages alloc 41 内存 page 页面

基于msm-5.4

一、相关结构体

1. struct zone

struct zone {
    unsigned long nr_reserved_highatomic;
    ...
};

成员介绍:

nr_reserved_highatomic: 记录为高优先级原子分配预留的内存页面数量。


二、赋值逻辑

赋值路径只有两个,一个是对高阶原子分配进行页面预留,另一个是减少高阶原子页面的预留。

1. 增加预留页面

调用路径:

    __alloc_pages_cpuset_fallback //page_alloc.c
    __alloc_pages_may_oom //page_alloc.c
    __alloc_pages_direct_compact //page_alloc.c
    __alloc_pages_direct_reclaim //page_alloc.c
    __alloc_pages_slowpath //page_alloc.c
    __alloc_pages_nodemask //page_alloc.c
        get_page_from_freelist //page_alloc.c
            reserve_highatomic_pageblock //page_alloc.c
                zone->nr_reserved_highatomic += pageblock_nr_pages;


执行逻辑:

1.1 reserve_highatomic_pageblock()

static void reserve_highatomic_pageblock(struct page *page, struct zone *zone,
        unsigned int alloc_order) //page_block.c
{
    int mt;
    unsigned long max_managed, flags;

    /* 将保留的数量限制为 1 个页面块或大约 1% 的区域。检查容易发生竞争,锁外检查无害 */
    max_managed = (zone_managed_pages(zone) / 100) + pageblock_nr_pages;
    if (zone->nr_reserved_highatomic >= max_managed)
        return;

    spin_lock_irqsave(&zone->lock, flags);

    /* 持有zone->lock后再次检查,上面在锁外进行一次检查可以预防卡锁 */
    if (zone->nr_reserved_highatomic >= max_managed)
        goto out_unlock;

    /*
     * 获取参数page所在页面块的迁移特性,如果不是 HIGHATOMIC、ISOLATE、CMA
     * 三种迁移类型,就将page所在页面块设置为高阶原子类型。
     */
    mt = get_pageblock_migratetype(page);
    if (!is_migrate_highatomic(mt) && !is_migrate_isolate(mt) && !is_migrate_cma(mt)) {
        /* 设置页面块的迁移类型为HIGHATOMIC */
        zone->nr_reserved_highatomic += pageblock_nr_pages;
        set_pageblock_migratetype(page, MIGRATE_HIGHATOMIC);
        /* 将page所在的页面块迁移到 HIGHATOMIC 这个迁移类型对应的freelist链表上 */
        move_freepages_block(zone, page, MIGRATE_HIGHATOMIC, NULL);
    }

out_unlock:
    spin_unlock_irqrestore(&zone->lock, flags);
}


1.2 move_freepages_block()

/* reserve_highatomic_pageblock: (zone, page, MIGRATE_HIGHATOMIC, NULL) */
int move_freepages_block(struct zone *zone, struct page *page,
        int migratetype, int *num_movable) //page_alloc.c
{
    unsigned long start_pfn, end_pfn;
    struct page *start_page, *end_page;

    if (num_movable)
        *num_movable = 0;

    /* page所在页面块的start/end pfn和页面块首page结构指针 */
    start_pfn = page_to_pfn(page);
    start_pfn = start_pfn & ~(pageblock_nr_pages-1);
    start_page = pfn_to_page(start_pfn);
    end_page = start_page + pageblock_nr_pages - 1;
    end_pfn = start_pfn + pageblock_nr_pages - 1;

    /* Do not cross zone boundaries */
    /* 若start_pfn不在zone管理的页面之间,则将start_page指向page(而不是页面块的首个page了) */
    if (!zone_spans_pfn(zone, start_pfn))
        start_page = page;
    /* 若end_pfn不在zone管理的页面之间, 则直接返回 */
    if (!zone_spans_pfn(zone, end_pfn))
        return 0;

    /* 将页面块迁移到迁移类型对应的freelist链表上 */
    return move_freepages(zone, start_page, end_page, migratetype, num_movable);
}


1.3 move_freepages()

/*
 * 翻译: 将range内的空闲页面移动到请求类型的空闲列表中。请注意,start_page 和 end_pages 未在页块边界上对齐。
 * 如果需要对齐,请使用 move_freepages_block()
 */
/* reserve_highatomic_pageblock: (zone, start_page, end_page, MIGRATE_HIGHATOMIC, NULL) */
static int move_freepages(struct zone *zone, struct page *start_page, struct page *end_page,
              int migratetype, int *num_movable) //page_alloc.c
{
    struct page *page;
    unsigned int order;
    int pages_moved = 0;

    for (page = start_page; page <= end_page;) {
        /* 检查区间中的每一个页面是否有对应实际的物理内存,是否是valid的 */
        if (!pfn_valid_within(page_to_pfn(page))) {
            page++;
            continue;
        }

        /* 伙伴系统中的空闲页面这个Buddy标志是设置的 */
        if (!PageBuddy(page)) {
            /*
             * 翻译: 我们假设可以隔离并迁移的页面是可移动的。但我们实际上并没有尝试隔离,因为这样做成本太高。
             * 通过参数 *num_movable 返回的是,不是buddy中的页面,但是moveable状态的页面。
             */
            if (num_movable && (PageLRU(page) || __PageMovable(page)))
                (*num_movable)++;

            page++;
            /* 若page不是伙伴系统中内存块的首个页面,这里就continue进行下一轮循环了 */
            continue;
        }

        /* 下面就是page是伙伴系统中空闲页面块的首个页面的逻辑了 */

        /* 确保我们不会无意中更改节点,断言page和zone必须属于同一个node,嵌入式单node恒成立 */
        VM_BUG_ON_PAGE(page_to_nid(page) != zone_to_nid(zone), page);
        VM_BUG_ON_PAGE(page_zone(page) != zone, page); //断言page必须属于这个zone

        order = page_order(page); //page->private 应该只有buddy中的首个页面的private才表示order
        /* 直接调用的是list_move()从原来链表上del下来再add到新链表上去 */
        move_to_free_area(page, &zone->free_area[order], migratetype);
        page += 1 << order;
        pages_moved += 1 << order;
    }

    /* 返回的是成功迁移的页面数量 */
    return pages_moved;
}


2. 减少预留

调用路径:

    __alloc_pages_slowpath //page_alloc.c
        __alloc_pages_direct_reclaim //page_alloc.c 传参: (ac, false)
    __alloc_pages_slowpath //page_alloc.c
        should_reclaim_retry //page_alloc.c 传参: (ac, true)
            unreserve_highatomic_pageblock
                zone->nr_reserved_highatomic -= min(pageblock_nr_pages, zone->nr_reserved_highatomic);


执行逻辑:

2.1 unreserve_highatomic_pageblock()

/*
 * 翻译: 当内存压力导致分配即将失败时使用。这可能会损害高阶分配在内存压力巨大时的可靠性,
 * 但失败的原子分配应该比 OOM 更容易恢复。
 * 如果 @force 为真,则尝试取消保留页面块,即使高原子页面块已耗尽。
 *
 * should_reclaim_retry:(ac, true) 返回迁移到ac->migratetype类型的空闲链表的页面数
 */
static bool unreserve_highatomic_pageblock(const struct alloc_context *ac, bool force)
{
    struct zonelist *zonelist = ac->zonelist;
    unsigned long flags;
    struct zoneref *z;
    struct zone *zone;
    struct page *page;
    int order;
    bool ret;

    /* 遍历系统中所有的zone */
    for_each_zone_zonelist_nodemask(zone, z, zonelist, ac->high_zoneidx, ac->nodemask) {
        /* 除非内存压力真的很高,否则至少保留一个页块,一个页面块也不给highatomic保留了。 */
        if (!force && zone->nr_reserved_highatomic <= pageblock_nr_pages)
            continue;

        spin_lock_irqsave(&zone->lock, flags); //关键部分主要是这个锁保护
        /* 遍历每一个order的HIGHATOMIC链表 */
        for (order = 0; order < MAX_ORDER; order++) {
            struct free_area *area = &(zone->free_area[order]);

            page = get_page_from_free_area(area, MIGRATE_HIGHATOMIC);
            if (!page)
                continue;

            /*
             * 翻译: 在页面释放路径中,migratetype 更改很活跃,因此尽管我们将页面块的迁移类型
             * 从 highatomic 更改为 ac->migratetype,但我们可以在此循环中计算页面块中的多个空
             * 闲页面。因此我们应该调整一次计数。
             *
             * 这里再次确认查询找到的page是 HIGHATOMIC 迁移类型的。
             */
            if (is_migrate_highatomic_page(page)) {
                zone->nr_reserved_highatomic -= min(pageblock_nr_pages, zone->nr_reserved_highatomic);
            }

            /*
             * 将分配出来的页面设置为ac指定的迁移类型,并移动到对应的freelist链表上,若成功移动
             * 了页面(ret!=0), 则返回成功移动的页面数,然后退出遍历。
             */
            set_pageblock_migratetype(page, ac->migratetype);
            ret = move_freepages_block(zone, page, ac->migratetype, NULL);
            if (ret) {
                spin_unlock_irqrestore(&zone->lock, flags);
                return ret;
            }
        }
        spin_unlock_irqrestore(&zone->lock, flags);
    }

    return false;
}


三、总结

1. 为 highatomic 类型分配的预留页面数量是有限制的,最大不能超过 zone->managed_pages/100+4k 个页面,并且在内存紧张时会从 MIGRATE_HIGHATOMIC 类型的freelist链表中释放出来,但会尽量给保留一个pageblock大小的内存页面给highatomic使用。若内存非常紧张时,则一个页面也不会给highatomic保留了,全部会释放出来。

2. 默认没有对 zone->nr_reserved_highatomic 进行任何调试打印。

3. 代码中涉及到的:
PageBuddy(page) 是Linux内核中用于检查一个页面是否处于空闲状态并在伙伴系统中的函数。
PageLRU(page) 宏在Linux内核中用于检查一个页面是否在LRU(Least Recently Used)链表上。

 

标签:highatomic,zone,pages,alloc,41,内存,page,页面
From: https://www.cnblogs.com/hellokitty2/p/18536919

相关文章

  • SS241109B. tii(tii)
    SS241109B.tii(tii)题意给你一个\(01\)序列,长度为\(n\le5\times10^5\)。给你一个小数\(p\),要你找出一个区间满足区间\(1\)的个数比区间长度和\(p\)最接近,输出区间的左端点,如果有多个区间输出左端点最小的那个。思路设\(s\)是原序列的前缀和数组,翻译一下题面就是求......
  • 2024-2025-1 20241413 《计算机基础与程序设计》第七周学习总结
    这个作业属于哪个课程https://edu.cnblogs.com/campus/besti/2024-2025-1-CFAP这个作业要求在哪里https://www.cnblogs.com/rocedu/p/9577842.html#WEEK07作业目标数组与链表基于数组和基于链表实现数据结构无序表与有序表树图子程序与参数--------作业......
  • 内存映射I/O(MMIO)是一种将硬件设备的控制寄存器和数据寄存器映射到处理器的地址空间中
    内存映射I/O(Memory-MappedI/O,简称MMIO)内存映射I/O(MMIO)是一种将硬件设备的控制寄存器和数据寄存器映射到处理器的地址空间中的技术。在这种方式下,操作系统和程序可以像访问内存一样,通过常规的内存访问指令(如读写)来访问硬件设备,而不需要使用专门的输入/输出指令。它简化了硬件访问......
  • DMA(Direct Memory Access,直接内存存取)是一种允许外设直接与计算机内存进行数据交换的
    DMA(直接内存存取)简介DMA(DirectMemoryAccess,直接内存存取)是一种允许外设直接与计算机内存进行数据交换的技术,绕过了CPU的参与。这种机制的优势在于,它能够显著提高数据传输效率,减轻CPU的负担,从而使得计算机能够处理更多的任务和更高的性能要求。在传统的输入输出(I/O)操作中,数据通......
  • 内存管理-40-_watermark内存水位
    基于msm-5.4模块内调用路径:postcore_initcall//page_alloc.c【】内核初始化init_per_zone_wmark_min//page_alloc.c/proc/sys/vm/extra_free_kbytes//【】sysctl节点配置。/proc/sys/vm/min_free_kbytes//【】sysctl节点配置,会同时更新user_min_free_kbytes。......
  • CN9130-2000-NG-AUS-G,88E6341-A0-NXU2C000,88E1548PA0-BAM2I00,88E1543-A1-LKJ2C000,Marv
    可广泛应用于消费类电子产品中。这些系统控制器具有高度集成的功能,包括处理器、存储器、图形处理器和解码器,可以支持多种应用,如智能电视、游戏机、数字音频播放器等。此外,美满电子的系统控制器还具有低功耗和高性能的特点,能够满足现代消费电子产品对处理能力和电池寿命的要求。......
  • 8章13节:网络图(知识图谱)绘制的深度解析(更新20241109)
    网络图是一种广泛应用于数据分析的可视化工具,能够有效展示事物之间的关系。在医药行业,网络图被用来分析复杂的关系,例如药物与疾病之间的关联、患者与医疗服务的互动等。通过网络图,研究人员和决策者能够直观地理解数据中的结构模式,发现潜在的规律和趋势,进而做出更为精准的判断......
  • 2024-2025-1 20241423 《计算机基础与程序设计》第七周学习总结
    作业信息这个作业属于哪个课程<班级的链接>(如2024-2025-1-计算机基础与程序设计)这个作业要求在哪里2024-2025-1计算机基础与程序设计第七周作业这个作业的目标数组与链表、基于数组和基于链表实现数据结构、无序表与有序表、树、图、子程序与参数作业正文本博......
  • Air780E软件指南:C语言内存数组(zbuff)
    一、ZBUFF(C内存数组)简介zbuff库可以用c风格直接操作(下标从0开始),例如buff[0]=buff[3]可以在sram上或者psram上申请空间,也可以自动申请(如存在psram则在psram进行申请,如不存在或失败则在sram进行申请)。操作里面的元素时,可以根据光标进行增删改查。偏移方式有三种:从头......
  • 动态内存的相关知识点
    今天学了动态内存管理的相关知识点,首先什么是动态内存呢,我的理解是可大可小的,能够动态变化的。1.为什么存在动态内存分配我们已经掌握的内存开辟方式有:intmain(){ inta=10; intarr[10]={0}; intn; scanf("%d",&n); intarr1[n]; return0;}向上面......