緩存爲何會有冷熱?linux
究其緣由,是由於對於內存的訪問,多是CPU發起的,也能夠是DMA設備發起的。緩存
若是是CPU發起的,在CPU的硬件緩存中,就會保存相應的頁內容。若是這個頁原本沒有存在於硬件緩存中,那麼它的到來,勢必會將本來爲其餘的頁緩存的內容擠出硬件緩存。this
可是,若是對於內存的訪問是由DMA設備發起的,那麼該頁不會被CPU訪問,就不須要在CPU的硬件緩存中進行緩存,也不會對已經緩存在硬件緩存中的頁內容形成傷害。操作系統
在Linux操做系統中,每一個內存區域(Zone)都分配了hot cache和cold cache,hot cache用來緩存那些極可能被CPU的硬件緩存收納了的頁。rest
hot/cold cache只處理單頁分配的狀況。code
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,則從冷緩存中分配一頁,不然,從熱緩存中分配。get