亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費(fèi)注冊(cè) 查看新帖 |

Chinaunix

  平臺(tái) 論壇 博客 文庫(kù)
最近訪問(wèn)板塊 發(fā)新帖
查看: 2040 | 回復(fù): 6
打印 上一主題 下一主題

[內(nèi)存管理] BiscuitOS 技術(shù)分享[請(qǐng)勿回復(fù)] [復(fù)制鏈接]

論壇徽章:
9
程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-02-11 06:20:00程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-02-14 06:20:00程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-02-14 06:20:0015-16賽季CBA聯(lián)賽之吉林
日期:2016-03-23 17:25:0015-16賽季CBA聯(lián)賽之浙江
日期:2016-04-01 08:25:0615-16賽季CBA聯(lián)賽之山西
日期:2016-04-01 10:09:1915-16賽季CBA聯(lián)賽之廣夏
日期:2016-06-03 15:58:212016科比退役紀(jì)念章
日期:2016-07-28 17:42:5215-16賽季CBA聯(lián)賽之廣東
日期:2017-02-20 23:32:43
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報(bào)告]
發(fā)表于 2016-03-30 10:17 |只看該作者 |正序?yàn)g覽
本帖最后由 Buddy_Zhang1 于 2016-04-02 11:41 編輯

本帖用于 BiscuitOS 的技術(shù)分享.
BiscuitOS 介紹:   www.72891.cn/thread-4241956-1-1.html
本貼請(qǐng)勿回復(fù),回復(fù)請(qǐng)到 www.72891.cn/thread-4241956-1-1.html
技術(shù)目錄:
              1. BiscuitOS 上輕松使用紅黑樹(shù)
              2. BiscuitOS 上輕松使用哈希散列式
              3. BiscuitOS 上構(gòu)建 GFP_ZONE_TABLE
              4. BiscuitOS - SLUB 分配器 slab page 大小計(jì)算方法
              5. BiscuitOS  中最大文件數(shù)計(jì)算方法:

論壇徽章:
11
程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2015-09-09 06:20:00CU十四周年紀(jì)念徽章
日期:2016-05-16 11:11:112016科比退役紀(jì)念章
日期:2016-05-04 17:16:57程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-02-20 06:20:00程序設(shè)計(jì)版塊每周發(fā)帖之星
日期:2015-11-06 19:30:58程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2015-09-12 06:20:00程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2015-09-11 06:20:00每日論壇發(fā)貼之星
日期:2015-09-10 06:20:00程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2015-09-10 06:20:00每日論壇發(fā)貼之星
日期:2015-09-09 06:20:0015-16賽季CBA聯(lián)賽之四川
日期:2016-12-15 15:52:10
7 [報(bào)告]
發(fā)表于 2016-04-14 16:15 |只看該作者
這個(gè)東西我想?yún)⑴c,但不知道如何入手

論壇徽章:
9
程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-02-11 06:20:00程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-02-14 06:20:00程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-02-14 06:20:0015-16賽季CBA聯(lián)賽之吉林
日期:2016-03-23 17:25:0015-16賽季CBA聯(lián)賽之浙江
日期:2016-04-01 08:25:0615-16賽季CBA聯(lián)賽之山西
日期:2016-04-01 10:09:1915-16賽季CBA聯(lián)賽之廣夏
日期:2016-06-03 15:58:212016科比退役紀(jì)念章
日期:2016-07-28 17:42:5215-16賽季CBA聯(lián)賽之廣東
日期:2017-02-20 23:32:43
6 [報(bào)告]
發(fā)表于 2016-04-02 10:53 |只看該作者
本帖最后由 Buddy_Zhang1 于 2016-04-02 11:02 編輯

BiscuitOS / Linux 中最大文件數(shù)計(jì)算方法:

在文件系統(tǒng)中,涉及一個(gè)最大文件數(shù),本帖重點(diǎn)講述如何計(jì)算這個(gè)值.
VFS 在初始化過(guò)程中,從內(nèi)核獲得當(dāng)前系統(tǒng)物理頁(yè)的數(shù)量(默認(rèn)一個(gè)物理頁(yè)的大小為 4K).
一個(gè) struct file 分配的 inode 和 dcache 的空間大概是 1K,內(nèi)核規(guī)定 struct file 占用的內(nèi)存不能超過(guò)總內(nèi)存的 10%,
于是計(jì)算公式如下:
1. mempages 為系統(tǒng)物理頁(yè)的數(shù)量,每個(gè)物理頁(yè)默認(rèn)為 4K.
2. PAGE_SIZE 為物理頁(yè)的大小,那么:
          "PAGE_SIZE / 1024"
    上面表達(dá)式的含義為,因?yàn)橐粋(gè) struct file 分配的 inode 和 dcache 空間大小為 1K,那么一個(gè)物理頁(yè)就能存儲(chǔ) 4 個(gè) struct file.
3. 那么全部物理頁(yè)可以存儲(chǔ)的 struct file 為:
          mempages * (PAGE_SIZE / 1024)
4. 由于內(nèi)核規(guī)定,struct file 的內(nèi)存空間只能為總內(nèi)存的 10 %,所以最后文件數(shù)為:
         (mempages * (PAGE_SIZE / 1024)) / 10
5. 系統(tǒng)默認(rèn)最大的文件數(shù)為 NR_FILE,通過(guò)上面的計(jì)算,最后最大文件數(shù)結(jié)果為:
         files_stat.max_files = max_t(unsigned long, n, NR_FILE);

論壇徽章:
9
程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-02-11 06:20:00程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-02-14 06:20:00程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-02-14 06:20:0015-16賽季CBA聯(lián)賽之吉林
日期:2016-03-23 17:25:0015-16賽季CBA聯(lián)賽之浙江
日期:2016-04-01 08:25:0615-16賽季CBA聯(lián)賽之山西
日期:2016-04-01 10:09:1915-16賽季CBA聯(lián)賽之廣夏
日期:2016-06-03 15:58:212016科比退役紀(jì)念章
日期:2016-07-28 17:42:5215-16賽季CBA聯(lián)賽之廣東
日期:2017-02-20 23:32:43
5 [報(bào)告]
發(fā)表于 2016-04-01 08:23 |只看該作者
本帖最后由 Buddy_Zhang1 于 2016-04-01 08:25 編輯

BiscuitOS - SLUB 分配器 slab page 大小計(jì)算方法

在 BiscuitOS / Linux 上使用 kmem_cache_create() 創(chuàng)建緩存時(shí),需要根據(jù)分配的對(duì)象的大小從 Buddy 分配器中獲得空閑頁(yè)來(lái)組成 slab page.
例如:
      struct kmem_cache *file_cachep = kmem_cache_create("File",sizeof(struct file),0,0,NULL);
內(nèi)核通過(guò) sizeof(struct file) 計(jì)算的值將從 Buddy 中獲得的空閑頁(yè),然后將空閑頁(yè)分成大小為 sizeof(struct file) 的 object.
儲(chǔ)存這些 object 的 page 稱為 slab page.本帖用于討論一個(gè) slab page 的大小.
內(nèi)核根據(jù) object 的 size 來(lái)計(jì)算 slab page 的大小,
1. 如果 object 的 size 很小,那么一個(gè) slab page 就由一個(gè) page 組成
2. 如果 object 的 size 很大,那么一個(gè) slab page 可能有兩個(gè)或多個(gè) page 組成.
Slab page 的大小計(jì)算如下:
1. 在 slub 中一個(gè) slab page 中規(guī)定最小的 object 數(shù)量為 slub_min_objects,其值可以為零,
    當(dāng) slub_min_objects 為零的時(shí)候,內(nèi)核根據(jù) cpu 的數(shù)量來(lái)進(jìn)行賦值,其計(jì)算公式如下:
         slub_min_objects = 4 * (fls(nr_cpu_ids) + 1)
    其中函數(shù) fls() 的作用是求參數(shù)的最高位的位數(shù),如
         fls(00001100B) = 4
         fls(00001000B) = 4
         fls(00010000B) = 5
    fls() 的作用類似于向下除的效果.
    nr_cpu_ids 為系統(tǒng) cpu 的個(gè)數(shù).
    于是我們可以得出以下結(jié)論:
    (1) 在單 CPU 的體系中 slub_min_objects 為 8
    (2) 在雙 CPU 的體系中 slub_min_objects 為 12
    (3) 在四 CPU 的體系中 slub_min_objects 為 16
2. 一個(gè) slab page 最大 objects 數(shù)量為 max_objects,其計(jì)算如下:
    max_objects = (PAGE_SIZE << slub_max_order) / size;
    max_objects = min(min_objects,max_objects);
    上述表達(dá)式中 slub_max_order 為 3,其含義為最大的 slab_page 為 2^3,也就是 一個(gè)最大的 slab_page 可由 8 page 構(gòu)成.
    size 為 object 的 size.
3. 獲得上面兩個(gè)值之后,內(nèi)核進(jìn)行 slab order 的計(jì)算,其過(guò)程如下:
    (1) 對(duì)一個(gè) page 構(gòu)成的 slab page 進(jìn)行檢測(cè),如果在這種情況下, objects 的數(shù)量大于 slab page 規(guī)定的最大 object 的數(shù)量
          那么內(nèi)核直接從 Buddy 分配器中獲得最大 object 時(shí)的 page. 代碼如下:
         if ((PAGE_SIZE << min_order) / size > MAX_OBJS_PER_PAGE)
                return get_order(size * MAX_OBJS_PER_PAGE) - 1;
     (2) 內(nèi)核計(jì)算 object 的 size 對(duì)應(yīng)的最小 order,其計(jì)算如下:
           order =  fls(min_objects * size - 1) - PAGE_SHIFT;
           通過(guò)上面對(duì) min_objects 的計(jì)算,可以獲得 object 的最小 order 如下表:



通過(guò)上面表的計(jì)算,我們可以看出不同的 object size 的 slab page 的最小 order 不同,由于 order 最小為 0,所以最最小 order 進(jìn)行處理
          order = max(min_order,fls(min_objects * size - 1) - PAGE_SHIFT);
     (3) 獲得最小 order 之后,就從最小 order 開(kāi)始遍歷,只要滿足一個(gè) slab page 中,浪費(fèi)部分小于 1/16 就可以進(jìn)行分配.因?yàn)?object size 大小不同,
         而 page 則按 PAGE_SIZE 進(jìn)行對(duì)齊,所以無(wú)法避免一定的浪費(fèi),但內(nèi)核規(guī)定只要浪費(fèi)不超過(guò) 1/16 就可以進(jìn)行分配.所以代碼如下:
          for (order = max(min_order , fls(min_objects * size - 1) - PAGE_SHIFT) ; order <= max_order; order++) {
                   unsigned long slab_size = PAGE_SIZE << order;
         
                  if (slab_size < min_objects * size)
                         continue;
                  rem = slab_size % size;

                  if (rem <= slab_size / fract_leftover)
                          break;
}
     (4) 通過(guò)上面的計(jì)算之后獲得最小 slab page 的 order,接著就可以從 Buddy 中獲得對(duì)應(yīng)的 page 來(lái)構(gòu)成 slab page.

論壇徽章:
9
程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-02-11 06:20:00程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-02-14 06:20:00程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-02-14 06:20:0015-16賽季CBA聯(lián)賽之吉林
日期:2016-03-23 17:25:0015-16賽季CBA聯(lián)賽之浙江
日期:2016-04-01 08:25:0615-16賽季CBA聯(lián)賽之山西
日期:2016-04-01 10:09:1915-16賽季CBA聯(lián)賽之廣夏
日期:2016-06-03 15:58:212016科比退役紀(jì)念章
日期:2016-07-28 17:42:5215-16賽季CBA聯(lián)賽之廣東
日期:2017-02-20 23:32:43
4 [報(bào)告]
發(fā)表于 2016-03-31 08:32 |只看該作者
BiscuitOS 上構(gòu)建 GFP_ZONE_TABLE

本貼主要講述如何構(gòu)建 BiscuitOS 或 Linux 上的 GFP_ZONE_TABLE 表.
當(dāng)在內(nèi)核中分配內(nèi)存的時(shí)候,必須指定分配的標(biāo)志,如:
kmalloc(size,gfp)
kmem_cache_alloc(cache,gfp)
內(nèi)核通過(guò) gfp 標(biāo)志來(lái)判斷從哪個(gè)區(qū)間分配內(nèi)存,內(nèi)核將物理內(nèi)存按區(qū)間分配,在 Linux 中存在 ZONE_DMA,ZONE_NORMAL,ZONE_DMA32 和 ZONE_HIGHMEM 幾個(gè) zone.
每個(gè) zone 管理各自內(nèi)存,調(diào)用者只要使用 gfp 標(biāo)志就可以從不同的 gfp 區(qū)間獲得內(nèi)存.
內(nèi)核使用 gfp_zone(gfp) 函數(shù)來(lái)將 gfp 標(biāo)志轉(zhuǎn)換為對(duì)應(yīng)的 zone.其實(shí)現(xiàn)如下:
  1. static inline enum zone_type gfp_zone(gfp_t flags)
  2. {
  3.     enum zone_type z;
  4.     int bit = (int)(flags & GFP_ZONEMASK);

  5.     z = (GFP_ZONE_TABLE >> (bit * ZONES_SHIFT)) &
  6.             ((1 << ZONES_SHIFT) - 1);

  7.     if(__builtin_constant_p(bit))
  8.         BUILD_BUG_ON((GFP_ZONE_BAD >> bit) & 1);
  9.     else {
  10. #ifdef CONFIG_DEBUG_VM
  11.         BUG_ON((GFP_ZONE_BAD >> bit) & 1);
  12. #endif
  13.     }
  14.     return z;
  15. }
復(fù)制代碼
從上面代碼實(shí)現(xiàn)過(guò)程中可以看出這個(gè)轉(zhuǎn)換依賴 GFP_ZONE_TABLE 表.其定義如下:
#define GFP_ZONE_TABLE ( \
        (ZONE_NORMAL << 0 * ZONES_SHIFT)   \
        | (OPT_ZONE_DMA << ___GFP_DMA * ZONES_SHIFT) \
        | (OPT_ZONE_HIGHMEM << ___GFP_HIGHMEM * ZONES_SHIFT) \
        | (OPT_ZONE_DMA32 << ___GFP_DMA32 * ZONES_SHIFT)  \
        | (ZONE_NORMAL << ___GFP_MOVABLE * ZONES_SHIFT)   \
        | (OPT_ZONE_DMA << (___GFP_MOVABLE | ___GFP_DMA) * ZONES_SHIFT)  \
        | (ZONE_MOVABLE << (___GFP_MOVABLE | ___GFP_HIGHMEM) * ZONES_SHIFT) \
        | (OPT_ZONE_DMA32 << (___GFP_MOVABLE | ___GFP_DMA32) * ZONES_SHIFT) \
        )
以及另外一個(gè)表 GFP_ZONE_BAD.
#define GFP_ZONE_BAD (   \
          1 << (___GFP_DMA | ___GFP_HIGHMEM)                  \
        | 1 << (___GFP_DMA | ___GFP_DMA32)               \
        | 1 << (___GFP_DMA32 | ___GFP_HIGHMEM)                   \
        | 1 << (___GFP_DMA | ___GFP_DMA32 | ___GFP_HIGHMEM)       \
        | 1 << (___GFP_MOVABLE | ___GFP_HIGHMEM | ___GFP_DMA)   \
        | 1 << (___GFP_MOVABLE | ___GFP_DMA32 | ___GFP_DMA)    \
        | 1 << (___GFP_MOVABLE | ___GFP_DMA32 | ___GFP_HIGHMEM)    \
        | 1 << (___GFP_MOVABLE | ___GFP_DMA32 | ___GFP_DMA | ___GFP_HIGHMEM) \
)
內(nèi)核是如何構(gòu)建這兩張表?本貼重點(diǎn)講述內(nèi)核如何構(gòu)建這兩張表.
首先內(nèi)核將一個(gè)節(jié)點(diǎn)分作不同的管理區(qū),每個(gè)管理區(qū)使用 struct zone 進(jìn)行管理,內(nèi)核在 zone 基本分為:
ZONE_DMA,ZONE_NORMAL,ZONE_DMA32 和 ZONE_HIGHMEM,每個(gè)管理區(qū)使用 gfp 標(biāo)志表示為:
#define ___GFP_DMA               0x01u
#define ___GFP_HIGHMEM     0x02u
#define ___GFP_DMA32          0x04u
#define ___GFP_MOVABLE     0x08u
在 gfp 標(biāo)志中低 3 位來(lái)表示內(nèi)存從哪個(gè) zone 獲得,其掩碼為:
#define GFP_ZONEMASK  (__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32 | __GFP_MOVABLE)
內(nèi)核規(guī)定 ___GFP_DMA,___GFP_HIGHMEM 和 ___GFP_DMA32 其兩個(gè)或全部不能同時(shí)存在于 gfp 標(biāo)志中.
四個(gè)標(biāo)志排列組合后可以獲得下表:



從上面的表很容易構(gòu)建 GFP_ZONE_BAD,將所有錯(cuò)誤情況或起來(lái)就行.
1. (___GFP_DMA      | ___GFP_HIGHMEM)
2. (___GFP_DMA      | ___GFP_DMA32)
3. (___GFP_DMA32 | ___GFP_HIGHMEM )
4. (___GFP_DMA32 | ___GFP_HIGHMEM | ___GFP_DMA)
5. (___GFP_DMA     | ___GFP_HIGHMEM | ___GFP_MOVABLE )
6. (___GFP_DMA     | ___GFP_DMA32       | ___GFP_MOVABLE)
7. (___GFP_DMA32 | ___GFP_HIGHMEM | ___GFP_MOVABLE)
8. (___GFP_DMA32 | ___GFP_DMA32       | ___GFP_HIGHMEM | ___GFP_MOVABLE)
將上面 8 種情況合成 BAD TABLE 如下:
#define GFP_ZONE_BAD (   \
          1 << (___GFP_DMA | ___GFP_HIGHMEM)                  \
        | 1 << (___GFP_DMA | ___GFP_DMA32)               \
        | 1 << (___GFP_DMA32 | ___GFP_HIGHMEM)                   \
        | 1 << (___GFP_DMA | ___GFP_DMA32 | ___GFP_HIGHMEM)       \
        | 1 << (___GFP_MOVABLE | ___GFP_HIGHMEM | ___GFP_DMA)   \
        | 1 << (___GFP_MOVABLE | ___GFP_DMA32 | ___GFP_DMA)    \
        | 1 << (___GFP_MOVABLE | ___GFP_DMA32 | ___GFP_HIGHMEM)    \
        | 1 << (___GFP_MOVABLE | ___GFP_DMA32 | ___GFP_DMA | ___GFP_HIGHMEM) \
)
剩下的 8 種情況就是可以分配.分別為:
1.  0
2. (___GFP_DMA)
3. (___GFP_HIGHMEM)
4. (___GFP_DMA32)
5. (___GFP_MOVABLE)
6. (___GFP_DMA           | ___GFP_MOVABLE)
7. (___GFP_HIGHMEM | ___GFP_MOVABLE)
8. (___GFP_DMA32      | ___GFP_MOVABLE)
構(gòu)建初期表為
\)
#define TABLE (                                                                  \
        (1 << 0)                                                                        \
      |  (1<<  ___GFP_DMA)                                                    \
      |  (1 <<  ___GFP_HIGHMEM)                                          \
      |  (1 <<  ___GFP_DMA32)                                                \
      |  (1 <<  ___GFP_MOVABLE)                                            \
      |  (1 << ___GFP_DMA           | ___GFP_MOVABLE)        \
      |  (1 << ___GFP_HIGHMEM | ___GFP_MOVABLE)        \
      |  (1 << ___GFP_DMA32      | ___GFP_MOVABLE)        \
)將對(duì)應(yīng)的 zone 填充進(jìn)去,其中
OPT_ZONE_DMA 代表 ___GFP_NORMAL 或者 ___GFP_NORMAL
OPT_ZONE_HGIHMEM 代表 ___GFP_NORMAL 或者 ___GFP_HIGHMEM
OPT_ZONE_DMA32 代表 ___GFP_NORMAL 或者 ___GFP_DMA32
根據(jù)表的分析,可獲得下面結(jié)論:
#define TABLE (                                                                  \
        (ZONE_NORMAL << 0)                                                                        \
      |  (OPT_ZONE_DMA <<  ___GFP_DMA)                                                    \
      |  (OPT_ZONE_HIGHMEM <<  ___GFP_HIGHMEM)                                          \
      |  (OPT_ZONE_DMA32 <<  ___GFP_DMA32)                                                \
      |  (ZONE_NORMAL <<  ___GFP_MOVABLE)                                            \
      |  (OPT_ZONE_DMA << ___GFP_DMA           | ___GFP_MOVABLE)        \
      |  (ZONE_MOVABLE << ___GFP_HIGHMEM | ___GFP_MOVABLE)        \
      |  (OPT_ZONE_DMA32 << ___GFP_DMA32      | ___GFP_MOVABLE)        \
)
由于不同的平臺(tái)會(huì)使用不同數(shù)量的 zone 管理區(qū),常見(jiàn)的 zone 分配為 ZONE_NORMAL 和 ZONE_HIGHMEM 搭配.
于是內(nèi)核將 TABLE 的位寬使用 ZONES_SHIFT 表示,如一個(gè)具有 ZONE_DMA,ZONE_DMA32,ZONE_NORMAL 和 ZONE_HIGHMEM 的平臺(tái)
ZONES_SHIFT 為 2,表示 GFP_ZONE_TABLE 每個(gè)選項(xiàng)的位寬為 2.于是最終的表為:
#define GFP_ZONE_TABLE ( \
        (ZONE_NORMAL << 0 * ZONES_SHIFT)   \
        | (OPT_ZONE_DMA << ___GFP_DMA * ZONES_SHIFT) \
        | (OPT_ZONE_HIGHMEM << ___GFP_HIGHMEM * ZONES_SHIFT) \
        | (OPT_ZONE_DMA32 << ___GFP_DMA32 * ZONES_SHIFT)  \
        | (ZONE_NORMAL << ___GFP_MOVABLE * ZONES_SHIFT)   \
        | (OPT_ZONE_DMA << (___GFP_MOVABLE | ___GFP_DMA) * ZONES_SHIFT)  \
        | (ZONE_MOVABLE << (___GFP_MOVABLE | ___GFP_HIGHMEM) * ZONES_SHIFT) \
        | (OPT_ZONE_DMA32 << (___GFP_MOVABLE | ___GFP_DMA32) * ZONES_SHIFT) \
        )

論壇徽章:
9
程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-02-11 06:20:00程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-02-14 06:20:00程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-02-14 06:20:0015-16賽季CBA聯(lián)賽之吉林
日期:2016-03-23 17:25:0015-16賽季CBA聯(lián)賽之浙江
日期:2016-04-01 08:25:0615-16賽季CBA聯(lián)賽之山西
日期:2016-04-01 10:09:1915-16賽季CBA聯(lián)賽之廣夏
日期:2016-06-03 15:58:212016科比退役紀(jì)念章
日期:2016-07-28 17:42:5215-16賽季CBA聯(lián)賽之廣東
日期:2017-02-20 23:32:43
3 [報(bào)告]
發(fā)表于 2016-03-30 19:36 |只看該作者
BiscuitOS 上輕松使用哈希散列式

哈希散列式作為 Linux 內(nèi)核重要的數(shù)據(jù)結(jié)構(gòu),負(fù)責(zé) Linux 的基本運(yùn)作,由于其高效的數(shù)據(jù)管理能力和實(shí)用性,
內(nèi)核也將哈希散列式作為其基本數(shù)據(jù)結(jié)構(gòu).本樓重點(diǎn)介紹如何在 BiscuitOS 和 Linux 使用哈希散列式.

哈希散列式的實(shí)現(xiàn)方法多種多樣,這里以拉鏈法做為介紹,至于理論部分可以自行查找.
哈希散列式在內(nèi)核中比較典型的運(yùn)用如 inode 和 dentry 的管理,pid 管理以及本樓例子 kmap() 分配的內(nèi)存管理.

內(nèi)核中 KMAP 的區(qū)域就是使用哈希散列式進(jìn)行管理.
從 ZONE_HIGHMEM 中的 Buddy System 中獲得一個(gè)空閑 page 之后,使用 hash_ptr(page,PA_HASH_ORDER) 獲得哈希散列式的 key.
內(nèi)核維護(hù)了一個(gè)哈希散列表頭 page_address_htable[1 << PA_HASH_ORDER]
內(nèi)核通過(guò) page_slot(page) 可以獲得 hash 表頭,在通過(guò)內(nèi)部的 list_head 進(jìn)行遍歷.

哈希散列式使用例子:
源碼位于 /BiscuitOS/tools/TestCase_Hash.c
  1. #include "linux/kernel.h"
  2. #include "linux/debug.h"
  3. #include "linux/types.h"
  4. #include "linux/slab.h"

  5. #define HEAD_NUM    3
  6. #define VALUE_NUM   100

  7. struct node {
  8.         struct hlist_node node;
  9.         int num;
  10. };

  11. struct hlist_head *phash = NULL;
  12. /*
  13. * TestCase_Hash
  14. */
  15. void TestCase_Hash(void)
  16. {
  17.         int i,k;
  18.         struct hlist_node *hnode;
  19.         struct hlist_head *head;
  20.         struct node *node;
  21.         int *value;

  22.         /* Prepare test data */
  23.         value = (int *)kmalloc(sizeof(int) * VALUE_NUM,GFP_KERNEL);
  24.         for(i = 0 ; i < VALUE_NUM ; i++)
  25.                 value[i] = i;

  26.         /* Prepare hash head array */
  27.         phash = (struct hlist_head *)kmalloc(sizeof(struct hlist_head) *
  28.                                         (1 << HEAD_NUM) , GFP_KERNEL);
  29.         /* Initialize hash head */
  30.         for(i = 0 ; i < (1 << HEAD_NUM) ; i++)
  31.                 INIT_HLIST_HEAD(&phash[i]);

  32.         /* Create Test node */
  33.         for(i = 0 ; i < VALUE_NUM ; i++) {
  34.                 node = (struct node *)kmalloc(sizeof(struct node),GFP_KERNEL);
  35.                 if(!node) {
  36.                         mm_err("No memory\n");

  37.                         /* Never water memory */
  38.                         goto bad_memory;
  39.                 }

  40.                 /* Prepare test data */
  41.                 node->num = value[i];
  42.                 /* Initialize the hash node */
  43.                 INIT_HLIST_NODE(&node->node);
  44.                 /* Get the hash head for node */
  45.                 head = &phash[hash_32(node->num,HEAD_NUM)];
  46.                 /* Add node into hash list */
  47.                 hlist_add_head(&node->node,head);
  48.         }

  49.         /* Trave all hash list */
  50.         for(i = 0 ; i < (1 << HEAD_NUM) ; i++) {
  51.                 mm_debug("HEAD %d:",i);
  52.                 if(!hlist_empty(&phash[i]))
  53.                         hlist_for_each_entry(node,hnode,&phash[i],node)
  54.                                 mm_debug("%d->",node->num);
  55.                 mm_debug("NULL\n");
  56.         }

  57.         /* Search data in hash list */
  58.         k = value[34];
  59.         head = &phash[hash_32(k,HEAD_NUM)];
  60.         mm_debug("Search %d in head %d\n",k,hash_32(k,HEAD_NUM));
  61.         if(!hlist_empty(head))
  62.                 hlist_for_each_entry(node,hnode,head,node)
  63.                         if(k == node->num)
  64.                                 mm_debug("Find the data %d\n",k);

  65.         /* Delete all node */
  66.         for(i = 0 ; i < (1 << HEAD_NUM) ; i++)
  67.                 while(!hlist_empty(&phash[i])) {
  68.                         node = hlist_entry(phash[i].first,struct node,node);
  69.                         hlist_del(&node->node);
  70.                         kfree(node);
  71.                 }

  72.         /* Final check */
  73.         for(i = 0 ; i < (1 << HEAD_NUM) ; i++) {
  74.                 if(!hlist_empty(&phash[i])) {
  75.                         mm_debug("HEAD %d REMAIN:",i);
  76.                         hlist_for_each_entry(node,hnode,&phash[i],node)
  77.                                 mm_debug("%d->",node->num);
  78.                         mm_debug("NULL\n");
  79.                 }
  80.         }
  81.         /* Free all and complete test */
  82.         kfree(phash);
  83.         kfree(value);

  84.         return;
  85. bad_memory:
  86.         for(i = 0 ; i < (1 << HEAD_NUM) ; i++)
  87.                 while(!hlist_empty(&phash[i])) {
  88.                         node = hlist_entry(phash[i].first,struct node,node);
  89.                         hlist_del(phash[i].first);
  90.                         kfree(node);
  91.                 }
  92.         kfree(phash);
  93.         kfree(value);
  94. }
復(fù)制代碼

論壇徽章:
9
程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-02-11 06:20:00程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-02-14 06:20:00程序設(shè)計(jì)版塊每日發(fā)帖之星
日期:2016-02-14 06:20:0015-16賽季CBA聯(lián)賽之吉林
日期:2016-03-23 17:25:0015-16賽季CBA聯(lián)賽之浙江
日期:2016-04-01 08:25:0615-16賽季CBA聯(lián)賽之山西
日期:2016-04-01 10:09:1915-16賽季CBA聯(lián)賽之廣夏
日期:2016-06-03 15:58:212016科比退役紀(jì)念章
日期:2016-07-28 17:42:5215-16賽季CBA聯(lián)賽之廣東
日期:2017-02-20 23:32:43
2 [報(bào)告]
發(fā)表于 2016-03-30 10:21 |只看該作者
BiscuitOS 上輕松使用紅黑樹(shù)

紅黑樹(shù)作為 Linux 內(nèi)核重要的數(shù)據(jù)結(jié)構(gòu),負(fù)責(zé) Linux 的基本運(yùn)作,其重要程度和難易程度讓人望而卻步。
本節(jié)通過(guò)一個(gè)簡(jiǎn)單例子介紹紅黑樹(shù)在 BiscuitOS 以及 Linux 內(nèi)核中的使用方法。

紅黑樹(shù)在 Linux 內(nèi)核很多地方都有使用,比如進(jìn)程調(diào)度的“完全公平調(diào)度”,虛擬空間對(duì)進(jìn)程地址管理以及本章重點(diǎn)例子 vmalloc 內(nèi)存區(qū)的管理。
紅黑樹(shù)由于其復(fù)雜的構(gòu)成,這里不過(guò)多講理論,本章側(cè)重講述如何使用紅黑樹(shù)。

1. 紅黑樹(shù) API
rb_link_node 將紅黑樹(shù)節(jié)點(diǎn)插入到紅黑樹(shù)。
rb_insert_color 紅黑樹(shù)翻轉(zhuǎn)顏色
rb_erase 從紅黑樹(shù)中移除一個(gè)節(jié)點(diǎn)
rb_first 獲得紅黑樹(shù)的第一個(gè)節(jié)點(diǎn)
rb_next 獲得紅黑樹(shù)節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)

2. 紅黑樹(shù)在內(nèi)核中的使用案例
VMALLOC 分配的虛擬地址通過(guò)紅黑樹(shù)進(jìn)行管理,我們可以通過(guò)紅黑樹(shù)的 root 和虛擬地址大小來(lái)查找 VMALLOC 區(qū)的內(nèi)容。
代碼如下:(源碼位置 /BiscuitOS/tools/TestCase_vmalloc.c)
  1.     void TestCase_vmalloc(void)
  2.     {
  3.             unsigned int addr;
  4.             struct rb_node *node;

  5.             addr = vmalloc(PAGE_SIZE);

  6.             addr = vmalloc(PAGE_SIZE);

  7.             addr = vmalloc(PAGE_SIZE);
  8.            
  9.             addr = vmalloc(PAGE_SIZE);
  10.            

  11.             /* Trave all node */
  12.             for(node = rb_first(&vmap_area_root) ; node ; node = rb_next(node)) {
  13.                     struct vmap_area *va;
  14.                     struct vm_struct *area;

  15.                     va = rb_entry(node,struct vmap_area,rb_node);
  16.                     area = va->private;
  17.                     printk(KERN_INFO "VA %p\n",(void *)(unsigned long)va->va_start);
  18.               }
  19.            
  20.             vfree(addr);
  21.     }
復(fù)制代碼
3. 紅黑樹(shù)的使用案例。
(源碼位置 /BiscuitOS/tools/TestCase_RB_tree.c)
  1. #include "linux/kernel.h"
  2. #include "linux/rbtree.h"
  3. #include "linux/debug.h"
  4. #include "linux/mm.h"
  5. #include "linux/gfp.h"
  6. #include "linux/slab.h"

  7. struct node {
  8.         struct rb_node node;
  9.         int num;
  10. };


  11. /*
  12. * Insert a node into RBtree.
  13. */
  14. int insert(struct node *data,struct rb_root *root)
  15. {
  16.         struct rb_node **link = &(root->rb_node);
  17.         struct rb_node *parent = NULL;

  18.         while(*link) {
  19.                 struct node *node = container_of(*link,struct node,node);

  20.                 parent = *link;
  21.                 if(data->num < node->num)
  22.                         link = &((*link)->rb_left);
  23.                 else if(data->num > node->num)
  24.                         link = &((*link)->rb_right);
  25.                 else
  26.                         return -1;
  27.         }
  28.         rb_link_node(&data->node,parent,link);
  29.         rb_insert_color(&data->node,root);
  30.         return 0;
  31. }

  32. /*
  33. * Search a node from RBtree.
  34. */
  35. struct node *search(int num,struct rb_root *root)
  36. {
  37.         struct rb_node *node = root->rb_node;

  38.         while(node) {
  39.                 struct node *data = container_of(node,struct node,node);

  40.                 if(num < data->num)
  41.                         node = node->rb_left;
  42.                 else if(num > data->num)
  43.                         node = node->rb_right;
  44.                 else
  45.                         return data;
  46.         }
  47.         return NULL;
  48. }

  49. /*
  50. * Delete a node from RBtree.
  51. */
  52. void delete(int num,struct rb_root *root)
  53. {
  54.         struct node *node = search(num,root);

  55.         if(node) {
  56.                 rb_erase(&node->node,root);
  57.                 kfree(node);
  58.         } else
  59.                 mm_err("%2d doesn't exits\n",num);
  60. }

  61. /*
  62. * Print all node
  63. */
  64. void print_all(struct rb_root *root)
  65. {
  66.         struct rb_node *node;

  67.         for(node = rb_first(root) ; node ; node = rb_next(node))
  68.                 mm_debug("%2d  ",rb_entry(node,struct node,node)->num);

  69.         mm_debug("\n");
  70. }

  71. /*
  72. * TestCase_RB_user
  73. */
  74. void TestCase_RB_user(void)
  75. {
  76.         struct rb_root root = RB_ROOT;
  77.         struct node *node;
  78.         int num,i,ret;
  79.         int value[30] = { 2  , 84 , 43 , 11 , 7  , 54 , 21 , 1  , 2  , 10 ,
  80.                           34 , 5  , 6  , 45 , 76 , 0  , 12 , 25 , 44 , 11 ,
  81.                           99 , 65 , 38 , 91 , 35 , 16 ,93  , 74 , 33 , 67 };

  82.         num = 30;

  83.         for(i = 0 ; i < num ; i++) {
  84.                 node = (struct node *)kmalloc(sizeof(struct node),GFP_KERNEL);
  85.                 if(!node) {
  86.                         mm_err("No Memory\n");

  87.                         /* Never Waste memory */
  88.                         for(i-- ; i >= 0 ; i--)
  89.                                 delete(value[i],&root);

  90.                         return;
  91.                 }

  92.                 node->num = value[i];

  93.                 /* Insert node into RBtree */
  94.                 ret = insert(node,&root);
  95.                 if(ret < 0) {
  96.                         mm_err("%2d has existed\n",node->num);
  97.                         kfree(node);
  98.                 }
  99.         }

  100.         mm_debug("First Check\n");
  101.         print_all(&root);

  102.         /* Delete a node */
  103.         delete(value[4],&root);
  104.         mm_debug("Second Check [%d]\n",value[4]);
  105.         print_all(&root);

  106.         /* Search a node */
  107.         node = search(value[2],&root);
  108.         mm_debug("Find %d\n",node->num);

  109.     /* Get prev node */
  110.         mm_debug("Prev num is %d\n",
  111.                         rb_entry(rb_prev(&node->node),struct node,node)->num);
  112.         /* Get next node */
  113.         mm_debug("Next num is %d\n",
  114.                         rb_entry(rb_next(&node->node),struct node,node)->num);
  115.         /* The first node */
  116.         mm_debug("Min num is %d\n",
  117.                         rb_entry(rb_first(&root),struct node,node)->num);
  118.         /* The last node */
  119.         mm_debug("Max num is %d\n",
  120.                         rb_entry(rb_last(&root),struct node,node)->num);

  121.         /* Free All node */
  122.         for(i = 0 ; i < num ; i++)
  123.                 delete(value[i],&root);

  124.         mm_debug("Last Check\n");
  125.         print_all(&root);
  126. }
復(fù)制代碼
您需要登錄后才可以回帖 登錄 | 注冊(cè)

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號(hào)-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號(hào):11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報(bào)專區(qū)
中國(guó)互聯(lián)網(wǎng)協(xié)會(huì)會(huì)員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過(guò)ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請(qǐng)注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP