[커널 17차] 117 ~ 119주차

2022.12.25 18:13

ㅇㅇㅇ 조회 수:61

117 주차 : shrink_page_list() 리뷰

118 ~ 119 주차 :

 

shrink_slab()
- 인자로 gfp_mask, nid, memcg, priority를 받는다
- shrinker 구조체에 reclaim을 위한 count_object(), scan_object() callback이 있어서 이를 호출하여 reclaim을 수행한다
- L895 : 리턴 값 freed = 0으로 초기화
- L905 : !mem_cgroup_disable()이고 memcg가 root memcg가 아니면 shrink_slab_memcg()를 호출하고 결과를 리턴한다
- L908 : shrinker_rwsem를 down read trylock하고 실패시 out으로 이동
- L911 : shrinker_list라는 전역변수 list에 달려있는 shrinker 구조체에 대해 루프를 수행한다
- L912 : gfp_mask, nid, memcg를 받아서 shrink_control sc 생성
- L918 : 함수 do_shrink_slab() 수행하고 ret에 결과 저장
- L919 : ret == SHRINK_EMPTY이면 ret = 0으로 한다
- L921 : freed에 ret 값 누적
- L927 : shrinker_rwsem가 contended인 경우엔 freed == 0이면 1로 세팅하고 아니면 그대로 유지한 채 loop break
- L931 : 루프 종료
- L933 : shrinker_rwsem up read
- L934 : out
- L935 : cond_resched()
- L936 : freed 리턴


shrink_slab_memcg()
- 인자로 gfp_mask, nid, memcg, priority를 받는다
- L794 : 리턴 값 freed = 0으로 초기화
- L797 : memcg가 online이 아니면 0 리턴
- L800 : shrinker_rwsem를 down read trylock하고 실패시 0 리턴
- L803 : shrinker_info_protected() 함수로 memcg, nid에 해당하는 shrinker_info를 가져온다
- L804 : info == NULL이면 unlock으로 이동
- L807 : info->map은 비트맵으로 각 비트에 대해서 루프를 수행한다. 값이 1인 set 비트에 대해서만 루프 수행
- L808 : gfp_mask, nid, memcg를 받아서 shrink_control sc 생성
- L815 : 전역 변수 xarray shrinker_idr이 존재하고, 여기에 shrinker가 node로서 달려있다. 그리고 i(비트맵 인덱스)를 index로 shrinker_idr에 저장된 shrinker를 가져온다
- L816 : shrinker가 없거나 shrinker->flags에 SHRINKER_REGISTERED가 없으면 info->map에서 비트값을 클리어하고 continue로 다음 비트로 이동한다
- L823 : memcg_kmem_enabled()가 거짓이면서 (static key) shrinker->flags가 SHRINKER_NONSLAB이 없으면 continue로 다음 비트 이동
- L827 : do_shrink_slab()으로 reclaim 수행하여 reclaim된 페이지 수를 ret에 기록
- L828 : ret == SHRINK_EMPTY, 즉 counting 단계에서 reclaim이 안된 경우, race 때문일 가능성이 있으니 비트맵에서 인덱스를 클리어하고, 메모리 배리어 수행 후 do_shrink_slab()을 다시 수행한다. 결과가 다시 SHRINK_EMPTY 이면 ret = 0으로 하고 아니면 비트맵에서 인덱스를 복구한다
- L852 : freed에 reclaim된 페이지 수를 누적
- L854 : shrinker_rwsem가 contended인 경우엔 freed == 0이면 1로 세팅하고 아니면 그대로 유지한 채 loop break
- L858 : loop 종료
- L859 : unlock
- L860 : shrinker_rwsem up read
- L861 : freed 리턴


register_shrinker_prepared()
- 인자로 shrinker 구조체를 받는다
- L653 : shrinker_rwsem down write
- L654 : shrinker_list tail에 shrinker 추가
- L655 : shrinker->flags에 SHRINKER_REGISTERED 추가
- L656 : shrinker_rwsem up write


do_shrink_slab()
- 인자로 shrink_control shrinkctl, shrinker, priority를 받는다
- L695 : 회수한 페이지 수 freed = 0으로 초기화
- L701 : shrinker->batch가 있으면 이를 batch_size로 잡고 없으면 128로 잡는다
- L703 : scanned = 0으로 초기화
- L705 : shrinker->count_object()를 호출하여 freeable page 수를 산출한다
- L706 : freeable == 0이거나 SHRINK_EMPTY이면 freeable을 리턴
- L714 : xchg_nr_deferred() 함수로 이전 scan에서 defer되었던 값을 nr로 가져온다
- L716 : delta값을 shrinker->seeks 설정 유무에 따라 다르게 계산한다. 설정 안된 경우 freeable / 2로 계산하고 설정 되어 있으면 freeable >> priority에 4배를 한 후 shrinker->seeks로 나누어 구한다
- L729 : total_scan 값을 nr >> priority + delta로 구하고 freeable * 2로 cap하여 계산
- L751 : total_scan이 batch_size와 freeable보다 작아질 때까지 while 문 수행
- L754 : nr_to_scan을 batch_size와 freeable 중 작은 것으로 설정
- L756 : shrinkctl->nr_to_scan, shrinkctl->nr_scanned를 모두 nr_to_scan으로 설정
- L758 : shrinker->scan_objects() callback으로 reclaim 수행 후 결과를 ret에 저장
- L759 : 결과가 SHRINK_STOP이면 break
- L761 : 아니면 freed에 ret 값 누적
- L763 : SLABS_SCANNED event를 shrinkctl->nr_scanned 만큼 증가
- L764 : total_scan을 shrinkctl->nr_scanned 만큼 감소
- L765 : scanned를 shrinkctl->nr_scanned 만큼 증가
- L767 : cond_resched()
- L768 : while 문 종료
- L776 : next_deferred를 nr + delta - scanned로 계산하고 2 * freeable로 cap
- L783 : add_nr_deferred()로 next_deferred를 shrinker의 nr_deferred[nid]에 더해준다
- L786 : freed를 리턴


xchg_nr_deferred()
- 인자로 shrinker, shrink_control sc를 받는다
- L495 : sc->nid를 가져온다
- L497 : shrinker->flags에 SHRINKER_NUMA_AWARE가 없으면 nid를 0으로 잡는다
- L500 : sc->memcg가 있고 shrinker->flags에 SHRINKER_MEMCG_AWARE가 있으면 xchg_nr_deferred_memcg() 함수로 memcg, nid에 해당하는 memcg->nodeinfo[nid]->shrinker_info->nr_deferred[shrinker->id]를 atomic xchg로 0으로 바꾸고 원래 값을 리턴한다
- L505 : 아니면 shrinker->nr_deferred[nid]를 atomic xchg로 0으로 바꾸고 원래 값을 리턴한다


add_nr_deferred()
- 인자로 nr, shrinker, shrink_control sc를 받는다
- L512 : sc->nid를 가져온다
- L514 : shrinker->flags에 SHRINKER_NUMA_AWARE가 없으면 nid를 0으로 잡는다
- L517 : sc->memcg가 있고 shrinker->flags에 SHRINKER_MEMCG_AWARE가 있으면 add_nr_deferred_memcg() 함수로 memcg, nid에 해당하는 memcg->nodeinfo[nid]->shrinker_info->nr_deferred[shrinker->id]를 atomic add return으로 nr만큼 증가시킨 뒤 리턴한다
- L505 : 아니면 shrinker->nr_deferred[nid]를 atomic add return으로 nr만큼 증가시킨 뒤 리턴한다


shrink_node_memcgs()
- 인자로 노드 정보 pgdat, scan control sc를 받아서 해당 노드의 모든 memcg에 대해 reclaim을 수행한다
- L2974 : sc->target_mem_cgroup에서 target_memcg를 가져온다
- L2977 : DFS로 target_memcg에서 시작해서 모든 child memcg에 대해 루프를 돈다
- L2979 : 현 노드/현 memcg에 대한 lruvec을 가져온다
- L2989 : 함수 cond_resched()으로 우선 순위 높은 task 있으면 양보
- L2991 : 함수 mem_cgroup_calculate_protection()로 현 memcg의 memcg->memory.emin, memcg->memory.elow를 계산한다
- L2993 : memcg memory가 emin보다 작으면 reclaim하지 않고 다음 memcg로 continue
- L2999 : memcg memory가 elow보다 작으면 sc->memcg_low_reclaim이 설정되어 있으면 reclaim하고 아니면 continue한다. 이 때 sc->memcg_low_skipped = 1로 로깅한다
- L3016 : 함수 shrink_lruvec()을 이용하여 reclaim 수행
- L3018 : 함수 shrink_slab()으로 reclaim 수행
- L3022 : reclaim 결과에 따라 함수 vmpressure() reclaim 효율을 업데이트한다
- L3026 : 다음 memcg로 이동한다


shrink_node()
- 인자로 node 정보 pgdat과 reclaim 설정값 scan_control sc를 받아 node reclaim을 수행한다
- L3039 : again
- L3044 : 함수 mem_cgroup_flush_stats()로 mem cgroup lurvec 정보들을 flush한다
- L3046 : sc->nr 메모리를 0으로 memset
- L3048 : sc->nr_reclaimed와 sc->nr_scanned를 로컬 변수로 가져온다
- L3054 : lru_lock을 걸고 memcg의 lruvec anon cost 및 file cost를 sc->anon_cost, sc->file_cost로 가져온다. 이후 lru lock을 해제한다
- L3063 : sc에 force_deactivate가 설정되어 있지 않으면 if 문 진입
- L3066 : refault가 발생하면 새로운 workingset이 설정되기 때문에 새 workingset에 속하지 않는 기존 stale active page들을 deactivate 시켜야 한다. 따라서 sc->may_deactivate를 DEACTIVATE_ANON/DEACTIVATE_FILE로 설정한다. 또는 inactive list가 너무 작으면 sc->may_deactivate를 DEACTIVATE_ANON/DEACTIVATE_FILE로 설정한다. refault도 아니고 inactive list가 작은 것도 아니면 DEACTIVATE_ANON/DEACTIVATE_FILE를 각각 클리어한다
- L3086 : sc에 force_deactivate가 설정되어 있으면 sc->may_deactivate를 DEACTIVATE_ANON/DEACTIVATE_FILE로 설정한다
- L3094 : file inactive list가 sc->priority에 견주어 크고 (file >> priority), DEACTIVATE_FILE이 클리어되어 있으면 sc->cache_trim_mode를 1로 설정한다. 아니면 0으로 설정한다
- L3109 : sc->target_mem_cgroup이 NULL이면 if문 진입
- L3110 : node의 free page와 file page 수를 계산하고 각 zone의 high watermark 총합을 계산한다. 또한 node의 inactive anon page수를 가져온다. 그리고 file + free page 수가 high watermark 총합보다 같거나 작고, DEACTIVATE_ANON가 클리어 되어 있고 anon inactive page 수가 priority에 비해 크면 sc->file_is_tiny를 set한다
- L3139 : shrink_node_memcgs() 함수로 해당 노드의 모든 memcg에 대해 reclaim을 수행한다
- L3141 : current->reclaim_state가 있으면 current->reclaim_state->reclaimed_slab을 sc->nr_reclaimed에 더해주고 current->reclaim_state->reclaimed_slab = 0으로 초기화한다
- L3147 : vmpressure() 함수로 새로 scan/reclaim된 페이지 수를 받아서 메모리 압력을 재계산하고 이를 user process에 리포팅한다
- L3151 : 새로 reclaim된 페이지가 있으면 reclaimable = true로 세팅
- L3154 : current task가 kswapd인 경우 1) isolated page 수 == writeback page 수이면 pgdat->flags에 PGDAT_WRITEBACK을 set 하고 2) unqueued dirty page 수 == isolate file page 수이면 pgdat->flags에 PGDAT_DIRTY를 set 한다. 그리고 3) writeback이 끝난 뒤 바로 reclaim해야 하는 immediate page가 있으면 congestion_wait() 함수로 100ms 동안 wait 한다
- L3197 : kswapd 이거나 memcg reclaim이면서 writeback throttling이 가능한 경우 dirty page 수 == congested page 수이면 lruvec->flags에 LRUVEC_CONGESTED를 set 한다
- L3208 : kswapd가 아니고 current task에서 backing device throttling이 되면서 hibernation mode가 아니고 lruvec->flags에 LRUVEC_CONGESTED가 있으면 IO completion을 위해 wait_iff_congested()을 수행하고 100ms 동안 wait
- L3213 : should_continue_reclaim() 함수로 reclaim을 계속해야 하는지 판단하고 계속해야 하면 again으로 이동하여 다시 reclaim 수행
- L3223 : 새로 reclaim된 page가 하나라도 있으면 pgdat->kswapd_failures = 0으로 초기화


should_continue_reclaim()
- 인자로 pgdat, nr_reclaimed : 새로 reclaim된 page 수, scan control sc를 받는다
- L2928 : in_reclaim_compaction()이 아니면 false 리턴. high order alloc이거나 메모리 압력이 높지 않으면 중단.
- L2941 : reclaim된 page가 없으면 false 리턴
- L2945 : 각 zone을 돌면서 루프 수행
- L2947 : managed_zone이 아니면 continue
- L2950 : order 0 page에 대해 해당 zone이 compaction 가능하면 false 리턴
- L2958 : compaction 가능한 zone이 없으면 루프 종료
- L2964 : order의 2배에 해당하는 페이지가 compaction을 위해 필요
- L2965 : inactivate file page 수를 가져온다
- L2966 : anon swap 가능하면 inactivate anon page 수로 가져온다
- L2969 : inactivate file + anon page 수 합이 compaction 위해 필요한 페이지 수보다 많으면 true 아니면 false 리턴


can_reclaim_anon_pages()
- 인자로 memcg, nid, scan control sc를 받는다
- L546 : memcg == NULL 이면 nr_swap_pages, 즉 swap 가능한 페이지가 있으면 true 리턴
- L553 : 아니면 해당 memcg에서 swap 가능한 페이지 있으면 true 리턴
- L564 : 아니면 swap할 수 없다. demote 관련은 생략


shrink_zones()
- 인자로 zonelist, scan control sc를 받는다
- L3281 : buffer head를 시스템 한계보다 초과해서 사용하는 경우 sc->gfp_mask에 GFP_HIGHMEM을 추가하고 sc->reclaim_idx도 그에 따라 조정한다. 추후 L3349에서 원래 값으로 sc->gfp_mask를 복구한다. 이 이유는 user가 요청한 highmem 메모리 영역이 DMA device 같은 lowmem 영역의 메모리를 잡고 있을 수 있기 때문이다(?)
- L3287 : zonelist에 따라서 루프 수행
- L3293 : global reclaim이면 if 문 진입
- L3294 : 현재 node가 cpuset에서 허용되지 않으면 스킵
- L3307 : 요청 order가 3 초과 (costly order) 이고 reclaim 없이 compaction 수행 가능하면 sc->compaction_ready를 true로 만들고 다음 zone으로 continue. Compaction 수행 가능 여부는 함수 compaction_ready()로 판단한다
- L3320 : 이미 현재 노드에서 reclaim 수행했으면 continue로 스킵
- L3329 : 함수 mem_cgroup_soft_limit_reclaim()로 memcg soft limit reclaim을 수행한다.
- L3339 : if 문 끝난 이후 동일 노드면 zone 스킵
- L3341 : 현재 zone에 해당하는 node 기록하여 스킵할 때 사용
- L3342 : 함수 shrink_node()로 현 zone에 해당하는 node에 대해 reclaim을 수행한다


mem_cgroup_soft_limit_reclaim()
- L3408 : mem_cgroup_soft_reclaim() 함수로 target memcg와 그 child memcg에 대해 reclaim을 수행한다
- L3449 : 회수한 page 수를 리턴


mem_cgroup_soft_reclaim()
- 주어진 root_memcg에서 시작하여 soft limit이하로 page 수가 줄어들 때까지 mem_cgroup_shrink_node()으로 reclaim을 수행하고 회수한 page 수를 리턴
- target memcg와 그 child memcg에 대해 reclaim을 수행


mem_cgroup_shrink_node()
- shrink_lruvec()을 호출하여 reclaim 수행
- 인자로 memcg를 받아서 scan control에 추가 후 scan control로 shrink_lruvec()
- shrink_lruvec() 내부에서 mem_cgroup_uncharge_list()를 부르고 여기서 memcg->memory->usage를 reclaim한 만큼 감소히킨다


이상 __alloc_pages_direct_reclaim() 까지의 path는 이전에 보았으므로 생략

번호 제목 글쓴이 날짜 조회 수
공지 [공지] 스터디 정리 노트 공간입니다. woos 2016.05.14 623
185 [커널 18차] 93주차 kkr 2023.03.04 53
184 [커널 18차] 91주차 kkr 2023.02.18 95
183 [커널 19차] 39 주차 Min 2023.02.18 53
182 [커널 18차] 90주차 kkr 2023.02.13 63
181 [커널 19차] 38 주차 Min 2023.02.11 45
180 [커널 19차] 37 주차 Min 2023.02.04 478
179 [커널 19차] 36 주차 Min 2023.01.28 85
178 [커널 18차] 88주차 kkr 2023.01.28 55
177 [커널 19차] 35 주차 Min 2023.01.14 93
176 [커널 17차] 120 ~ 121주차 ㅇㅇㅇ 2023.01.08 110
175 [커널 18차] 85주차 kkr 2023.01.07 53
174 [커널 19차] 34 주차 Min 2023.01.07 42
173 [커널 18차] 84주차 kkr 2022.12.31 104
172 [커널 19차] 33 주차 Min 2022.12.31 51
» [커널 17차] 117 ~ 119주차 ㅇㅇㅇ 2022.12.25 61
170 [커널 19차] 31 주차 Min 2022.12.17 63
169 [커널 19차] 30 주차 Min 2022.12.10 61
168 [커널 17차] 112 ~ 116주차 ㅇㅇㅇ 2022.12.05 72
167 [커널 18차] 80주차 kkr 2022.12.03 156
166 [커널 19차] 28 ~ 29 주차 Min 2022.12.03 35
XE Login