- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想知道如果属于同一个程序的两个具有相同 PCID 的线程在被安排在同一个物理 CPU 上运行时是否可以共享 TLB 条目?
我已经研究过 SDM ( 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
次以减少一次运行中由于线程和其他进程的启动时间略有不同以及系统中断而引起的噪音。
我的机器有四个物理内核和八个逻辑内核。逻辑核心 x 和 x+4 位于同一个物理核心 (lstopo)。
中央处理器:英特尔酷睿 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 的未命中/命中次数大致相同。这进一步支持了在同一逻辑内核上共享但在物理内核上不共享的论点。
正如 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
关于x86 - 在两个逻辑 CPU 之间共享一个 TLB 条目(Intel),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72291786/
我是Intel pin工具的新手,最近开始研究pin工具。在教程中,描述了pin工具的模式: Sometimes, however, it can be useful to look at diffe
我是Intel pin工具的新手,最近开始研究pin工具。在教程中,描述了pin工具的模式: Sometimes, however, it can be useful to look at diffe
我得到了这份工作:1。产生一个正弦信号。2。使用 FFT 构建其频谱。首先,我为 visual studio 2010 安装了 Intel Parallel Studio XE 2011。在 vs 2
看起来 Intel 提供了许多 OpenCL 实现。 ArchWiki描述 OpenCL 实现。它说 beignet 和 intel-opencl 已弃用。那么,intel-compute-runti
我正在尝试通过阅读 Intel Intrinsics Guide 来开始使用 AVX512 内在函数但到目前为止我发现它没有定义命名数据类型或用于解释的伪代码语法。没有这样的定义,所谓的指南对我起码没
关闭。这个问题是opinion-based 。目前不接受答案。 想要改进这个问题吗?更新问题,以便 editing this post 可以用事实和引文来回答它。 . 已关闭 4 年前。 Improv
在 Android SDK 管理器中,我可以看到 3 种类型的 Intel Atom 图像。有人可以解释“Intel Atom Image”、“Google APIs Intel Atom Image
我写了这个 pintool: #include "pin.H" #include #include VOID Instruction(INS ins, VOID *v) { cou
我正在尝试了解 _mm256_permute2f128_ps() 的作用,但无法完全理解 intel's code-example . DEFINE SELECT4(src1, src2, contr
我正在开发一个性能关键应用程序,该应用程序必须移植到仅支持 MMX、SSE、SSE2 和 SSE3 的英特尔凌动处理器中。我以前的应用程序支持 SSSE3 和 AVX,现在我想将其降级为 Intel
我有最新版本的 Intel Pin 3.0 版本 76887。 我有一个支持 MPX 的玩具示例: #include int g[10]; int main(int argc, char **arg
我想研究和比较elf、SPARC和PA-RISC的可执行文件结构。 为了进行研究,我想在 Intel 机器 (Core2Duo) 上安装 OpenSolaris。 但我有一个基本的疑问,它会起作用吗?
我尝试使用 g++ 用 intel mkl 11.1 进行编译: g++ -m32 test.c -lmkl_intel -lmkl_intel_thread -lmkl_core -liomp5 -
我正在按照以下说明进行操作: https://software.intel.com/en-us/articles/building-boost-with-intel-c-compiler-150 Co
我正在尝试在我的 C 程序中使用内联汇编程序 __asm,使用 Intel 语法而不是 AT&T 语法。我正在使用 gcc -S -masm=intel test.c 进行编译但它给出了错误。下面是我
我是 OpenCL 的新手,目前对其性能有一些疑问。 我有 Intel(R) Core(TM) i5-4460 CPU @ 3.20GHz + ubuntu + Beignet(Intel 开源 op
我在/ex 文件夹中有一个 main.f90。 f77 子程序文件在/ex/src 中。子程序文件再次使用 BLAS 和 LAPACK 库。对于 BLAS 和 LAPACK,我必须使用英特尔数学核心函
我的团队最近从 2015 年英特尔编译器(并行工作室)升级到 2018 年版本,我们遇到了一个链接器问题,让每个人都焦头烂额。 我有以下类(为简洁起见进行了适度编辑),用于处理子进程的包装以及与它们对
在最后几天,我观察到我无法解释的新工作站的行为。对这个问题做一些研究,INTEL Haswell architecture 中可能存在一个可能的错误。以及在当前的 Skylake Generation
我的 HAXM 安装存在问题。事情是这样的。每次尝试为我的计算机安装 HAXM 时,我都会收到此错误: 问题是,我的计算机支持虚拟化技术(见下图)。知道如何解决这个问题吗? 最佳答案 只需执行以下步骤
我是一名优秀的程序员,十分优秀!