In Search of CPUs and Cores
Who among you has ever looked at the CPU information that the Altiris hardware inventory gathers and said "That's not what I need. I need to know how many physical CPUs are there, or how many cores there are, or whether this is a hyper threading CPU, etc."
Why is this important? Well, my primary interest is licensing of software, in particular server software for this information. Let's look at some examples of a real server.
First: What does the Altiris hardware inventory shows about the server:
This shows a CPU count of 8 CPUs. Now let's say we were installing MS SQL Server on that box, licensing it on a per-processor basis. That would mean that we would need to purchase 8 CPU licenses for the server in order to operate it in this mode, right? Well, actually wrong...
The problem comes in that Microsoft defines a processor as a physical chip, not a core. I prefer to think of it as "per-socket" rather than "per-processor" licensing. So with the 8 CPUs here, is it 8 single-core CPUs, 4 Dual Core, or 2 Quad Core CPUs? This distinction changes, by a factor of 4, the amount you need to spend on SQL Server licenses, from around $12,000 down to $3,000, and that's just for one server.
Now, you're left with a few choices as an Asset Manager:
- Assume there are 8 single core CPUs, and pay the $12,000 for SQL Server, just to make sure you're not under licensed
- Assume you have 2 quad core CPUs and pay the $3,000 to keep your costs as low as possible, and risk being non-compliant in the event of an audit
- Ask the server administrator, and have him respond with "Don't YOU do inventory?"
- Dig through your financial records to see what was purchased
None of these options is particularly appealing (I personally hate the third one the most!)
I tend to operate on two guiding principles:
- I can never have too much information
- I don't trust other people to tell me things that systems can gather
So, I went in search of a way to gather CPU and Core information in some way.
First stop: WMI. You've all heard it, WMI has everything, and from any kind of examination, it seems to be incredibly comprehensive. In fact, a search of Microsoft's website will show that there is a NumberOfCores property...until you dig deeper and find it's a new attribute in Vista (potentially a hotfix to add it to XP/2003...Server 2000, you're outta luck!) Doh!
Next stop: Google...I was absolutely certain that someone, anyone, had to have solved this problem. So off I went into the wide world of the Internet to find a kindred spirit who had already solved my problem.
After several hours of reading message boards with many, many people saying "Yeah, if you find out how to do that, let me know too!", I finally stumbled onto something pretty cool...a paper from an organization who ought to know how to do this: Intel...Detecting Multi-Core Processor Topology in an IA-32 Platform. Not only that, but they have a utility that kicks out the relevant information and runs nicely from a command-line...it gets better and better. Finally, not only do they have the utility, but they've also released the source code for the utility!!! OK, so my C++ skills are a bit weak, and I decided to go another direction for this, but for those of you so inclined, you can make the Intel utility skip a ton of my steps!
Now to make this play nice with Altiris. Running the utility, I found four lines in the output to be of interest (from the server above):
Hyper-Threading Technology: Not capable Multi-core: Yes Multi-processor: Yes AND System wide availability: 2 physical processors, 8 cores,8 logical processors
Getting the server to spit out the information is one thing, I want to be able to report on the information! So, how do we get this data from this format into something that uploads into the Altiris database. I selected a 2 step approach: Perl and Custom Inventory.
First, manipulating and extracting information from verbose text is what Perl was made for. So, I build a short Perl script that converts from the wordy output of the Intel utility to an INI file. Then I use a custom inventory to take that INI and upload it into the Altiris database, where I can report on it at my leisure.
First the Perl:
#! perl /* ParseCPU.pl compiled with the Perl Development Kit from ActiveState (http://www.activestate.com) into parseCPU.exe */ @Input = `echo a | cpucount.exe`; $ht = $Input[17]; $mc = $Input[18]; $mp = $Input[19]; if ($ht =~ /: (.*)\n/) { $ht=$1; } if ($mc =~ /: (.*)\n/) { $mc=$1; } if ($mp =~ /: (.*)\n/) { $mp=$1; } if ($Input[24] =~ /: (.*) physical processors, (.*) cores,(.*) logical processors/) { $phy = $1; $core=$2; $log = $3; } else { print "Parse Error\n"; } print "[Capabilities]\n"; print "Hyperthreading=$ht\nMultiCore=$mc\nMultiProcessor=$mp\n\n"; print "[ProcessorCounts]\n"; print "Physical=$phy\nCores=$core\nLogical=$log\n";
Put simply, this script executes the utility, then extracts 6 things from the output, and outputs those items into an INI file:
[Capabilities] Hyperthreading=not capable MultiCore=Yes MultiProcessor=yes [ProcessorCounts] Physical=2 Cores=8 Logical=8
Many of you may have experience using Custom Inventory to read data from an INI file, and it's pretty simple to do. First you build a Custom Inventory script in XML:
<InventoryClasses>
<InventoryClass name='CPUCount' manufacturer='Altiris' description='' version='1.0' platform='Win32' mifClass=Altiris|CPUCount|1.0'>
<xml xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema">
<s:Schema id="RowsetSchema">
<s:ElementType name="row" content="eltOnly" rs:updatable="true">
<s:AttributeType name="c0" rs:name="HyperThreadCapable" rs:number="1" rs:nullable="true" mifAttrId="1">
<s:datatype dt:type="string" dt:maxlength="50"/>
</s:AttributeType>
<s:AttributeType name="c1" rs:name="MultiCoreCapable" rs:number="2" rs:nullable="true" mifAttrId="2">
<s:datatype dt:type="string" dt:maxlength="50"/>
</s:AttributeType>
<s:AttributeType name="c2" rs:name="MultiProcessorCapable" rs:number="3" rs:nullable="true" mifAttrId="3">
<s:datatype dt:type="string" dt:maxlength="50"/>
</s:AttributeType>
<s:AttributeType name="c3" rs:name="PhysicalProcessors" rs:number="4" rs:nullable="true" mifAttrId="4">
<s:datatype dt:type="int" dt:maxlength="4"/>
</s:AttributeType>
<s:AttributeType name="c4" rs:name="Cores" rs:number="5" rs:nullable="true" mifAttrId="5">
<s:datatype dt:type="int" dt:maxlength="4"/>
</s:AttributeType>
<s:AttributeType name="c5" rs:name="LogicalProcessors" rs:number="6" rs:nullable="true" mifAttrId="6">
<s:datatype dt:type="int" dt:maxlength="4"/>
</s:AttributeType>
</s:ElementType>
</s:Schema>
<rs:data>
<%set filepath = ".\parsecpu.ini" %>
<z:row
c0 = "<%writexml "ini:%filepath%\[Capabilities]\Hyperthreading"%>"
c1 = "<%writexml "ini:%filepath%\[Capabilities]\MultiCore"%>"
c2 = "<%writexml "ini:%filepath%\[Capabilities]\MultiProcessor"%>"
c3 = "<%writexml "ini:%filepath%\[ProcessorCounts]\Physical"%>"
c4 = "<%writexml "ini:%filepath%\[ProcessorCounts]\Cores"%>"
c5 = "<%writexml "ini:%filepath%\[ProcessorCounts]\Logical"%>"
/>
</rs:data>
</xml>
</InventoryClass>
</InventoryClasses>
This custom inventory will specifically read the INI file created by the Perl script and render it as an NSI file:
<InventoryClasses> <InventoryClass name='CPUCount' manufacturer='Altiris' description='' version='1.0' platform='Win32' mifClass='Altiris|CPUCount|1.0'> <xml xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema"> <s:Schema id="RowsetSchema"> <s:ElementType name="row" content="eltOnly" rs:updatable="true"> <s:AttributeType name="c0" rs:name="HyperThreadCapable" rs:number="1" rs:nullable="true" mifAttrId="1"> <s:datatype dt:type="string" dt:maxlength="50"/> </s:AttributeType> <s:AttributeType name="c1" rs:name="MultiCoreCapable" rs:number="2" rs:nullable="true" mifAttrId="2"> <s:datatype dt:type="string" dt:maxlength="50"/> </s:AttributeType> <s:AttributeType name="c2" rs:name="MultiProcessorCapable" rs:number="3" rs:nullable="true" mifAttrId="3"> <s:datatype dt:type="string" dt:maxlength="50"/> </s:AttributeType> <s:AttributeType name="c3" rs:name="PhysicalProcessors" rs:number="4" rs:nullable="true" mifAttrId="4"> <s:datatype dt:type="int" dt:maxlength="4"/> </s:AttributeType> <s:AttributeType name="c4" rs:name="Cores" rs:number="5" rs:nullable="true" mifAttrId="5"> <s:datatype dt:type="int" dt:maxlength="4"/> </s:AttributeType> <s:AttributeType name="c5" rs:name="LogicalProcessors" rs:number="6" rs:nullable="true" mifAttrId="6"> <s:datatype dt:type="int" dt:maxlength="4"/> </s:AttributeType> </s:ElementType> </s:Schema> <rs:data> <z:row c0 = "not capable" c1 = "Yes" c2 = "yes" c3 = "2" c4 = "8" c5 = "8" /> </rs:data> </xml> </InventoryClass> </InventoryClasses>
The NSI can then be picked up and submitted to the NS in the same way as any other Inventory process. To summarize, 4 things happen to get this inventory:
- The Perl script is executed
- The Perl script executes the Intel utility, and transforms its output into an INI file
- The AexCustInv.exe reads the INI (with the help of the XML script) and generates an NSI file
- AeXNSInvCollector.exe takes the NSI and posts it to the server's notification server
I chose to deploy this Custom script with a dedicated package. This package consists of the following five files:
- ParseCPU.EXE (I use the Perl Developer Kit from ActiveState to create an EXE from my Perl, so I don't need to deploy the Perl interpreter)
- CPUCOUNT.EXE (from Intel)
- AexCustInv.exe
- AeXNSInvCollector.exe
- parsecpu.xml (the Custom Inventory Script)
I execute these steps with a single batch file:
parsecpu.exe > parsecpu.ini aexcustinv.exe /in .\parsecpu.xml /out .\parsecpu.nsi AeXNSInvCollector /s . /useguid /nsctransport /hidden
Once that step is done, simply create a task to execute the batch files on you "All 32-bit Windows Servers" collection (sorry, the paper was limited to IA-32, so 64 bit is still unsolved).
The data initially comes in under the Default Folder under the Inventory tab in Resource Manager:
Now, you have data in the database that you can utilize. The final step is to convert data into information, and that's a reporting function. In the above example, with MS SQL Server, I can now go into the server and see that even though it reports 8 CPUs, I only need to pay for 2 of them for Microsoft (we'll leave what I would have to pay for Oracle or others to another rant!) More importantly, if we do move to an application with a different metric (or even have multiple on the same box with SQL Server and Tivoli Storage Manager for example), I have the information at my fingertips to give good advice to server administrators as to what they need to purchase, I have good information to give to auditors/vendors to tell them to leave me alone, and more importantly, I don't look stupid asking server admins for information that I really should have had in the first place.
| Attachment | Size |
|---|---|
| parsecpu.zip | 876.23 KB |
- Login or register to post comments
- 1580 reads
- Printer-friendly version

















interseting idea w/ the perl script
can't i just do it w/ a custom inventory to query wmi? that way you wouldn't have to use a perl script, just do the normal inventory
Not in WMI
That's part of the problem...the information is not in WMI, so you have to go a bit deeper to get the information.
Honestly, this should be a part of the basic HW Inventory, but isn't and never has been.
With you on that one!
This actually couldn't come at a better time for me as I was just tasked with getting this same information!
But yeah, I agree that this should be a native function of HW Inv.
I believe this is an addition to IS 7.0 and I know myself and a few others have requested this as a feature request as well.
Any body any good at xfer this into VBS?
Microsoft updates to WMI
Microsoft has provided unpublished updates to WMI to gather this information. You may want to see the following juice article for information about the updates and a custom invetnory sample to gather the cpu information:
http://juice.altiris.com/download/2677/identifying...
Does it work on 64bit?
Great info, and we would be interested in applying it to our custom inventory....IF it works on 64bit HW. I don't have any direct access to a 64bit OS/server, but would be interested to know if it does work. Anyone able to test it out?
64-Bit
I haven't been able to test any 64-bit either yet...the Intel Paper (see link a few comments earlier) deals only with IA-32 architecture...I don't even know how it would work with AMD processors.
Tools links...
Any chance you could post the links to where you located the tools for you post?
Scratch that last comment...
Google is great when you give it explicit terms...
Linkey here: http://softwarecommunity.intel.com/articles/eng/27...
Oops.
Linkey here: http://softwarecommunity.intel.com/articles/eng/27...
Hmmm...that link was in my original article, I guess it got stripped during publication.
Sorry 'bout that.
I can edit!
I found out I can edit the original article...I've added the link now.
Cool!
What about the parse file?
Can you post the parsecpu.exe file you compiled?
Ask and ye shall receive
I've attached the file as a ZIP.
I don't want to attach the whole thing, as I'm not sure how the Intel utility is licensed for redistribution (I know you can use it, I just don't know if I can give it to you)
ParseCPU.Zip
WMI will report correctly
You can get WMI to report processors/cores correctly after applying patches. Upon request only from MS:
2003: http://support.microsoft.com/kb/932370/en-us
XP: http://support.microsoft.com/kb/936235/en-us
WMI will report correctly
What about Windows 2000 though?
2003: http://support.microsoft.com/kb/932370/en-us
XP: http://support.microsoft.com/kb/936235/en-us
Slight problem
Great article! This is exactly what I was looking for. Thank you very much.
On about 15% of my servers I'm getting an error when running CPUCOUNT.EXE. The others are working great. Example:
----Counting Hardware MultiThreading Capabilities and Availability ----------
This application displays information on three forms of hardware multithreading
capability and their availability to apps. The three forms of capabilities are:
multi-processor (MP), Multi-core (core), and HyperThreading Technology (HT).
Hardware capability results represents the maximum number provided in hardware.
Note, Bios/OS or experienced user can make configuration changes resulting in
less-than-full HW capabilities are available to applications.
For best result, the operator is responsible to configure the BIOS/OS such that
full hardware multi-threading capabilities are enabled.
----------------------------------------------------------------------------
Capabilities:
Hyper-Threading Technology: Not capable
Multi-core: No
Multi-processor: No
Hardware capability and its availability to applications:
System wide availability: 1 physical processors, 1 cores,2 logical processors
Multi-core capabililty : Maximum 1 cores per package
HT capability: Maximum 1 logical processors per core
Assertion failed: PhysicalNum * MaxLogicalProcPerPhysicalProc() >= TotAvailLogic
al, file cpucountcode.c, line 171
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
Even though the capabilities and processorcounts are in the output (before it errors out), ParseCPU.EXE fails to grab them. The result of the .ini:
Parse Error
[Capabilities]
Hyperthreading=
MultiCore=
MultiProcessor=
[ProcessorCounts]
Physical=
Cores=
Logical=
Is there anyway you could update ParseCPU.EXE so it could still work when CPUCOUNT.EXE errors like this?
Also, just an fyi, there's a missing quote in your parsecpu.xml. In the 2nd line:
should be
Thanks again for all of your help.