-
Notifications
You must be signed in to change notification settings - Fork 481
/
Copy pathtopologyentry.h
180 lines (167 loc) · 6.1 KB
/
topologyentry.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2022-, Intel Corporation
#pragma once
#include "types.h"
namespace pcm
{
struct PCM_API TopologyEntry // describes a core
{
/*
* core_id is the hw specific physical core id that was introduced in newer generations, on
* older generations this is the same as socket_unique_core_id.
* socket_unique_core_id is like the name says a socket unique core id that is built out of the core_id, module_id, thread_id, die_id and die_grp_id.
* With it, we have unique core ids inside a socket for keeping backward compatibility in the prometheus and json output.
*/
int32 os_id;
int32 thread_id;
int32 core_id;
int32 module_id;
int32 tile_id; // tile is a constellation of 1 or more cores sharing same L2 cache. Unique for entire system
int32 die_id;
int32 die_grp_id;
int32 socket_id;
int32 socket_unique_core_id;
int32 native_cpu_model = -1;
enum DomainTypeID
{
InvalidDomainTypeID = 0,
LogicalProcessorDomain = 1,
CoreDomain = 2,
ModuleDomain = 3,
TileDomain = 4,
DieDomain = 5,
DieGrpDomain = 6,
SocketPackageDomain = 0xffff
};
enum CoreType
{
Atom = 0x20,
Core = 0x40,
Invalid = -1
};
CoreType core_type = Invalid;
TopologyEntry() : os_id(-1), thread_id (-1), core_id(-1), module_id(-1), tile_id(-1), die_id(-1), die_grp_id(-1), socket_id(-1), socket_unique_core_id(-1) { }
const char* getCoreTypeStr()
{
switch (core_type)
{
case Atom:
return "Atom";
case Core:
return "Core";
case Invalid:
return "invalid";
}
return "unknown";
}
static const char* getDomainTypeStr(const DomainTypeID & id)
{
switch (id)
{
case InvalidDomainTypeID: return "invalid";
case LogicalProcessorDomain: return "LogicalProcessor";
case CoreDomain: return "Core";
case ModuleDomain: return "Module";
case TileDomain: return "Tile";
case DieDomain: return "Die";
case DieGrpDomain: return "DieGroup";
case SocketPackageDomain: return "Socket/Package";
}
return "unknown";
}
bool isSameSocket( TopologyEntry& te ) {
return this->socket_id == te.socket_id;
}
bool isSameDieGroup( TopologyEntry& te ) {
return this->die_grp_id == te.die_grp_id && isSameSocket(te);
}
bool isSameDie( TopologyEntry& te ) {
return this->die_id == te.die_id && isSameDieGroup(te);
}
bool isSameTile( TopologyEntry& te ) {
return this->tile_id == te.tile_id && isSameDie(te);
}
bool isSameModule( TopologyEntry& te ) {
return this->module_id == te.module_id && isSameTile (te);
}
bool isSameCore( TopologyEntry& te ) {
return this->core_id == te.core_id && isSameModule(te);
}
};
inline void fillEntry(TopologyEntry & entry, const uint32 & smtMaskWidth, const uint32 & coreMaskWidth, const uint32 & l2CacheMaskShift, const int apic_id)
{
entry.thread_id = smtMaskWidth ? extract_bits_32(apic_id, 0, smtMaskWidth - 1) : 0;
entry.core_id = (smtMaskWidth + coreMaskWidth) ? extract_bits_32(apic_id, smtMaskWidth, smtMaskWidth + coreMaskWidth - 1) : 0;
entry.socket_id = extract_bits_32(apic_id, smtMaskWidth + coreMaskWidth, 31);
entry.tile_id = extract_bits_32(apic_id, l2CacheMaskShift, 31);
entry.socket_unique_core_id = entry.core_id;
}
inline bool initCoreMasks(uint32 & smtMaskWidth, uint32 & coreMaskWidth, uint32 & l2CacheMaskShift)
{
// init constants for CPU topology leaf 0xB
// adapted from Topology Enumeration Reference code for Intel 64 Architecture
// https://software.intel.com/en-us/articles/intel-64-architecture-processor-topology-enumeration
int wasCoreReported = 0, wasThreadReported = 0;
PCM_CPUID_INFO cpuid_args;
if (true)
{
uint32 corePlusSMTMaskWidth = 0;
int subleaf = 0, levelType, levelShift;
do
{
pcm_cpuid(0xb, subleaf, cpuid_args);
if (cpuid_args.array[1] == 0)
{ // if EBX ==0 then this subleaf is not valid, we can exit the loop
break;
}
levelType = extract_bits_32(cpuid_args.array[2], 8, 15);
levelShift = extract_bits_32(cpuid_args.array[0], 0, 4);
switch (levelType)
{
case 1: //level type is SMT, so levelShift is the SMT_Mask_Width
smtMaskWidth = levelShift;
wasThreadReported = 1;
break;
case 2: //level type is Core, so levelShift is the CorePlusSMT_Mask_Width
corePlusSMTMaskWidth = levelShift;
wasCoreReported = 1;
break;
default:
break;
}
subleaf++;
} while (1);
if (wasThreadReported && wasCoreReported)
{
coreMaskWidth = corePlusSMTMaskWidth - smtMaskWidth;
}
else if (!wasCoreReported && wasThreadReported)
{
coreMaskWidth = smtMaskWidth;
}
else
{
return false;
}
(void) coreMaskWidth; // to suppress warnings on MacOS (unused vars)
#ifdef PCM_DEBUG_TOPOLOGY
uint32 threadsSharingL2;
#endif
uint32 l2CacheMaskWidth;
pcm_cpuid(0x4, 2, cpuid_args); // get ID for L2 cache
l2CacheMaskWidth = 1 + extract_bits_32(cpuid_args.array[0],14,25); // number of APIC IDs sharing L2 cache
#ifdef PCM_DEBUG_TOPOLOGY
threadsSharingL2 = l2CacheMaskWidth;
#endif
for( ; l2CacheMaskWidth > 1; l2CacheMaskWidth >>= 1)
{
l2CacheMaskShift++;
}
#ifdef PCM_DEBUG_TOPOLOGY
std::cerr << "DEBUG: Number of threads sharing L2 cache = " << threadsSharingL2
<< " [the most significant bit = " << l2CacheMaskShift << "]\n";
#endif
}
return true;
}
}