美文网首页
Linux X86, testing TLB Flush

Linux X86, testing TLB Flush

作者: simitel | 来源:发表于2020-07-27 11:41 被阅读0次

    之前提到了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

          本文链接:https://www.haomeiwen.com/subject/thczlktx.html