Linux X86, testing TLB Flush

之前提到了PCID的引入目的在于优化TLB flush的场景,从而提到系统性能。这里主要搞一个测试,用以验证以下几个方面。

验证TLB的有效(functionality)。

TLB Flush的作用(functionality)。

Flush TLB的方法。

具体而言,这里需要一个内核模块来完成上述操作,不需要用户态进程。测试的基本操作如下。

分配一个内存页kaddress_1,写入11H。

分配一个内存页kaddress_2,写入22H。

修改kaddress_1对应的页表项,使其指向kaddress2对应的页。

Flush kaddress_1所对应的TLB,再次读取kaddress_1,应该读到22H。

恢复kaddress_1之前的页表项,不flush TLB,读取的仍然是22H,这说明TLB在工作,页表是命中了TLB中的缓存,所以读取的还是步骤3当中的页的内容。

Flush TLB,再次读取kaddress_1,这次返回时11H,说明TLB flush有效。

完成上述操作的代码如下。

int test_main(u64 sym_addr)

{

    u64      *kvad1, *kvad2;

    u64        old_val = 0;

    kvad2 = kmalloc(0x1000, GFP_KERNEL);

    if (kvad2 == NULL) {

        printk("Failed to kmalloc, return \n");

        return -ENOMEM;

    }

    printk("kvad2 = %px, phys = %llx\n", kvad2, virt_to_phys(kvad2));

    walk_pagetable((u64)kvad2, my_swapper_pg_dir);

    memset(kvad2, 0x22, 0x10);

    kvad1 = kmalloc(0x1000, GFP_KERNEL);

    if (kvad1) {

        printk("kvad1 = %px, phys = %llx\n", kvad1, virt_to_phys(kvad1));

        walk_pagetable((u64)kvad1, my_swapper_pg_dir);

        memset(kvad1, 0x11, 0x10);

        old_val = virt_to_phys(kvad1);

        update_pte(my_swapper_pg_dir, (u64)kvad1, virt_to_phys(kvad2));

        printk("Changed the PTE, and dumping the new page table\n");

        walk_pagetable((u64)kvad1, my_swapper_pg_dir);

        printk("Flushed cache, read the data\n");

        clflush((u64 *)kvad1);

        printk("kvad1[0] = %llx\n", *(u64 *)kvad1);

        flush_tlb((void *)kvad1);

        printk("Flushed TLB,  read the data = %llx\n", *(u64 *)kvad1);

        // Now change back to the old pte value.

        printk("Restored the Old PTE, w/o flushing tlb\n");

        update_pte(my_swapper_pg_dir, (u64)kvad1, old_val);

        printk("A: kvad1[0]=%llx, kvad2[0]=%llx\n", *kvad1, *kvad2);

        flush_tlb(kvad1);

        printk("Flushed TLB\n");

        printk("B: kvad1[0]=%llx, kvad2[0]=%llx\n", *kvad1, *kvad2);

        kfree(kvad1);

    }

    kfree(kvad2);

    return 0;

}

kernel log显示了测试结果,如下

[764666.408725] Changed the PTE, and dumping the new page table

[764666.408725] ================  Walking page table  ==================

[764666.408725] Vaddr is = 0xffff97a465c0b000

[764666.408726] PGD = 0x2ec40a000

[764666.408726]  PGD [12f] (V: 0x00000000eb103258 P: 0x2ec40a978) = 0x2ecb64067

[764666.408727]  PUD [091] (V: 0x00000000d7a343ca P: 0x2ecb64488) = 0x42d261063. P=1

[764666.408727]  PMD [12e] (V: 0x00000000bf1731a6 P: 0x42d261970) = 0x421abb063. P=1

[764666.408728]  PTE [00b] (V: 0x00000000cdc9f88c P: 0x421abb058) = 0x8000000425c0c063. P=1

[764666.408728] PTE --> page 0x425c0c000

[764666.408729] Flushed cache, read the data

[764666.408729] kvad1[0] = 1111111111111111

[764666.408730] Flushing TLB by reloading CR3 (non global page). 41e772004

[764666.408731] Writing CR3 takes 342 cycles

[764666.408731] Flushed TLB,  read the data = 2222222222222222

[764666.408732] Restored the Old PTE, w/o flushing tlb

                Done

[764666.408733] A: kvad1[0]=2222222222222222, kvad2[0]=2222222222222222

[764666.408734] Flushing TLB by reloading CR3 (non global page). 41e772004

[764666.408735] Writing CR3 takes 327 cycles

[764666.408735] Flushed TLB

[764666.408736] B: kvad1[0]=1111111111111111, kvad2[0]=2222222222222222

以上就是一个针对TLB和TLB flush的测试,从这个测试当中可以验证TLB的功能,以及TLB flush的功能。

下一篇讲一下Intel的TurboBoost,同样的,还是耳听为虚,实操为实,通过具体的测试来看一下Intel的动态变频是怎么工作的。

你可能感兴趣的:(Linux X86, testing TLB Flush)