使用 C/C++ 和 osx 中的内联 assembly/intrinsics 获取缓存信息
Getting cache info using C/C++ with inline assembly/intrinsics in osx
我使用 gcc __get_cpuid
和内联汇编编写了以下程序来获取笔记本电脑的缓存信息,但无法在 table 关于(缓存和 TLB 描述符的编码)中识别它们我在网上找的。
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <time.h>
#include <stdint.h>
#include <math.h>
#include <cpuid.h>
static inline void cpuid(uint32_t *eax, uint32_t *ebx,
uint32_t *ecx, uint32_t *edx);
int main() {
uint32_t a, b, c, d;
uint32_t eax, ebx, ecx, edx;
eax = 2; /* processor info and feature bits */
uint32_t command = 2;
cpuid(&eax, &ebx, &ecx, &edx);
__get_cpuid(command, &a, &b, &c, &d);
printf("eax: %08x\n", eax);
printf("ebx: %08x\n", ebx);
printf("ecx: %08x\n", ecx);
printf("edx: %08x\n", edx);
printf("a: %08x\n", a);
printf("b: %08x\n", b);
printf("c: %08x\n", c);
printf("d: %08x\n", d);
}
static inline void cpuid(uint32_t *eax, uint32_t *ebx,
uint32_t *ecx, uint32_t *edx)
{
/* ecx is often an input as well as an output. */
asm ("cpuid"
: "=a" (*eax),
"=b" (*ebx),
"=c" (*ecx),
"=d" (*edx)
: "0" (*eax));
}
我的输出:
eax: 76036301
ebx: 00f0b5ff
ecx: 00000000
edx: 00c10000
a: 76036301
b: 00f0b5ff
c: 00000000
d: 00c10000
我从 here 中找到了这个 table
我使用 sysctl hw.cachesize
并发现
L1 cache: 32KB
L2 cache: 256KB
L3 cache: 6MB
我的环境:
system: os x 10.10.1
compiler: clang-602.0.53
CPU: I7-4850 HQ 2.3HZ
我的程序有什么问题?我的程序应该可以工作,因为这两种方法都给出相同的结果......我对此感到困惑。谢谢!
编辑:
我尝试了 Mats 的建议并得到以下结果作为我的输出:
gcc intrinsic
a: 76036301
b: 00f0b5ff
c: 00000000
d: 00c10000
eax: 2
eax: 76036301
ebx: 00f0b5ff
ecx: 00000000
edx: 00c10000
eax: 4, ecx: 0
eax: 1c004121
ebx: 01c0003f
ecx: 0000003f
edx: 00000000
eax: 4, ecx: 1
eax: 1c004122
ebx: 01c0003f
ecx: 0000003f
edx: 00000000
eax: 4, ecx: 2
eax: 1c004143
ebx: 01c0003f
ecx: 000001ff
edx: 00000000
eax: 4, ecx: 3
eax: 1c03c163
ebx: 02c0003f
ecx: 00001fff
edx: 00000006
eax: 4, ecx: 4
eax: 1c03c183
ebx: 03c0f03f
ecx: 00001fff
edx: 00000004
eax: 4, ecx: 5
eax: 00000000
ebx: 00000000
ecx: 00000000
edx: 00000000
我在 here
查找 table
静态 cpuid_cache_descriptor_t intel_cpuid_leaf2_descriptor_table[] = {
// -------------------------------------------------------
// value type level ways size entries
// -------------------------------------------------------
{ 0x00, _NULL_, NA, NA, NA, NA },
{ 0x01, TLB, INST, 4, SMALL, 32 },
{ 0x02, TLB, INST, FULLY, LARGE, 2 },
{ 0x03, TLB, DATA, 4, SMALL, 64 },
{ 0x04, TLB, DATA, 4, LARGE, 8 },
{ 0x05, TLB, DATA1, 4, LARGE, 32 },
{ 0x06, CACHE, L1_INST, 4, 8*K, 32 },
{ 0x08, CACHE, L1_INST, 4, 16*K, 32 },
{ 0x09, CACHE, L1_INST, 4, 32*K, 64 },
{ 0x0A, CACHE, L1_DATA, 2, 8*K, 32 },
{ 0x0B, TLB, INST, 4, LARGE, 4 },
{ 0x0C, CACHE, L1_DATA, 4, 16*K, 32 },
{ 0x0D, CACHE, L1_DATA, 4, 16*K, 64 },
{ 0x0E, CACHE, L1_DATA, 6, 24*K, 64 },
{ 0x21, CACHE, L2, 8, 256*K, 64 },
{ 0x22, CACHE, L3_2LINESECTOR, 4, 512*K, 64 },
{ 0x23, CACHE, L3_2LINESECTOR, 8, 1*M, 64 },
{ 0x25, CACHE, L3_2LINESECTOR, 8, 2*M, 64 },
{ 0x29, CACHE, L3_2LINESECTOR, 8, 4*M, 64 },
{ 0x2C, CACHE, L1_DATA, 8, 32*K, 64 },
{ 0x30, CACHE, L1_INST, 8, 32*K, 64 },
{ 0x40, CACHE, L2, NA, 0, NA },
{ 0x41, CACHE, L2, 4, 128*K, 32 },
{ 0x42, CACHE, L2, 4, 256*K, 32 },
{ 0x43, CACHE, L2, 4, 512*K, 32 },
{ 0x44, CACHE, L2, 4, 1*M, 32 },
{ 0x45, CACHE, L2, 4, 2*M, 32 },
{ 0x46, CACHE, L3, 4, 4*M, 64 },
{ 0x47, CACHE, L3, 8, 8*M, 64 },
{ 0x48, CACHE, L2, 12, 3*M, 64 },
{ 0x49, CACHE, L2, 16, 4*M, 64 },
{ 0x4A, CACHE, L3, 12, 6*M, 64 },
{ 0x4B, CACHE, L3, 16, 8*M, 64 },
{ 0x4C, CACHE, L3, 12, 12*M, 64 },
{ 0x4D, CACHE, L3, 16, 16*M, 64 },
{ 0x4E, CACHE, L2, 24, 6*M, 64 },
{ 0x4F, TLB, INST, NA, SMALL, 32 },
{ 0x50, TLB, INST, NA, BOTH, 64 },
{ 0x51, TLB, INST, NA, BOTH, 128 },
{ 0x52, TLB, INST, NA, BOTH, 256 },
{ 0x55, TLB, INST, FULLY, BOTH, 7 },
{ 0x56, TLB, DATA0, 4, LARGE, 16 },
{ 0x57, TLB, DATA0, 4, SMALL, 16 },
{ 0x59, TLB, DATA0, FULLY, SMALL, 16 },
{ 0x5A, TLB, DATA0, 4, LARGE, 32 },
{ 0x5B, TLB, DATA, NA, BOTH, 64 },
{ 0x5C, TLB, DATA, NA, BOTH, 128 },
{ 0x5D, TLB, DATA, NA, BOTH, 256 },
{ 0x60, CACHE, L1, 16*K, 8, 64 },
{ 0x61, CACHE, L1, 4, 8*K, 64 },
{ 0x62, CACHE, L1, 4, 16*K, 64 },
{ 0x63, CACHE, L1, 4, 32*K, 64 },
{ 0x70, CACHE, TRACE, 8, 12*K, NA },
{ 0x71, CACHE, TRACE, 8, 16*K, NA },
{ 0x72, CACHE, TRACE, 8, 32*K, NA },
{ 0x78, CACHE, L2, 4, 1*M, 64 },
{ 0x79, CACHE, L2_2LINESECTOR, 8, 128*K, 64 },
{ 0x7A, CACHE, L2_2LINESECTOR, 8, 256*K, 64 },
{ 0x7B, CACHE, L2_2LINESECTOR, 8, 512*K, 64 },
{ 0x7C, CACHE, L2_2LINESECTOR, 8, 1*M, 64 },
{ 0x7D, CACHE, L2, 8, 2*M, 64 },
{ 0x7F, CACHE, L2, 2, 512*K, 64 },
{ 0x80, CACHE, L2, 8, 512*K, 64 },
{ 0x82, CACHE, L2, 8, 256*K, 32 },
{ 0x83, CACHE, L2, 8, 512*K, 32 },
{ 0x84, CACHE, L2, 8, 1*M, 32 },
{ 0x85, CACHE, L2, 8, 2*M, 32 },
{ 0x86, CACHE, L2, 4, 512*K, 64 },
{ 0x87, CACHE, L2, 8, 1*M, 64 },
{ 0xB0, TLB, INST, 4, SMALL, 128 },
{ 0xB1, TLB, INST, 4, LARGE, 8 },
{ 0xB2, TLB, INST, 4, SMALL, 64 },
{ 0xB3, TLB, DATA, 4, SMALL, 128 },
{ 0xB4, TLB, DATA1, 4, SMALL, 256 },
{ 0xBA, TLB, DATA1, 4, BOTH, 64 },
{ 0xCA, STLB, DATA1, 4, BOTH, 512 },
{ 0xD0, CACHE, L3, 4, 512*K, 64 },
{ 0xD1, CACHE, L3, 4, 1*M, 64 },
{ 0xD2, CACHE, L3, 4, 2*M, 64 },
{ 0xD3, CACHE, L3, 4, 4*M, 64 },
{ 0xD4, CACHE, L3, 4, 8*M, 64 },
{ 0xD6, CACHE, L3, 8, 1*M, 64 },
{ 0xD7, CACHE, L3, 8, 2*M, 64 },
{ 0xD8, CACHE, L3, 8, 4*M, 64 },
{ 0xD9, CACHE, L3, 8, 8*M, 64 },
{ 0xDA, CACHE, L3, 8, 12*M, 64 },
{ 0xDC, CACHE, L3, 12, 1536*K, 64 },
{ 0xDD, CACHE, L3, 12, 3*M, 64 },
{ 0xDE, CACHE, L3, 12, 6*M, 64 },
{ 0xDF, CACHE, L3, 12, 12*M, 64 },
{ 0xE0, CACHE, L3, 12, 18*M, 64 },
{ 0xE2, CACHE, L3, 16, 2*M, 64 },
{ 0xE3, CACHE, L3, 16, 4*M, 64 },
{ 0xE4, CACHE, L3, 16, 8*M, 64 },
{ 0xE5, CACHE, L3, 16, 16*M, 64 },
{ 0xE6, CACHE, L3, 16, 24*M, 64 },
{ 0xF0, PREFETCH, NA, NA, 64, NA },
{ 0xF1, PREFETCH, NA, NA, 128, NA }
};
现在的问题是我仍然无法获得我的三级缓存的正确大小(当 ecx=1 时,我得到 22 即 512K,但正确的值是 6MB)。另外,我的 L2 缓存的大小似乎存在一些冲突(43(当 ecx=2 时)和 21(当 ecx=0 时))
因此,您的数据似乎相当正确,只是您使用的是旧参考。不幸的是,Intel 的网站目前要么已损坏,要么不喜欢 Firefox and/or Linux.
76036301
76 表示具有 64K 操作的跟踪缓存。
03 表示具有 64 个条目的 4 路 DATA TLB。
63 是 32KB 一级缓存 - 来源 here 显示该值,您的文档中没有。
01 表示具有 32 个条目的 4 路指令 TLB。
00f0b5ff 给出
00 "nothing"
f0 预取,64 个条目。
0b 大页面 4 路 TLB 指令,4 个条目。
b5 甚至在 link 上也没有记录。 [猜猜小数据TLB]
要获得 L2 和 L3 缓存大小,您需要使用 EAX=4 的 CPUID,并将每个缓存级别的 ECX 设置为 0、1、2 ...。 linked 代码显示了这一点,英特尔的文档详细说明了哪些位的含义。
Intel's Instruction Set Reference 拥有您需要的所有相关信息(大约在第 263 页),并且实际上是最新的,这与我找到的所有其他来源不同。
该参考资料中可能提到了获取缓存信息的最佳方法。
当eax = 4且ecx为缓存级别时,
Ways = EBX[31:22]
Partitions = EBX[21:12]
LineSize = EBX[11:0]
Sets = ECX
Total Size = (Ways + 1) * (Partitions + 1) * (Line_Size + 1) * (Sets + 1)
所以当调用 CUPID 时 eax = 4 和 ecx = 3,你可以通过上面的计算得到你的 L3 缓存大小。使用 OP 的发布数据:
ebx: 02c0003f
ecx: 00001fff
Ways = 63
Partitions = 0
LineSize = 11
Sets = 8191
L3 缓存总大小 = 6291456
这是预期的结果。
我使用 gcc __get_cpuid
和内联汇编编写了以下程序来获取笔记本电脑的缓存信息,但无法在 table 关于(缓存和 TLB 描述符的编码)中识别它们我在网上找的。
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <time.h>
#include <stdint.h>
#include <math.h>
#include <cpuid.h>
static inline void cpuid(uint32_t *eax, uint32_t *ebx,
uint32_t *ecx, uint32_t *edx);
int main() {
uint32_t a, b, c, d;
uint32_t eax, ebx, ecx, edx;
eax = 2; /* processor info and feature bits */
uint32_t command = 2;
cpuid(&eax, &ebx, &ecx, &edx);
__get_cpuid(command, &a, &b, &c, &d);
printf("eax: %08x\n", eax);
printf("ebx: %08x\n", ebx);
printf("ecx: %08x\n", ecx);
printf("edx: %08x\n", edx);
printf("a: %08x\n", a);
printf("b: %08x\n", b);
printf("c: %08x\n", c);
printf("d: %08x\n", d);
}
static inline void cpuid(uint32_t *eax, uint32_t *ebx,
uint32_t *ecx, uint32_t *edx)
{
/* ecx is often an input as well as an output. */
asm ("cpuid"
: "=a" (*eax),
"=b" (*ebx),
"=c" (*ecx),
"=d" (*edx)
: "0" (*eax));
}
我的输出:
eax: 76036301
ebx: 00f0b5ff
ecx: 00000000
edx: 00c10000
a: 76036301
b: 00f0b5ff
c: 00000000
d: 00c10000
我从 here 中找到了这个 table
我使用 sysctl hw.cachesize
并发现
L1 cache: 32KB
L2 cache: 256KB
L3 cache: 6MB
我的环境:
system: os x 10.10.1
compiler: clang-602.0.53
CPU: I7-4850 HQ 2.3HZ
我的程序有什么问题?我的程序应该可以工作,因为这两种方法都给出相同的结果......我对此感到困惑。谢谢!
编辑: 我尝试了 Mats 的建议并得到以下结果作为我的输出:
gcc intrinsic
a: 76036301
b: 00f0b5ff
c: 00000000
d: 00c10000
eax: 2
eax: 76036301
ebx: 00f0b5ff
ecx: 00000000
edx: 00c10000
eax: 4, ecx: 0
eax: 1c004121
ebx: 01c0003f
ecx: 0000003f
edx: 00000000
eax: 4, ecx: 1
eax: 1c004122
ebx: 01c0003f
ecx: 0000003f
edx: 00000000
eax: 4, ecx: 2
eax: 1c004143
ebx: 01c0003f
ecx: 000001ff
edx: 00000000
eax: 4, ecx: 3
eax: 1c03c163
ebx: 02c0003f
ecx: 00001fff
edx: 00000006
eax: 4, ecx: 4
eax: 1c03c183
ebx: 03c0f03f
ecx: 00001fff
edx: 00000004
eax: 4, ecx: 5
eax: 00000000
ebx: 00000000
ecx: 00000000
edx: 00000000
我在 here
查找 table
静态 cpuid_cache_descriptor_t intel_cpuid_leaf2_descriptor_table[] = {
// -------------------------------------------------------
// value type level ways size entries
// -------------------------------------------------------
{ 0x00, _NULL_, NA, NA, NA, NA },
{ 0x01, TLB, INST, 4, SMALL, 32 },
{ 0x02, TLB, INST, FULLY, LARGE, 2 },
{ 0x03, TLB, DATA, 4, SMALL, 64 },
{ 0x04, TLB, DATA, 4, LARGE, 8 },
{ 0x05, TLB, DATA1, 4, LARGE, 32 },
{ 0x06, CACHE, L1_INST, 4, 8*K, 32 },
{ 0x08, CACHE, L1_INST, 4, 16*K, 32 },
{ 0x09, CACHE, L1_INST, 4, 32*K, 64 },
{ 0x0A, CACHE, L1_DATA, 2, 8*K, 32 },
{ 0x0B, TLB, INST, 4, LARGE, 4 },
{ 0x0C, CACHE, L1_DATA, 4, 16*K, 32 },
{ 0x0D, CACHE, L1_DATA, 4, 16*K, 64 },
{ 0x0E, CACHE, L1_DATA, 6, 24*K, 64 },
{ 0x21, CACHE, L2, 8, 256*K, 64 },
{ 0x22, CACHE, L3_2LINESECTOR, 4, 512*K, 64 },
{ 0x23, CACHE, L3_2LINESECTOR, 8, 1*M, 64 },
{ 0x25, CACHE, L3_2LINESECTOR, 8, 2*M, 64 },
{ 0x29, CACHE, L3_2LINESECTOR, 8, 4*M, 64 },
{ 0x2C, CACHE, L1_DATA, 8, 32*K, 64 },
{ 0x30, CACHE, L1_INST, 8, 32*K, 64 },
{ 0x40, CACHE, L2, NA, 0, NA },
{ 0x41, CACHE, L2, 4, 128*K, 32 },
{ 0x42, CACHE, L2, 4, 256*K, 32 },
{ 0x43, CACHE, L2, 4, 512*K, 32 },
{ 0x44, CACHE, L2, 4, 1*M, 32 },
{ 0x45, CACHE, L2, 4, 2*M, 32 },
{ 0x46, CACHE, L3, 4, 4*M, 64 },
{ 0x47, CACHE, L3, 8, 8*M, 64 },
{ 0x48, CACHE, L2, 12, 3*M, 64 },
{ 0x49, CACHE, L2, 16, 4*M, 64 },
{ 0x4A, CACHE, L3, 12, 6*M, 64 },
{ 0x4B, CACHE, L3, 16, 8*M, 64 },
{ 0x4C, CACHE, L3, 12, 12*M, 64 },
{ 0x4D, CACHE, L3, 16, 16*M, 64 },
{ 0x4E, CACHE, L2, 24, 6*M, 64 },
{ 0x4F, TLB, INST, NA, SMALL, 32 },
{ 0x50, TLB, INST, NA, BOTH, 64 },
{ 0x51, TLB, INST, NA, BOTH, 128 },
{ 0x52, TLB, INST, NA, BOTH, 256 },
{ 0x55, TLB, INST, FULLY, BOTH, 7 },
{ 0x56, TLB, DATA0, 4, LARGE, 16 },
{ 0x57, TLB, DATA0, 4, SMALL, 16 },
{ 0x59, TLB, DATA0, FULLY, SMALL, 16 },
{ 0x5A, TLB, DATA0, 4, LARGE, 32 },
{ 0x5B, TLB, DATA, NA, BOTH, 64 },
{ 0x5C, TLB, DATA, NA, BOTH, 128 },
{ 0x5D, TLB, DATA, NA, BOTH, 256 },
{ 0x60, CACHE, L1, 16*K, 8, 64 },
{ 0x61, CACHE, L1, 4, 8*K, 64 },
{ 0x62, CACHE, L1, 4, 16*K, 64 },
{ 0x63, CACHE, L1, 4, 32*K, 64 },
{ 0x70, CACHE, TRACE, 8, 12*K, NA },
{ 0x71, CACHE, TRACE, 8, 16*K, NA },
{ 0x72, CACHE, TRACE, 8, 32*K, NA },
{ 0x78, CACHE, L2, 4, 1*M, 64 },
{ 0x79, CACHE, L2_2LINESECTOR, 8, 128*K, 64 },
{ 0x7A, CACHE, L2_2LINESECTOR, 8, 256*K, 64 },
{ 0x7B, CACHE, L2_2LINESECTOR, 8, 512*K, 64 },
{ 0x7C, CACHE, L2_2LINESECTOR, 8, 1*M, 64 },
{ 0x7D, CACHE, L2, 8, 2*M, 64 },
{ 0x7F, CACHE, L2, 2, 512*K, 64 },
{ 0x80, CACHE, L2, 8, 512*K, 64 },
{ 0x82, CACHE, L2, 8, 256*K, 32 },
{ 0x83, CACHE, L2, 8, 512*K, 32 },
{ 0x84, CACHE, L2, 8, 1*M, 32 },
{ 0x85, CACHE, L2, 8, 2*M, 32 },
{ 0x86, CACHE, L2, 4, 512*K, 64 },
{ 0x87, CACHE, L2, 8, 1*M, 64 },
{ 0xB0, TLB, INST, 4, SMALL, 128 },
{ 0xB1, TLB, INST, 4, LARGE, 8 },
{ 0xB2, TLB, INST, 4, SMALL, 64 },
{ 0xB3, TLB, DATA, 4, SMALL, 128 },
{ 0xB4, TLB, DATA1, 4, SMALL, 256 },
{ 0xBA, TLB, DATA1, 4, BOTH, 64 },
{ 0xCA, STLB, DATA1, 4, BOTH, 512 },
{ 0xD0, CACHE, L3, 4, 512*K, 64 },
{ 0xD1, CACHE, L3, 4, 1*M, 64 },
{ 0xD2, CACHE, L3, 4, 2*M, 64 },
{ 0xD3, CACHE, L3, 4, 4*M, 64 },
{ 0xD4, CACHE, L3, 4, 8*M, 64 },
{ 0xD6, CACHE, L3, 8, 1*M, 64 },
{ 0xD7, CACHE, L3, 8, 2*M, 64 },
{ 0xD8, CACHE, L3, 8, 4*M, 64 },
{ 0xD9, CACHE, L3, 8, 8*M, 64 },
{ 0xDA, CACHE, L3, 8, 12*M, 64 },
{ 0xDC, CACHE, L3, 12, 1536*K, 64 },
{ 0xDD, CACHE, L3, 12, 3*M, 64 },
{ 0xDE, CACHE, L3, 12, 6*M, 64 },
{ 0xDF, CACHE, L3, 12, 12*M, 64 },
{ 0xE0, CACHE, L3, 12, 18*M, 64 },
{ 0xE2, CACHE, L3, 16, 2*M, 64 },
{ 0xE3, CACHE, L3, 16, 4*M, 64 },
{ 0xE4, CACHE, L3, 16, 8*M, 64 },
{ 0xE5, CACHE, L3, 16, 16*M, 64 },
{ 0xE6, CACHE, L3, 16, 24*M, 64 },
{ 0xF0, PREFETCH, NA, NA, 64, NA },
{ 0xF1, PREFETCH, NA, NA, 128, NA }
};
现在的问题是我仍然无法获得我的三级缓存的正确大小(当 ecx=1 时,我得到 22 即 512K,但正确的值是 6MB)。另外,我的 L2 缓存的大小似乎存在一些冲突(43(当 ecx=2 时)和 21(当 ecx=0 时))
因此,您的数据似乎相当正确,只是您使用的是旧参考。不幸的是,Intel 的网站目前要么已损坏,要么不喜欢 Firefox and/or Linux.
76036301
76 表示具有 64K 操作的跟踪缓存。
03 表示具有 64 个条目的 4 路 DATA TLB。
63 是 32KB 一级缓存 - 来源 here 显示该值,您的文档中没有。
01 表示具有 32 个条目的 4 路指令 TLB。
00f0b5ff 给出
00 "nothing"
f0 预取,64 个条目。
0b 大页面 4 路 TLB 指令,4 个条目。
b5 甚至在 link 上也没有记录。 [猜猜小数据TLB]
要获得 L2 和 L3 缓存大小,您需要使用 EAX=4 的 CPUID,并将每个缓存级别的 ECX 设置为 0、1、2 ...。 linked 代码显示了这一点,英特尔的文档详细说明了哪些位的含义。
Intel's Instruction Set Reference 拥有您需要的所有相关信息(大约在第 263 页),并且实际上是最新的,这与我找到的所有其他来源不同。
该参考资料中可能提到了获取缓存信息的最佳方法。
当eax = 4且ecx为缓存级别时,
Ways = EBX[31:22]
Partitions = EBX[21:12]
LineSize = EBX[11:0]
Sets = ECX
Total Size = (Ways + 1) * (Partitions + 1) * (Line_Size + 1) * (Sets + 1)
所以当调用 CUPID 时 eax = 4 和 ecx = 3,你可以通过上面的计算得到你的 L3 缓存大小。使用 OP 的发布数据:
ebx: 02c0003f
ecx: 00001fff
Ways = 63
Partitions = 0
LineSize = 11
Sets = 8191
L3 缓存总大小 = 6291456
这是预期的结果。