在两个逻辑 CPU 之间共享 TLB 条目 (Intel)

2024-02-21

我想知道当属于同一程序且具有相同PCID的两个线程被安排在同一物理CPU上运行时是否可以共享TLB条目?

我已经研究过SDM(https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html);第3115页(TLB和HT)没有提到任何共享机制。但文档的另一部分指出,在访问 TLB 条目之前,会检查 PCID 值,如果相等,则使用该值。然而,在 PCID 标识符旁边还有一个用于当前线程集的位。

我的问题:PCID 值的使用优先级高于 CPU 线程位,还是两个值必须匹配?


根据我的观察,这是不可能的(至少对于dTLB),尽管它会带来性能优势。

我是如何得出这个结论的

按照 Peter 的建议,我编写了一个小程序,其中包含两个反复访问同一堆区域的工作线程。

编译用-O0以防止优化。

#define _GNU_SOURCE
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <inttypes.h>
#include <err.h>
#include <sched.h>
#include <sys/mman.h>

#define PAGE_SIZE 4096

int repetitions = 1ll << 20;
uint64_t ptrsize = 1ll<<18;
uint64_t main_cpu, co_cpu ;

void pin_task_to(int pid, int cpu)
{
    cpu_set_t cset;
    CPU_ZERO(&cset);
    CPU_SET(cpu, &cset);
    if (sched_setaffinity(pid, sizeof(cpu_set_t), &cset))
        err(1, "affinity");
}
void pin_to(int cpu) { pin_task_to(0, cpu); }


void *foo(void *p)
{
    pin_to(main_cpu);

    int value;
    uint8_t *ptr = (uint8_t *)p;
    printf("Running on CPU: %d\n", sched_getcpu());
    for (size_t j = 0; j < repetitions; j++)
    {
        for (size_t i = 0; i < ptrsize; i += PAGE_SIZE)
        {
            value += ptr[i];
        }
    }
    volatile int dummy = value;
    pthread_exit(NULL);
}

void *boo(void *p)
{
    pin_to(co_cpu);

    int value;
    uint8_t *ptr = (uint8_t *)p;
    printf("Running on CPU: %d\n", sched_getcpu());
    for (size_t j = 0; j < repetitions; j++)
    {
        for (size_t i = 0; i < ptrsize; i+=PAGE_SIZE)
        {
            value += ptr[i];
        }
    }
    volatile int dummy = value;
    pthread_exit(NULL);
}

int main(int argc, char **argv)
{
    if (argc < 3){
        exit(-1);
    }
    main_cpu = strtoul(argv[1], NULL, 16);
    co_cpu = strtoul(argv[2], NULL, 16);
    pthread_t id[2];
    void *mptr = malloc(ptrsize);

    pthread_create(&id[0], NULL, foo, mptr);
    pthread_create(&id[1], NULL, boo, mptr);

    pthread_join(id[0], NULL);
    pthread_join(id[1], NULL);
}

我决定将内存区域中的所有值相加(显然,value会溢出)来阻止CPU进行微架构优化。

[另一个想法是简单地逐字节取消引用内存区域并将值加载到RAX]

我们回顾一下内存区域repetitions次,以减少一次运行中由于线程和其他进程的启动时间略有不同以及系统上的中断而引起的噪音。

Results

我的机器有四个物理核心和八个逻辑核心。逻辑核心 x 和 x+4 位于同一物理核心 (lstopo)。

CPU:英特尔酷睿i5 8250u

在同一逻辑核心上运行

由于内核使用 PCID 来识别 TLB 条目,因此到其他线程的上下文切换不应使 TLB 无效。

> $ perf stat -e dtlb_load_misses.stlb_hit,dtlb_load_misses.miss_causes_a_walk,cycles,task-clock ./main 1 1
Running on CPU: 1
Running on CPU: 1

 Performance counter stats for './main 1 1':

        12,621,724      dtlb_load_misses.stlb_hit:u #   49.035 M/sec
             1,152      dtlb_load_misses.miss_causes_a_walk:u #    4.475 K/sec
       834,363,092      cycles:u                  #    3.241 GHz
            257.40 msec task-clock:u              #    0.997 CPUs utilized

       0.258177969 seconds time elapsed

       0.258253000 seconds user
       0.000000000 seconds sys

在两个不同的物理核心上运行

没有任何 TLB 共享或干扰。

> $ perf stat -e dtlb_load_misses.stlb_hit,dtlb_load_misses.miss_causes_a_walk,cycles,task-clock ./main 1 2
Running on CPU: 1
Running on CPU: 2

 Performance counter stats for './main 1 2':

        11,740,758      dtlb_load_misses.stlb_hit:u #   45.962 M/sec
             1,647      dtlb_load_misses.miss_causes_a_walk:u #    6.448 K/sec
       834,021,644      cycles:u                  #    3.265 GHz
            255.44 msec task-clock:u              #    1.991 CPUs utilized

       0.128304564 seconds time elapsed

       0.255768000 seconds user
       0.000000000 seconds sys

在同一个物理核心上运行

如果 TLB 共享是可能的,我希望这里有最低的sTLB点击率和数量较少dTLB页面行走。但相反,我们在这两种情况下的数量都是最多的。

> $ perf stat -e dtlb_load_misses.stlb_hit,dtlb_load_misses.miss_causes_a_walk,cycles,task-clock ./main 1 5
Running on CPU: 1
Running on CPU: 5

 Performance counter stats for './main 1 5':

       140,040,429      dtlb_load_misses.stlb_hit:u #  291.368 M/sec
           198,827      dtlb_load_misses.miss_causes_a_walk:u #  413.680 K/sec
     1,596,298,827      cycles:u                  #    3.321 GHz
            480.63 msec task-clock:u              #    1.990 CPUs utilized

       0.241509701 seconds time elapsed

       0.480996000 seconds user
       0.000000000 seconds sys

结论

正如你所看到的,我们拥有最多的sTLB点击率和dTLB在同一物理核心上运行时页面遍历。因此,我认为同一物理核心上的同一 PCID 不存在共享机制。在同一逻辑核心和两个不同的物理核心上运行该进程会导致 sTLB 的未命中/命中数量大致相同。这进一步支持了以下论点:同一逻辑核心上存在共享,但物理核心上不存在共享。

Update

正如 Peter 所建议的,还可以使用链表方法来防止 THP 和预取。修改后的数据如下所示。

编译用-O0防止优化

#define _GNU_SOURCE
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <inttypes.h>
#include <err.h>
#include <sched.h>
#include <time.h>
#include <sys/mman.h>

#define PAGE_SIZE 4096

const int repetitions = 1ll << 20;
const uint64_t ptrsize = 1ll<< 5;
uint64_t main_cpu, co_cpu ;

void pin_task_to(int pid, int cpu)
{
    cpu_set_t cset;
    CPU_ZERO(&cset);
    CPU_SET(cpu, &cset);
    if (sched_setaffinity(pid, sizeof(cpu_set_t), &cset))
        err(1, "affinity");
}
void pin_to(int cpu) { pin_task_to(0, cpu); }


void *foo(void *p)
{
    pin_to(main_cpu);

    uint64_t *value;
    uint64_t *ptr = (uint64_t *)p;
    printf("Running on CPU: %d\n", sched_getcpu());
    for (size_t j = 0; j < repetitions; j++)
    {
        value = ptr;
        for (size_t i = 0; i < ptrsize; i++)
        {
            value = (uint64_t *)*value;
        }
    }
    volatile uint64_t *dummy = value;
    pthread_exit(NULL);
}

void *boo(void *p)
{
    pin_to(co_cpu);

    uint64_t *value;
    uint64_t *ptr = (uint64_t *)p;
    printf("Running on CPU: %d\n", sched_getcpu());
    for (size_t j = 0; j < repetitions; j++)
    {
        value = ptr;
        for (size_t i = 0; i < ptrsize; i++)
        {
            value = (uint64_t *)*value;
        }
    }
    volatile uint64_t *dummy = value;
    pthread_exit(NULL);
}

int main(int argc, char **argv)
{
    if (argc < 3){
        exit(-1);
    }
    srand(time(NULL));

    uint64_t *head,*tail,*tmp_ptr;
    int r;
    head = mmap(NULL,PAGE_SIZE,PROT_READ|PROT_WRITE,MAP_PRIVATE | MAP_ANONYMOUS,0,0);
    tail = head;
    for (size_t i = 0; i < ptrsize; i++)
    {
        r = (rand() & 0xF) +1;
        // try to use differents offset to the next page to prevent microarch prefetching
        tmp_ptr = mmap(tail-r*PAGE_SIZE, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
        *tail = (uint64_t)tmp_ptr;
        tail = tmp_ptr;
    }

    printf("%Lx, %lx\n", head, *head);
    main_cpu = strtoul(argv[1], NULL, 16);
    co_cpu = strtoul(argv[2], NULL, 16);
    pthread_t id[2];

    pthread_create(&id[0], NULL, foo, head);
    pthread_create(&id[1], NULL, boo, head);

    pthread_join(id[0], NULL);
    pthread_join(id[1], NULL);
}

相同的逻辑核心

> $ perf stat -e dtlb_load_misses.stlb_hit,dtlb_load_misses.miss_causes_a_walk,cycles,task-clock ./main 1 1                                 
7feac4d90000, 7feac4d5b000
Running on CPU: 1
Running on CPU: 1

 Performance counter stats for './main 1 1':

             3,696      dtlb_load_misses.stlb_hit:u #   11.679 K/sec
               743      dtlb_load_misses.miss_causes_a_walk:u #    2.348 K/sec
       762,856,367      cycles:u                  #    2.410 GHz
            316.48 msec task-clock:u              #    0.998 CPUs utilized

       0.317105072 seconds time elapsed

       0.316859000 seconds user
       0.000000000 seconds sys

不同的物理核心

> $ perf stat -e dtlb_load_misses.stlb_hit,dtlb_load_misses.miss_causes_a_walk,cycles,task-clock ./main 1 2                                 
7f59bb395000, 7f59bb34d000
Running on CPU: 1
Running on CPU: 2

 Performance counter stats for './main 1 2':

            15,144      dtlb_load_misses.stlb_hit:u #   49.480 K/sec
               756      dtlb_load_misses.miss_causes_a_walk:u #    2.470 K/sec
       770,800,780      cycles:u                  #    2.518 GHz
            306.06 msec task-clock:u              #    1.982 CPUs utilized

       0.154410840 seconds time elapsed

       0.306345000 seconds user
       0.000000000 seconds sys

相同的物理核心/不同的逻辑核心

> $ perf stat -e dtlb_load_misses.stlb_hit,dtlb_load_misses.miss_causes_a_walk,cycles,task-clock ./main 1 5                                 
7f7d69e8b000, 7f7d69e56000
Running on CPU: 5
Running on CPU: 1

 Performance counter stats for './main 1 5':

         9,237,992      dtlb_load_misses.stlb_hit:u #   20.554 M/sec
               789      dtlb_load_misses.miss_causes_a_walk:u #    1.755 K/sec
     1,007,185,858      cycles:u                  #    2.241 GHz
            449.45 msec task-clock:u              #    1.989 CPUs utilized

       0.225947522 seconds time elapsed

       0.449813000 seconds user
       0.000000000 seconds sys
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在两个逻辑 CPU 之间共享 TLB 条目 (Intel) 的相关文章

  • 我如何使其解密而不是加密?

    想知道如何从加密代码中获取此代码并使用相同的代码来创建解密 我知道这意味着我必须反转一些指令并重新排序 但我无法弄清楚哪些指令需要重新排序 哪些不需要 编辑 这是完整的函数 可以让事情变得更清晰一些 对堆栈溢出非常陌生 因此对于任何混淆表示
  • 早期的BIOS怎么能使用CALL呢?

    我纯粹是出于爱好原因 试图理解 PC 中的一些低级代码 我为随机的旧千兆字节 MB 下载了一个过时的 BIOS ROM 映像 https www gigabyte com Motherboard GA 8I845GE775 G rev 10
  • x86 汇编中 cmove 指令的用途?

    反汇编可执行文件时我遇到了cmove操作说明 我已经在互联网上搜索过 但我只发现这是一个有条件的移动 如果源和目的地相等mov发生 我还不明白为什么我需要它 因为它不会改变操作数 它的目的是什么 The CMOVcc指令不比较源和目标 它们
  • C#:TurboBoost 激活时如何获取 Intel i 系列 CPU 的当前时钟速度

    我知道有可能获得此信息 Intel 自己的 TurboBoost 侧边栏小工具似乎使用 ActiveX 控件来确定 TurboBoost 处于活动状态时 i3 i5 i7 CPU 的当前时钟速度 但是 我想在 C 中以编程方式执行此操作 从
  • 如何禁用浮点单元(FPU)?

    我想在 x86 系统中禁用 FPU MMX SSE 指令 并且我将为设备不可用异常实现一个处理程序 我已经提到过控制寄存器 wiki 页面 http en wikipedia org wiki Control register 看来我必须在
  • gcc 如何知道内联汇编中使用的寄存器大小?

    我有内联汇编代码 define read msr index buf asm volatile rdmsr d buf 1 a buf 0 c index 使用该宏的代码 u32 buf 2 read msr 0x173 buf 我发现反汇
  • 编写 AMD64 SysV 程序集时使用哪些寄存器作为临时寄存器?

    我正在使用实现一个功能cpuid根据 AMD64 SysV ABI 进行组装 我需要在函数本身中使用 2 个临时寄存器 第一个用于累积返回值 第二个用作计数器 我的功能目前如下所示 zero argument function some c
  • 为什么这个“std::atomic_thread_fence”起作用

    首先我想谈一下我对此的一些理解 如有错误请指正 a MFENCE在x86中可以保证全屏障 顺序一致性可防止 STORE STORE STORE LOAD LOAD STORE 和 LOAD LOAD 重新排序 这是根据维基百科 https
  • 一条指令可以同时处于两种寻址模式吗?

    我在书中读到了以下内容从头开始编程 处理器有多种不同的访问数据的方式 称为 寻址模式 最简单的模式是立即模式 其中 要访问的数据嵌入在指令本身中 例如 如果我们想将寄存器初始化为 0 而不是给出 计算机要从中读取 0 的地址 我们将指定立即
  • 预取双类成员需要转换为 char*?

    我有一个正在使用的课程 mm prefetch 预先请求包含 double 类型的类成员的缓存行 class MyClass double getDouble return dbl other members double dbl othe
  • CPU缓存:两个地址之间的距离是否需要小于8字节才能具有缓存优势?

    这似乎是一个奇怪的问题 假设缓存行的大小为 64 字节 此外 假设 L1 L2 L3 具有相同的缓存行大小 this https stackoverflow com a 15333156 8385554帖子说英特尔酷睿 i7 就是这种情况
  • 在 x86 Intel VT-X 非根模式下,是否可以在每个指令边界传递中断?

    除了不将中断传送到虚拟处理器的某些正常指定条件 cli if 0 等 之外 客户机中的所有指令实际上都是可中断的吗 也就是说 当传入的硬件中断先传递给 LAPIC 然后传递给处理器时 据说会发生一些内部魔法 将其转换为虚拟中断给来宾 使用虚
  • CPU是如何做减法的?

    我有一些基本的疑问 但每次我坐下来尝试面试问题时 这些问题和我的疑问就会出现 假设 A 5 B 2 假设A和B都是4字节 那么CPU是怎么做的呢 A B添加 我知道 A 的符号位 MSB 为 0 表示正值 B 的符号位为 1 表示负整数 现
  • 在 x86 ASM 中测试零通常哪个更快:“TEST EAX, EAX”与“TEST AL, AL”?

    测试 AL 中的字节是否为零 非零通常哪个更快 TEST EAX EAX TEST AL AL 假设之前有一个 MOVZX EAX BYTE PTR ESP 4 指令加载了一个带有零扩展的字节参数到 EAX 的其余部分 防止了我已经知道的组
  • Intel 64 和 IA-32 上的 MESI 有何意义

    MESI 的要点是保留共享内存系统的概念 然而 对于存储缓冲区 事情就变得复杂了 一旦数据到达 MESI 实现的缓存 下游内存就会保持一致 然而 在此之前 每个核心可能对内存位置 X 中的内容存在分歧 具体取决于每个核心的本地存储缓冲区中的
  • 大会,你好世界问题

    我正在 Linux 上学习 asm noobuntu 10 04 我得到了以下代码 http asm sourceforge net intro hello html http asm sourceforge net intro hello
  • 我们如何计算这段代码片段中缓存的读取/未命中次数?

    鉴于我目前正在学习的这本教科书中的代码片段 Randal E Bryant David R O Hallaron 计算机系统 程序员的视角 第 3 版 2016 年 Pearson 全球版 因此本书的练习可能是错误的 for i 31 i
  • 为什么 FMA _mm256_fmadd_pd() 内在函数有 3 个 asm 助记符:“vfmadd132pd”、“231”和“213”?

    有人可以向我解释一下为什么融合乘法累加指令有 3 种变体 vfmadd132pd vfmadd231pd and vfmadd213pd 而只有一个 C 内在函数 mm256 fmadd pd 为了简单起见 在 AT T 语法中 有什么区别
  • 缓存一致性是否始终可以防止读取过时的值?失效队列允许吗?

    在 MESI 协议中 仅当将缓存行保持在独占 修改状态时才写入缓存行 要获取独占状态 您可以向持有同一高速缓存行的所有核心发送无效请求 但是是否存在一种微架构 其中某些内核会在实际使缓存线无效之前做出确认响应 如果确实如此 那不是违反了缓存
  • 为什么我的代码显示垃圾?

    当我也想打印列表中的每个数字时 我的代码显示垃圾 有什么问题吗 输出应如下所示 给定的数组是 2G 4 PT为什么这是垃圾总数是 7 Code ASSUME CS CODE DS DATA SS STK ORG 0000H DATA SEG

随机推荐

  • 从 Chrome 94+ 与不支持 HTTPS 的 LAN 设备通过网络应用程序进行通信

    我们开发了一个 Web 应用程序 通过发送 POST 请求与连接到同一 LAN 的打印机进行通信 此类打印机有一个在端口 80 上打开的服务器 该服务器接受包含命令的 XML 无法从通过 HTTPS 加载的页面与网络设备进行通信 因此 我们
  • 调用 SaveChanges() 时排除更新属性

    似乎有两种方法可以使用 附加 方法来更新断开连接的实体框架实体 方法一是简单地将断开连接的实体的状态设置为已修改 myDbContext Dogs Attach dog myDbContext Entry dog State EntityS
  • 如何在C#中枚举音频输出设备

    我想知道如何获取计算机上已安装的音频输出设备 waveOut 的列表 操作系统 Windows XP Vista 7 框架 Net 3 5 语言 c 迭代此列表时 我想获取每个设备的标识符 制造商等信息 有什么提示吗 下面是使用 WMI 参
  • JSP 组件创建

    创建 JSP 页面时 我经常喜欢的一件事是能够执行以下操作
  • Gulp 伊斯坦布尔完整覆盖报告

    我正在使用 gulp istanbul 通过 Gulp 生成 JavaScript 单元测试覆盖率报告 有没有办法配置 Istanbul 以生成我的 gulp 流中所有 JS 文件的完整覆盖率报告 而不仅仅是测试用例涉及的文件 我正在开发一
  • main 函数不返回任何内容。为什么? [复制]

    这个问题在这里已经有答案了 对于 C C main 必须始终返回一个整数 零表示成功 非零表示失败 我可以理解这一点 因为程序运行时它成为一个进程 每个进程都应该有一个退出状态 我们通过执行 echo 获得退出状态 进程结束后从 shell
  • 如何在 git 中找到 origin/master 的位置,以及如何更改它?

    我是 Git 新手 我最近将一个 Rails 项目从 Subversion 迁移到了 Git 我按照这里的教程进行操作 http www simplisticcomplexity com 2008 03 05 cleanly migrate
  • 如何创建像所附照片一样的用户界面

    谁能告诉我这个照片效果叫什么 我想知道如何为这个附加的图像效果创建一个适配器 编辑 这是Android市场的示例照片 我想创建一个这样的布局 我想这应该覆盖 GridView 适配器 肖像截图 风景截图 另一张截图 我非常抱歉我的问题对你们
  • 如何使用 Google Colab 安装 vizdoom?

    我正在关注本教程 https github com simoninithomas Deep reinforcement learning Course blob master Policy 20Gradients Doom Doom 20R
  • Matlab 箱线图属性

    I m trying to plot this box plot like this 我尝试了这段代码 boxplot randn 10 98 notch on set 0 DefaultAxesFontName Cambria Math
  • Heroku Rails Net::HTTP: OpenSSL::SSL::SSLError: SSL_connect 返回=1 errno=0 状态=SSLv3 读取服务器证书 B: 证书验证失败

    我有一个在 Heroku 服务器上运行的 Rails 应用程序 但我在使用 Net HTTP over HTTPS 与外部服务器通信时遇到问题 每当我尝试时收到的错误POST通过 HTTPS 到外部专有 API 的方法是 OpenSSL S
  • 为什么我的小型大写字体变体 CSS 类被忽略?

    我添加了这个 CSS 类 beanies font variant small caps 我从几个地方调用它 再加上另一个类 以这种方式尝试 p class coolPools beanies LICENSE 764014 p 和这个 h3
  • 列数会影响MYSQL的速度吗?

    我有一张桌子 我只需要运行一种类型的查询 在第 1 列中查找给定的唯一值 然后获取前 3 列 现在 如果我在表中添加额外的几列以进行基本的 数据存储 会对速度产生多大影响 我知道我应该使用一个单独的表 但假设我仅限于只有 1 个表 所以唯一
  • 将 MapReduce 作业的输出记录到文本文件

    我一直在使用这个 jobclient monitorandprintjob 方法将映射缩减作业的输出打印到控制台 我的用法是这样的 job client monitorAndPrintJob job conf job client getJ
  • python 通过通配符复制文件

    我正在学习 python python 3 我可以将 1 个文件复制到新目录 通过做这个 import shutil shutil copyfile C test test txt C lol test txt 我现在想做的是将所有 txt
  • Elixir:修改模块属性值

    是否有可能实现以下行为 其中尝试更改模块属性的值以改变模块方法的行为 defmodule Adder do num to add 10 def addTo input do input num to add end IO inspect A
  • 重新签署包含框架的 IPA

    我正在重新签名 iOS 应用程序 使用 iResign 以便将其上传到 App Store 作为其中的一部分 我正在更改捆绑包 ID 我只有 IPA 没有源代码 该应用程序包含第三方框架 辞职似乎进展顺利 但是当我使用应用程序加载器上传时
  • application.properties中的spring boot .env变量

    我已经创建了 env 文件 我现在在其中保存变量 我希望它们在我的 application properties 中定义 但这不起作用 我需要添加什么来获取变量 env 文件 MYSQLDB USER root MYSQLDB ROOT P
  • TopoJSON 属性保留

    我正在使用 topojson 转换现有的 GeoJSON 数据集 但它不保留属性 它遵循标准 GeoJSON 格式 并将属性放置在与几何图形同一级别的 属性 对象中 下面的片段 但是当 topojson 成功完成时 我最终会得到一个可以使用
  • 在两个逻辑 CPU 之间共享 TLB 条目 (Intel)

    我想知道当属于同一程序且具有相同PCID的两个线程被安排在同一物理CPU上运行时是否可以共享TLB条目 我已经研究过SDM https www intel com content www us en developer articles t