Linux - 3.14.12 메모리 관리 노트 [파트너 관리 알고리즘 (1)]
build_all_zonelists () 는 메모리 분배 기 에 사용 되 는 저장 노드 의 관리 구역 링크 를 초기 화 하 는 데 사용 되 며 메모리 관리 알고리즘 (파트너 관리 알고리즘) 을 위 한 준비 작업 입 니 다.구체 적 인 실현:
【file:/mm/page_alloc.c】
/*
* Called with zonelists_mutex held always
* unless system_state == SYSTEM_BOOTING.
*/
void __ref build_all_zonelists(pg_data_t *pgdat, struct zone *zone)
{
set_zonelist_order();
if (system_state == SYSTEM_BOOTING) {
__build_all_zonelists(NULL);
mminit_verify_zonelist();
cpuset_init_current_mems_allowed();
} else {
#ifdef CONFIG_MEMORY_HOTPLUG
if (zone)
setup_zone_pageset(zone);
#endif
/* we have to stop all cpus to guarantee there is no user
of zonelist */
stop_machine(__build_all_zonelists, pgdat, NULL);
/* cpuset refresh routine should be here */
}
vm_total_pages = nr_free_pagecache_pages();
/*
* Disable grouping by mobility if the number of pages in the
* system is too low to allow the mechanism to work. It would be
* more accurate, but expensive to check per-zone. This check is
* made on memory-hotadd so a system can start with mobility
* disabled and enable it later
*/
if (vm_total_pages < (pageblock_nr_pages * MIGRATE_TYPES))
page_group_by_mobility_disabled = 1;
else
page_group_by_mobility_disabled = 0;
printk("Built %i zonelists in %s order, mobility grouping %s. "
"Total pages: %ld
",
nr_online_nodes,
zonelist_order_name[current_zonelist_order],
page_group_by_mobility_disabled ? "off" : "on",
vm_total_pages);
#ifdef CONFIG_NUMA
printk("Policy zone: %s
", zone_names[policy_zone]);
#endif
}
먼저 setzonelist_order():
【file:/mm/page_alloc.c】
static void set_zonelist_order(void)
{
current_zonelist_order = ZONELIST_ORDER_ZONE;
}
이 곳 은 zonelist 의 순 서 를 설정 하 는 데 사 용 됩 니 다. ZONELISTORDER_ZONE 은 순서 (- zonetype, [node] distance) 를 나타 내 는 데 사용 되 며, ZONELIST 도 있다.ORDER_NODE 는 순서 ([node] distance, - zonetype) 를 표시 합 니 다.그러나 NUMA 환경 에 만 차이 가 있 고 비 NUMA 환경 은 차이 가 없다.
시스템 상태 systemstate 는 SYSTEMBOOTING, 시스템 상 태 는 startkernel 마지막 함수 rest 까지 실행init 이후 에 야 SYSTEMRUNNING, 그래서 초기 화 할 때 다음build_all_zonelists () 함수:
【file:/mm/page_alloc.c】
/* return values int ....just for stop_machine() */
static int __build_all_zonelists(void *data)
{
int nid;
int cpu;
pg_data_t *self = data;
#ifdef CONFIG_NUMA
memset(node_load, 0, sizeof(node_load));
#endif
if (self && !node_online(self->node_id)) {
build_zonelists(self);
build_zonelist_cache(self);
}
for_each_online_node(nid) {
pg_data_t *pgdat = NODE_DATA(nid);
build_zonelists(pgdat);
build_zonelist_cache(pgdat);
}
/*
* Initialize the boot_pagesets that are going to be used
* for bootstrapping processors. The real pagesets for
* each zone will be allocated later when the per cpu
* allocator is available.
*
* boot_pagesets are used also for bootstrapping offline
* cpus if the system is already booted because the pagesets
* are needed to initialize allocators on a specific cpu too.
* F.e. the percpu allocator needs the page allocator which
* needs the percpu allocator in order to allocate its pagesets
* (a chicken-egg dilemma).
*/
for_each_possible_cpu(cpu) {
setup_pageset(&per_cpu(boot_pageset, cpu), 0);
#ifdef CONFIG_HAVE_MEMORYLESS_NODES
/*
* We now know the "local memory node" for each node--
* i.e., the node of the first zone in the generic zonelist.
* Set up numa_mem percpu variable for on-line cpus. During
* boot, only the boot cpu should be on-line; we'll init the
* secondary cpus' numa_mem as they come on-line. During
* node/memory hotplug, we'll fixup all on-line cpus.
*/
if (cpu_online(cpu))
set_cpu_numa_mem(cpu, local_memory_node(cpu_to_node(cpu)));
#endif
}
return 0;
}
그 중 buildzonelists_node () 함수 구현:
【file:/mm/page_alloc.c】
/*
* Builds allocation fallback zone lists.
*
* Add all populated zones of a node to the zonelist.
*/
static int build_zonelists_node(pg_data_t *pgdat, struct zonelist *zonelist,
int nr_zones)
{
struct zone *zone;
enum zone_type zone_type = MAX_NR_ZONES;
do {
zone_type--;
zone = pgdat->node_zones + zone_type;
if (populated_zone(zone)) {
zoneref_set_zone(zone,
&zonelist->_zonerefs[nr_zones++]);
check_highest_zone(zone_type);
}
} while (zone_type);
return nr_zones;
}
populated_zone () 관리 구역 zone 을 판단 하 는 presentpages 구성원 이 0 인지, 0 이 아니라면 이 관리 구역 에 페이지 가 존재 한 다 는 뜻 이 며, zoneref 를 통 해set_zone () 이 를 zonelist 에 설정 한zonerefs 안, checkhighest_zone () 은 NUMA 를 열지 않 은 상태 에서 빈 함수 입 니 다.buildzonelists_node () 는 사실 ZONEHIGHMEM—>ZONE_NORMAL—>ZONE_DMA 의 순 서 를 반복 해서zonerefs 에 서 는 메모 리 를 신청 하 는 대가 가 저렴 한 것 에서 비 싼 것 으로 나 타 났 습 니 다. 이것 은 메모 리 를 분배 할 때의 예비 순서 입 니 다.
build 로 돌아 가기zonelists () 함수 에서 코드 는 로 컬 메모리 관리 구역 을 분배 예비 순서 로 정렬 하 는 것 을 보 여 줍 니 다. 그 다음 에 분배 메모리 대가 가 로 컬 보다 낮 고 마지막 에 분배 메모리 대가 가 로 컬 보다 높 습 니 다.
build 분석 완료zonelists (), 다시 돌아 가기build_all_zonelists () buildzonelist_cache():
【file:/mm/page_alloc.c】
/* non-NUMA variant of zonelist performance cache - just NULL zlcache_ptr */
static void build_zonelist_cache(pg_data_t *pgdat)
{
pgdat->node_zonelists[0].zlcache_ptr = NULL;
}
이 함수 와 CONFIGNUMA 관련, zlcache 관련 멤버 를 설정 합 니 다.이 설정 을 열지 않 았 기 때문에 NULL 로 직접 설정 합 니 다.
build 기반all_zonelists () 호출build_all_zonelists () 입 참 은 NULL 로 알 수 있 습 니 다build_all_zonelists () 가 실행 하 는 코드 는:
for_each_online_node(nid) {
pg_data_t *pgdat = NODE_DATA(nid);
build_zonelists(pgdat);
build_zonelist_cache(pgdat);
}
주로 각 메모리 관리 노드 node 에 있 는 각자 의 메모리 관리 구역 zone 의 메모리 분배 순 서 를 설정 합 니 다.
__build_all_zonelists () 다음은:
for_each_possible_cpu(cpu) {
setup_pageset(&per_cpu(boot_pageset, cpu), 0);
#ifdef CONFIG_HAVE_MEMORYLESS_NODES
if (cpu_online(cpu))
set_cpu_numa_mem(cpu, local_memory_node(cpu_to_node(cpu)));
#endif
}
그 중 CONFIGHAVE_MEMORYLESS_NODES 가 설정 되 지 않 았 습 니 다. 주로 setup 을 분석 합 니 다.pageset():
【file:/mm/page_alloc.c】
static void setup_pageset(struct per_cpu_pageset *p, unsigned long batch)
{
pageset_init(p);
pageset_set_batch(p, batch);
}
setup_pageset () 에서 호출 된 두 함수 가 비교적 간단 하 니 바로 넘 어 갑 니 다.먼저:
【file:/mm/page_alloc.c】
static void pageset_init(struct per_cpu_pageset *p)
{
struct per_cpu_pages *pcp;
int migratetype;
memset(p, 0, sizeof(*p));
pcp = &p->pcp;
pcp->count = 0;
for (migratetype = 0; migratetype < MIGRATE_PCPTYPES; migratetype++)
INIT_LIST_HEAD(&pcp->lists[migratetype]);
}
pageset_init () 는 주로 struct percpu_pageset 구조 체 는 초기 화 되 고 pagesetset_batch () 는 설정 합 니 다.pageset_set_batch () 구현:
【file:/mm/page_alloc.c】
/*
* pcp->high and pcp->batch values are related and dependent on one another:
* ->batch must never be higher then ->high.
* The following function updates them in a safe manner without read side
* locking.
*
* Any new users of pcp->batch and pcp->high should ensure they can cope with
* those fields changing asynchronously (acording the the above rule).
*
* mutex_is_locked(&pcp_batch_high_lock) required when calling this function
* outside of boot time (or some other assurance that no concurrent updaters
* exist).
*/
static void pageset_update(struct per_cpu_pages *pcp, unsigned long high,
unsigned long batch)
{
/* start with a fail safe value for batch */
pcp->batch = 1;
smp_wmb();
/* Update high, then batch, in order */
pcp->high = high;
smp_wmb();
pcp->batch = batch;
}
/* a companion to pageset_set_high() */
static void pageset_set_batch(struct per_cpu_pageset *p, unsigned long batch)
{
pageset_update(&p->pcp, 6 * batch, max(1UL, 1 * batch));
}
setup_pageset () 함수 입 참 p 는 struct per 입 니 다.cpu_pageset 구조 체 의 지침, percpu_pageset 구 조 는 커 널 의 각 zone 이 모든 CPU 의 페이지 캐 시 관리 구조 에 사용 되 는 것 입 니 다.이 캐 시 는 로 컬 CPU 가 보 내 는 단일 메모리 요청 을 충족 시 키 기 위해 미리 분 배 된 페이지 를 포함 하고 있 습 니 다.and struct 타격 percpu_페이지 가 정의 하 는 pcp 는 이 관리 구조의 구성원 으로 구체 적 인 페이지 관리 에 사용 된다.원래 모든 관리 구 조 는 두 개의 pcp 배열 구성원 이 있 었 는데 그 안의 두 대기 열 은 각각 냉 페이지 와 열 페이지 관리 에 사용 되 었 으 며 현재 분석 한 3.14.12 버 전 은 두 가 지 를 합 쳐 냉 열 페이지 를 통일 적 으로 관리 하고 열 페이지 는 대기 열 앞 에 있 으 며 냉 페이지 는 대기 열 뒤에 있 습 니 다.일단 이렇게 많이 기억 하고 나중에 버디 알고리즘 을 사용 할 때 상세 하 게 분석 하 겠 습 니 다.
* * 이로써 알 수 있 습 니 다build_all_zonelists () 는 메모리 관리 프레임 워 크 가 후속 메모리 페이지 관리 알고리즘 을 준비 하고 메모리 관리 구역 zone 의 배분 순 서 를 배정 하 는 동시에 냉 열 페이지 관 리 를 초기 화 합 니 다. * *
마지막 build 로 돌아 가기all_zonelists () 함수.메모리 가 열 리 지 않 아 디 버 깅 기능 초기 화 CONFIGDEBUG_MEMORY_INIT,mminit_verify_zonelist () 는 빈 함수 입 니 다.
CONFIG 기반CPUSETS 설정 항목 이 열 린 상태 에서 cpusetinit_current_mems_allowed () 는 다음 과 같이 실현 합 니 다.
【file:/kernel/cpuset.c】
void cpuset_init_current_mems_allowed(void)
{
nodes_setall(current->mems_allowed);
}
이 안의 current 는 cpuset 의 데이터 구조 로 cgroup 의 작업 에 사용 할 수 있 는 cpu 와 메모리 노드 를 관리 합 니 다.멤버 memsallowed, 이 멤버 는 nodemaskt 유형의 구조 체
【file:/include/linux/nodemask.h】
typedef struct { DECLARE_BITMAP(bits, MAX_NUMNODES); } nodemask_t;
이 구 조 는 사실 하나의 비트 필드 를 정의 하 는 것 입 니 다. 각 비트 는 하나의 메모리 노드 에 대응 하고 1 을 설치 하면 이 노드 의 메모리 가 사용 가능 하 다 는 것 을 표시 합 니 다.반면 nodessetall 은 이 필드 의 모든 위 치 를 1 로 설정 합 니 다.
마지막 으로 buildall_zonelists () 내 nrfree_pagecache_pages () 의 실현:
【file:/mm/page_alloc.c】
/**
* nr_free_pagecache_pages - count number of pages beyond high watermark
*
* nr_free_pagecache_pages() counts the number of pages which are beyond the
* high watermark within all zones.
*/
unsigned long nr_free_pagecache_pages(void)
{
return nr_free_zone_pages(gfp_zone(GFP_HIGHUSER_MOVABLE));
}
안에서 호출 된 nrfree_zone_pages () 구현:
【file:/mm/page_alloc.c】
/**
* nr_free_zone_pages - count number of pages beyond high watermark
* @offset: The zone index of the highest zone
*
* nr_free_zone_pages() counts the number of counts pages which are beyond the
* high watermark within all zones at or below a given zone index. For each
* zone, the number of pages is calculated as:
* managed_pages - high_pages
*/
static unsigned long nr_free_zone_pages(int offset)
{
struct zoneref *z;
struct zone *zone;
/* Just pick one node, since fallback list is circular */
unsigned long sum = 0;
struct zonelist *zonelist = node_zonelist(numa_node_id(), GFP_KERNEL);
for_each_zone_zonelist(zone, z, zonelist, offset) {
unsigned long size = zone->managed_pages;
unsigned long high = high_wmark_pages(zone);
if (size > high)
sum += size - high;
}
return sum;
}
nrfree_zone_pages () 는 모든 메모리 관리 구역 을 옮 겨 다 니 며 각 관리 구역 의 메모리 공간 을 구 합 니 다. 실질 적 으로 모든 관리 구역 이 분배 할 수 있 는 메모리 페이지 수 를 통계 하 는 데 사 용 됩 니 다.
이어서 buildall_zonelists () 뒤 에는 현재 시스템 의 메모리 페이지 상자 수 를 판단 하여 유동 그룹 메커니즘 (Mobility Grouping) 을 사용 할 지 여 부 를 결정 합 니 다. 이 메커니즘 은 큰 메모리 블록 을 할당 할 때 메모리 조각 을 줄 일 수 있 습 니 다.보통 메모리 가 충분 할 때 만 이 기능 을 사용 합 니 다. 그렇지 않 으 면 소 모 를 줄 이 고 성능 을 떨 어 뜨 릴 수 있 습 니 다.그 중 pageblocknr_페이지 는 파트너 시스템 의 최고 단계 블록 에 포 함 될 수 있 는 페이지 수 를 표시 합 니 다.
이로써 메모리 관리 프레임 워 크 알고리즘 이 기본적으로 준비 되 었 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.