• Linux内核的冷热缓存


    缓存为什么会有冷热?

    究其原因,是因为对于内存的访问,可能是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,则从冷缓存中分配一页,否则,从热缓存中分配。

  • 相关阅读:
    计算机网络为什么是这样样子?
    MySQL技术内幕 InnoDB存储引擎 B+树索引的使用 笔记
    后端性能-batch 化的想法
    稳定高效的服务来自于稳定而合理的数据结构
    gRPC 学习了解记录
    Go 进阶训练营 Week02: error 错误处理
    生活小感受
    Nginx 499 排查到docker 中一个进程一直在空转
    方法论和原理总结
    Debug
  • 原文地址:https://www.cnblogs.com/long123king/p/3502116.html
Copyright © 2020-2023  润新知