download cpucount.cpp
Language: C++
License: IOSL
Copyright: (c) 2005 Intel Corporation
LOC: 212
Project Info
geekinfo - Cross-platform system information tool(geekinfo)
Server: Google
Type: svn
Google\g\geekinfo\trunk\
   basesystem.cpp
   basesystem.h
   cpucount.cpp
   cpucount.h
   cpucount_asm.asm
   cpucount_asm.h
   geekinfo.cpp
   geekinfo.h
   geekinfo_c.cpp
   geekinfo_c.h
   geekinfo_c_test.c
   linuxsystem.cpp
   linuxsystem.h
   macosxsystem.cpp
   macosxsystem.h
   Makefile.win32
   Makefile_c.win32
   model.cpp
   model.h
   model.py
   platform.h
   solarissystem.cpp
   solarissystem.h
   system.cpp
   system.h
   types.h
   win32system.cpp
   win32system.h
   wmi.cpp
   wmi.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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
// Copyright (c) 2005 Intel Corporation 
// All Rights Reserved
//
// CPUCount.cpp : Detects three forms of hardware multi-threading support across IA-32 platform
//					The three forms of HW multithreading are: Multi-processor, Multi-core, and 
//					HyperThreading Technology.
//					This application enumerates all the logical processors enabled by OS and BIOS,
//					determine the HW topology of these enabled logical processors in the system 
//					using information provided by CPUID instruction.
//					A multi-processing system can support any combination of the three forms of HW
//					multi-threading support. The relevant topology can be identified using a 
//					three level decomposition of the "initial APIC ID" into 
//					Package_id, core_id, and SMT_id. Such decomposition provides a three-level map of 
//					the topology of hardware resources and
//					allow multi-threaded software to manage shared hardware resources in 
//					the platform to reduce resource contention

//					Multicore detection algorithm for processor and cache topology requires
//					all leaf functions of CPUID instructions be available. System administrator
//					must ensure BIOS settings is not configured to restrict CPUID functionalities.
//-------------------------------------------------------------------------------------------------

// Modifications for Win32 geekinfo by Xo W. (GHF):
// -all linux stuff taken out
// -inline assembly not usable with 64-bit MSVC compiler replace with intrinsics where possible and
// -put into a separate file if necessary (or convenient, really)

#include "cpucount_asm.h"
#include "cpucount.h"
#include <intrin.h>

#define HWD_MT_BIT         0x10000000     // EDX[28]  Bit 28 is set if HT or multi-core is supported
#define NUM_LOGICAL_BITS   0x00FF0000     // EBX[23:16] Bit 16-23 in ebx contains the number of logical
                                          // processors per physical processor when execute cpuid with 
                                          // eax set to 1
#define NUM_CORE_BITS      0xFC000000     // EAX[31:26] Bit 26-31 in eax contains the number of cores minus one
                                          // per physical processor when execute cpuid with 
                                          // eax set to 4. 


#define INITIAL_APIC_ID_BITS  0xFF000000  // EBX[31:24] Bits 24-31 (8 bits) return the 8-bit unique 
                                          // initial APIC ID for the processor this code is running on.
                                          


// Status Flag
#define SINGLE_CORE_AND_HT_ENABLED					1
#define SINGLE_CORE_AND_HT_DISABLED					2
#define SINGLE_CORE_AND_HT_NOT_CAPABLE					4
#define MULTI_CORE_AND_HT_NOT_CAPABLE					5
#define MULTI_CORE_AND_HT_ENABLED					6
#define MULTI_CORE_AND_HT_DISABLED					7
#define USER_CONFIG_ISSUE						8


unsigned int  CpuIDSupported(void);
unsigned int  GenuineIntel(void);
unsigned int  HWD_MTSupported(void);
unsigned int  MaxLogicalProcPerPhysicalProc(void);
unsigned int  MaxCorePerPhysicalProc(void);
unsigned int  find_maskwidth(unsigned int);
unsigned char GetAPIC_ID(void);
unsigned char GetNzbSubID(unsigned char,
						  unsigned char,
						  unsigned char);

unsigned char CPUCount(unsigned int *,
					   unsigned int *,
					   unsigned int *);

#include <windows.h>
#include <stdio.h>
#include <assert.h>

char g_s3Levels[2048];

//
// CpuIDSupported will return 0 if CPUID instruction is unavailable. Otherwise, it will return 
// the maximum supported standard function.
//
unsigned int CpuIDSupported(void)
{
//	unsigned int MaxInputValue;
// If CPUID instruction is supported
/*	try
	{
		MaxInputValue = 0;
		// call cpuid with eax = 0
		__asm
		{
			xor eax, eax
			cpuid
			mov MaxInputValue, eax
		}
	}
	catch (...)
	{
		return(0);                   // cpuid instruction is unavailable
	}*/

	return 1;

}


//
// GenuineIntel will return 0 if the processor is not a Genuine Intel Processor 
//
unsigned int GenuineIntel(void)
{
	unsigned int VendorID[4] = {0, 0, 0, 0};
	try    // If CPUID instruction is supported
	{
        /*
		__asm		
		{
			xor eax, eax			
        	cpuid					
			mov VendorID, ebx
			mov VendorID + 4, edx
			mov VendorID + 8, ecx
		}
		*/
		__cpuid( (int *)VendorID, 0 );
	}		
	catch (...)
	{
		return(0);      		unsigned int MaxInputValue =0;
		             // cpuid instruction is unavailable
	}
	return  ((VendorID[1] == 'uneG') &&
			 (VendorID[3] == 'Ieni') &&
			 (VendorID[2] == 'letn'));
}



//
// Function returns the maximum cores per physical package. Note that the number of 
// AVAILABLE cores per physical to be used by an application might be less than this
// maximum value.
//

unsigned int MaxCorePerPhysicalProc(void)
{
    unsigned int Regeax = 0;
	
	if (!HWD_MTSupported()) return (unsigned int) 1;  // Single core
        /*
        __asm
		{
			xor eax, eax
			cpuid
			cmp eax, 4			 //check if cpuid supports leaf 4
			jl single_core		 //Single core
			mov eax, 4			
			mov ecx, 0			 //start with index = 0; Leaf 4 reports
			cpuid				 //at least one valid cache level
			mov Regeax, eax
			jmp multi_core

            single_core:
			xor eax, eax		

            multi_core:
			
		}
        */
		Regeax = __MaxCorePerPhysicalProc__();
		
	return (unsigned int)((Regeax & NUM_CORE_BITS) >> 26)+1;

}





//
// The function returns 0 when the hardware multi-threaded bit is not set.
//
unsigned int HWD_MTSupported(void)
{
    unsigned int CPUInfo[4] = { 0, 0, 0, 0 };
	unsigned int Regedx      = 0;


	if ((CpuIDSupported() >= 1) && GenuineIntel())
	{
		/*
        __asm
		{
			mov eax, 1
			cpuid
			mov Regedx, edx
		}
        */
		__cpuid( (int *)CPUInfo, 1 );
	}

	return (CPUInfo[3] & HWD_MT_BIT);  

  
}

//
// Function returns the maximum logical processors per physical package. Note that the number of 
// AVAILABLE logical processors per physical to be used by an application might be less than this
// maximum value.
//
unsigned int MaxLogicalProcPerPhysicalProc(void)
{
    unsigned int CPUInfo[4] = { 0, 0, 0, 0 };

	if (!HWD_MTSupported()) return (unsigned int) 1;
	    /*
		__asm
		{
			mov eax, 1
			cpuid
			mov Regebx, ebx
		}
		*/
		__cpuid( (int *)CPUInfo, 1 );
		
		return (unsigned int) ((CPUInfo[1] & NUM_LOGICAL_BITS) >> 16);

}


unsigned char GetAPIC_ID(void)
{
    unsigned int CPUInfo[4] = { 0, 0, 0, 0 };
    
    /*
	__asm
	{
		mov eax, 1
		cpuid
		mov Regebx, ebx
	}                             
    */
    
    __cpuid( (int *)CPUInfo, 1 );
    
	return (unsigned char) ((CPUInfo[1] & INITIAL_APIC_ID_BITS) >> 24);

}


//
// Determine the width of the bit field that can represent the value count_item. 
//
unsigned int find_maskwidth(unsigned int CountItem)
{
	unsigned int MaskWidth,
				 count = CountItem;
    /*
	__asm
	{
		mov eax, count
		mov ecx, 0
		mov MaskWidth, ecx
		dec eax
		bsr cx, ax
		jz next
		inc cx
		mov MaskWidth, ecx
        next:
		
	}
	*/
	
	MaskWidth = __find_maskwidth__(count);
	
	return MaskWidth;
}


//
// Extract the subset of bit field from the 8-bit value FullID.  It returns the 8-bit sub ID value
//
unsigned char GetNzbSubID(unsigned char FullID,
						  unsigned char MaxSubIDValue,
						  unsigned char ShiftCount)
{
	unsigned int MaskWidth;
	unsigned char MaskBits;

	MaskWidth = find_maskwidth((unsigned int) MaxSubIDValue);
	MaskBits  = (0xff << ShiftCount) ^ 
				((unsigned char) (0xff << (ShiftCount + MaskWidth)));

	return (FullID & MaskBits);
}




//
//
//
unsigned char CPUCount(unsigned int *TotAvailLogical,
					   unsigned int *TotAvailCore,
					   unsigned int *PhysicalNum)
{
	unsigned char StatusFlag = 0;
	unsigned int numLPEnabled = 0;
	DWORD dwAffinityMask;
	int j = 0, MaxLPPerCore;
	unsigned char apicID, PackageIDMask;
	unsigned char tblPkgID[256], tblCoreID[256], tblSMTID[256];
	char	tmp[256];
	g_s3Levels[0] = 0;
	*TotAvailCore = 1;
	*PhysicalNum  = 1;

	DWORD dwProcessAffinity, dwSystemAffinity;
	GetProcessAffinityMask(GetCurrentProcess(), 
						   &dwProcessAffinity,
						   &dwSystemAffinity);
	if (dwProcessAffinity != dwSystemAffinity)  // not all CPUs are enabled
	{
		StatusFlag = USER_CONFIG_ISSUE;		
		return StatusFlag;
	}
	
	// Assumwe that cores within a package have the SAME number of 
	// logical processors.  Also, values returned by
	// MaxLogicalProcPerPhysicalProc and MaxCorePerPhysicalProc do not have
	// to be power of 2.

	MaxLPPerCore = MaxLogicalProcPerPhysicalProc() / MaxCorePerPhysicalProc();
	dwAffinityMask = 1;

	while (dwAffinityMask && dwAffinityMask <= dwSystemAffinity)
	{
		if (SetThreadAffinityMask(GetCurrentThread(), dwAffinityMask))
		{
			Sleep(0);  // Ensure system to switch to the right CPU
			apicID = GetAPIC_ID();


			// Store SMT ID and core ID of each logical processor
			// Shift vlaue for SMT ID is 0
			// Shift value for core ID is the mask width for maximum logical
			// processors per core

			tblSMTID[j]  = GetNzbSubID(apicID, MaxLPPerCore, 0);
			tblCoreID[j] = GetNzbSubID(apicID, 
						   MaxCorePerPhysicalProc(),
						   (unsigned char) find_maskwidth(MaxLPPerCore));

			// Extract package ID, assume single cluster.
			// Shift value is the mask width for max Logical per package

			PackageIDMask = (unsigned char) (0xff << 
							find_maskwidth(MaxLogicalProcPerPhysicalProc()));

			tblPkgID[j] = apicID & PackageIDMask;
			sprintf(tmp,"  AffinityMask = %d; Initial APIC = %d; Physical ID = %d, Core ID = %d,  SMT ID = %d\n",
				    dwAffinityMask, apicID, tblPkgID[j], tblCoreID[j], tblSMTID[j]);
			strcat(g_s3Levels, tmp);

			numLPEnabled ++;   // Number of available logical processors in the system.

		} // if

		j++;
		dwAffinityMask = 1 << j;
	} // while

    // restore the affinity setting to its original state
    SetThreadAffinityMask(GetCurrentThread(), dwProcessAffinity);
	Sleep(0);
	*TotAvailLogical = numLPEnabled;
	
	//
	// Count available cores (TotAvailCore) in the system
	//
	unsigned char CoreIDBucket[256];
	DWORD ProcessorMask, pCoreMask[256];
	unsigned int i, ProcessorNum;

	CoreIDBucket[0] = tblPkgID[0] | tblCoreID[0];
	ProcessorMask = 1;
	pCoreMask[0] = ProcessorMask;

	for (ProcessorNum = 1; ProcessorNum < numLPEnabled; ProcessorNum++)
	{
		ProcessorMask <<= 1;
		for (i = 0; i < *TotAvailCore; i++)
		{
			// Comparing bit-fields of logical processors residing in different packages
			// Assuming the bit-masks are the same on all processors in the system.
			if ((tblPkgID[ProcessorNum] | tblCoreID[ProcessorNum]) == CoreIDBucket[i])
			{
				pCoreMask[i] |= ProcessorMask;
				break;
			}

		}  // for i

		if (i == *TotAvailCore)   // did not match any bucket.  Start a new one.
		{
			CoreIDBucket[i] = tblPkgID[ProcessorNum] | tblCoreID[ProcessorNum];
			pCoreMask[i] = ProcessorMask;

			(*TotAvailCore)++;	// Number of available cores in the system

		}

	}  // for ProcessorNum


	//
	// Count physical processor (PhysicalNum) in the system
	//
	unsigned char PackageIDBucket[256];
	DWORD pPackageMask[256];

	PackageIDBucket[0] = tblPkgID[0];
	ProcessorMask = 1;
	pPackageMask[0] = ProcessorMask;

	for (ProcessorNum = 1; ProcessorNum < numLPEnabled; ProcessorNum++)
	{
		ProcessorMask <<= 1;
		for (i = 0; i < *PhysicalNum; i++)
		{
			// Comparing bit-fields of logical processors residing in different packages
			// Assuming the bit-masks are the same on all processors in the system.
			if (tblPkgID[ProcessorNum]== PackageIDBucket[i])
			{
				pPackageMask[i] |= ProcessorMask;
				break;
			}

		}  // for i

		if (i == *PhysicalNum)   // did not match any bucket.  Start a new one.
		{
			PackageIDBucket[i] = tblPkgID[ProcessorNum];
			pPackageMask[i] = ProcessorMask;

			(*PhysicalNum)++;	// Total number of physical processors in the system

		}

	}  // for ProcessorNum

    //
    // Check to see if the system is multi-core 
    // Check if the system is hyper-threading
    //
    if (*TotAvailCore > *PhysicalNum) 
    {
    	// Multi-core
    	if (MaxLPPerCore == 1)
    		StatusFlag = MULTI_CORE_AND_HT_NOT_CAPABLE;
    	else if (numLPEnabled > *TotAvailCore)
    		StatusFlag = MULTI_CORE_AND_HT_ENABLED;
    		else StatusFlag = MULTI_CORE_AND_HT_DISABLED;
    
    }
    else
    {
    	// Single-core
    	if (MaxLPPerCore == 1)
    		StatusFlag = SINGLE_CORE_AND_HT_NOT_CAPABLE;
    	else if (numLPEnabled > *TotAvailCore)
    		StatusFlag = SINGLE_CORE_AND_HT_ENABLED;
    		else StatusFlag = SINGLE_CORE_AND_HT_DISABLED;
    
    
    }

    return StatusFlag;
}





About Koders | Resources | Downloads | Support | Black Duck | Submit Project | Terms of Service | DMCA | Privacy Policy | Site Map| Contact Us