Scripting with dmidecode
(Originally published Thursday December 23, 2004 on Newsforge)
The recent Newsforge article about dmidecode got me thinking: what other practical applications are there for dmidecode? As that article points out, there isn't a lot of software out there that makes real use of the dmidecode data. Let's see if we can change that.
I work as a Linux System Administrator, overseeing the usual motley collection of systems in my company's server room. Recently my boss gave me an assignment: find a way to determine if a system is running a kernel that matches the number of CPUs. In other words, if a system has one CPU installed, it should be running a uniprocessor kernel. If a system has more than one CPU installed, it should be running an SMP kernel. This is an issue for us because we clone new servers off existing servers. Thus if I forget to manually adjust a system after cloning it, I can end up running an SMP kernel on a UP system.
How to do this? The short answer is dmidecode plus a few other tools, tied together with the baling twine of the computer world, Perl. The following is a discussion of how I researched the problem and ultimately produced a script to automate this process.
The first question to ask when approaching this sort of project is: how do I get my data? Because once you can find the data, you just need to develop the script logic to tie it together.
First of all, I knew I could determine the number of running processors in a system by examining /proc/cpuinfo. This pseudo-file contains one entry per CPU that the kernel is actually using. For example, /proc/cpuinfo on my dual processor test system reports:
processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 11 model name : Intel(R) Pentium(R) III CPU - S 1266MHz stepping : 4 cpu MHz : 1258.341 ...other stuff we don't care about... processor : 1 vendor_id : GenuineIntel cpu family : 6 model : 11 model name : Intel(R) Pentium(R) III CPU - S 1266MHz stepping : 4 cpu MHz : 1258.341 ...other stuff we don't care about...
Next, I needed to find out how many CPUs were actually in the system. Isn't this the same as what is listed in /proc/cpuinfo? The answer is no, for a variety of reasons. /proc/cpuinfo only lists the CPUs that the kernel knows about. If you boot a uniprocessor a kernel on a system with more than one CPU, /proc/cpuinfo is going to report one CPU.
Here's where dmidecode comes in. By examining the DMI data, we should be able to determine how many CPUs the BIOS thinks are installed. Remember from that previous article that we should never trust what the BIOS says. However, in this case I'm willing to trust the BIOS a little bit and believe the DMI data. Basically if DMI doesn't contain the real number of physical processors, then your server is more screwed up than I care to deal with.
Here are are the relevant dmidecode entries:
Handle 0x0400 DMI type 4, 35 bytes. Processor Information Socket Designation: Proc_1 Type: Central Processor Family: Pentium III Manufacturer: Intel Status: Populated, Idle ...lots of other stuff omitted... Handle 0x0401 DMI type 4, 35 bytes. Processor Information Socket Designation: Proc_2 Type: Central Processor Family: Pentium III Manufacturer: Intel Status: Populated, Enabled ...lots of other stuff omitted...
Obviously, for this particular application we don't care about most of the information from /proc/cpuinfo or dmidecode. In /proc/cpuinfo, we just need to count the number of
processor: lines that appear in the output to get the number of processors currently in use by the kernel.
Similarly, we can count the number of
Processor Information sections in the dmidecode output to get the number of processors the BIOS thinks are installed. But wait, there's a catch: look at that
Status entry. We need to check that line as well, because an SMP system with only one CPU installed will report
Status: Unpopulated for the other CPU. This indicates the socket is present, but no CPU is installed. Although I don't check this case in my script, in some installations it might be useful to issue a warning if a system is missing a physical CPU.
That's the basic outline of the script, which I've placed on my website if you are interested. If you look at the script, you'll notice it performs several other checks which I haven't discussed yet. One check I added was to determine if Hyper-Threading is enabled on the system. For those of you not familiar with Hyper-Threading, it's basically an Intel mechanism to make a single processor in a system work like two processors. In theory, a system with Hyper-Threading will appear to have two processors and will run faster than a plain system without Hyper-Threading.
As usual, the reality is not so simple. For various reasons, you may not want to use Hyper-Threading. We don't want to use it on our server. Thus, I expanded the CheckProcs script to check and report if Hyper-Threading is enabled on the system. To do this, I used the utility x86info. Unlike dmidecode which queries the BIOS or /proc/cpuinfo which queries the kernel, x86info talks to the processor directly.
I would have liked to just read /proc/cpuinfo to determine if Hyper-Threading is enabled, but currently that info is not exported to that file. /proc/cpuinfo just displays the number of physical CPUs in the system and ignores Hyper-Threading.
The process of using x86info is similar to the process of using dmidecode: execute and parse the output. In this case, x86info will say
The physical package supports 2 logical processors if Hyper-Threading is enabled on a standard Xeon system.
I also count the number of CPUs returned by x86info and compare this against the dmidecode and /proc/cpuinfo output. However, I'm not entirely clear if x86info could ever report a different number than those other tools. Still, it seems good to be paranoid and check, just in case.
I hope I've shown that dmidecode is a genuinely useful tool for system administration scripting. As is usually the case with Linux system administration, it's only part of the answer. You have to take a little info from dmidecode, a little from /proc/cpuinfo, and a little from x86info to really get a picture of what's going on with your system. This plus some perl gives you a way to automatically determine if your server and kernel are correctly configured, and hopefully save you some trouble later on.
Since I originally wrote this article, I discovered my hyperthreading detection doesn't really work. At this point I don't have a good general way to detect hyperthreading, so I am recommending you ignore that part of the article.