缓存为什么会有冷热?
究其原因,是因为对于内存的访问,可能是CPU发起的,也可以是DMA设备发起的。
如果是CPU发起的,在CPU的硬件缓存中,就会保存相应的页内容。如果这个页本来没有存在于硬件缓存中,那么它的到来,势必会将原本为其他的页缓存的内容挤出硬件缓存。
但是,如果对于内存的访问是由DMA设备发起的,那么该页不会被CPU访问,就不需要在CPU的硬件缓存中进行缓存,也不会对已经缓存在硬件缓存中的页内容造成伤害。
在Linux操作系统中,每个内存区域(Zone)都分配了hot cache和cold cache,hot cache用来缓存那些很可能被CPU的硬件缓存收纳了的页。
hot/cold cache只处理单页分配的情况。
1: /* 2: * Really, prep_compound_page() should be called from __rmqueue_bulk(). But 3: * we cheat by calling it from here, in the order > 0 path. Saves a branch 4: * or two. 5: */ 6: static inline 7: struct page *buffered_rmqueue(struct zone *preferred_zone, 8: struct zone *zone, int order, gfp_t gfp_flags, 9: int migratetype) 10: { 11: unsigned long flags; 12: struct page *page; 13: int cold = !!(gfp_flags & __GFP_COLD); 14: 15: again: 16: if (likely(order == 0)) { 17: struct per_cpu_pages *pcp; 18: struct list_head *list; 19: 20: local_irq_save(flags); 21: pcp = &this_cpu_ptr(zone->pageset)->pcp; 22: list = &pcp->lists[migratetype]; 23: if (list_empty(list)) { 24: pcp->count += rmqueue_bulk(zone, 0, 25: pcp->batch, list, 26: migratetype, cold); 27: if (unlikely(list_empty(list))) 28: goto failed; 29: } 30: 31: if (cold) 32: page = list_entry(list->prev, struct page, lru); 33: else 34: page = list_entry(list->next, struct page, lru); 35: 36: list_del(&page->lru); 37: pcp->count--; 38: } else { 39: if (unlikely(gfp_flags & __GFP_NOFAIL)) { 40: /* 41: * __GFP_NOFAIL is not to be used in new code. 42: * 43: * All __GFP_NOFAIL callers should be fixed so that they 44: * properly detect and handle allocation failures. 45: * 46: * We most definitely don't want callers attempting to 47: * allocate greater than order-1 page units with 48: * __GFP_NOFAIL. 49: */ 50: WARN_ON_ONCE(order > 1); 51: } 52: spin_lock_irqsave(&zone->lock, flags); 53: page = __rmqueue(zone, order, migratetype); 54: spin_unlock(&zone->lock); 55: if (!page) 56: goto failed; 57: __mod_zone_page_state(zone, NR_FREE_PAGES, -(1 << order)); 58: } 59: 60: __count_zone_vm_events(PGALLOC, zone, 1 << order); 61: zone_statistics(preferred_zone, zone, gfp_flags); 62: local_irq_restore(flags); 63: 64: VM_BUG_ON(bad_range(zone, page)); 65: if (prep_new_page(page, order, gfp_flags)) 66: goto again; 67: return page; 68: 69: failed: 70: local_irq_restore(flags); 71: return NULL; 72: }
buffered_rmqueue用于从冷热分配器中分配单页的缓存页。
如果gfp_flags中指定的__GFP_COLD,则从冷缓存中分配一页,否则,从热缓存中分配。
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/119576.html