Multitasking is the operating system technique for sharing a single processor among multiple threads of execution. When a computer has more than one processor, however, it can execute multiple threads simultaneously. Thus, whereas a multitasking operating system only appears to execute multiple threads at the same time, a multiprocessing operating system actually does it, executing one thread on each of its processors.
As mentioned at the beginning of this chapter, one of the key design goals for Windows was that it had to run well on multiprocessor computer systems. Windows is a symmetric multiprocessing (SMP) operating system. There is no master processor—the operating system as well as user threads can be scheduled to run on any processor. Also, all the processors share just one memory space. This model contrasts with asymmetric multiprocessing (ASMP), in which the operating system typically selects one processor to execute operating system kernel code while other processors run only user code. The differences in the two multiprocessing models are illustrated in Figure 2-2.
Windows Vista and Windows Server 2008 also support two modern types of multiprocessor systems: hyperthreading and NUMA (non-uniform memory architecture). These are briefly mentioned in the following paragraphs. (For a complete, detailed description of the scheduling support for these systems, see the thread scheduling section in Chapter 5.)
Naturally, Windows also natively supports multicore systems—because these systems have real physical cores (simply on the same package), the original SMP code in Windows treats them as discrete processors, except for certain accounting and identification tasks (such as licensing, described shortly) that distinguish between cores on the same processor and cores on different sockets.
Hyperthreading is a technology introduced by Intel that provides many logical processors on one physical processor. Each logical processor has its CPU state, but the execution engine and onboard cache are shared. This permits one logical CPU to make progress while the other logical CPUs are busy (such as performing interrupt processing work, which prevents threads from running on that logical processor). The scheduling algorithms are enhanced to make optimal use of multiprocessor hyperthreaded machines, such as by scheduling threads on an idle physical processor versus choosing an idle logical processor on a physical processor whose other logical processors are busy.
In NUMA systems, processors are grouped in smaller units called nodes. Each node has its own processors and memory and is connected to the larger system through a cachecoherent interconnect bus. Windows on a NUMA system still runs as an SMP system, in that all processors have access to all memory—it’s just that node-local memory is faster to reference than memory attached to other nodes. The system attempts to improve performance
by scheduling threads on processors that are in the same node as the memory being used. It attempts to satisfy memory-allocation requests from within the node, but will allocate memory from other nodes if necessary.
Although Windows was originally designed to support up to 32 processors, nothing inherent in the multiprocessor design limits the number of processors to 32—that number is simply an obvious and convenient limit because 32 processors can easily be represented as a bit mask using a native 32-bit data type. In fact, the 64-bit versions of Windows support up to 64 processors, because the native size of a word on a 64-bit machine is 64 bits. The actual number of supported processors depends on the edition of Windows being used. (See Table 2-3.) This number is stored in the system license policy file (\Windows\ServiceProfiles\NetworkService\AppData\Roaming\Microsoft\SoftwareLicensing\tokens.dat) as a policy value called “Kernel-MaximumProcessors.” (Keep in mind that tampering with that data is a violation of the software license and modifying licensing policies to allow the use of
more processors involves more than just changing this value.)
As of Windows Vista and Windows Server 2008, there is a unified kernel regardless of whether the system is a uniprocessor or multiprocessor machine. This change, compared to earlier versions of Windows, which had separate kernels for each machine type, was made both because the majority of systems currently sold include at least two cores and because the few uniprocessor-only optimizations result in negligible performance improvement.
However, 32-bit versions of Windows still come in two flavors of the kernel, depending on whether PAE is enabled and supported. Because no-execute memory support (known as NX on AMD processors and XD on Intel processors) in today’s processors makes use of PAE structures, most 32-bit systems use the PAE kernel. On 64-bit Windows systems there is no PAE kernel (there isn’t a need for it), so there is only a single kernel image.
At installation time, the appropriate files are selected and copied to the local %SystemRoot% directory. Table 2-2 shows the correspondence of installed file names to their original names on the installation media.
The rest of the system files that make up Windows (including all utilities, libraries, and device drivers) have the same version on all types of systems (that is, they handle multiprocessor synchronization and PAE issues correctly). You should use this approach on any software you build, whether it is a Windows application or a device driver—keep multiprocessor synchronization issues in mind when you design your software, and test the software on both uniprocessor and multiprocessor systems. For legacy applications, Windows implements a number of flags to provide backward compatibility. For example, applications need to be specifically made “large address aware” for PAE support, and they can also set a “uniprocessor only” field in their image if they break on SMP systems.
EXPERIMENT: Checking Which Ntoskrnl Version You’re Running
Windows has no utility to show which version of Ntoskrnl you are running. However, an Event Log entry is written each time the system boots that does record the type of kernel image that loaded (multiprocessor and free vs. checked), as shown in the following screen shot. (From the Start menu, select Programs/Administrative Tools/Event Viewer, select Windows Logs/System, and then double-click an Event Log entry with an Event ID of 6009, indicating the entry was written at the system start.)
This Event Log entry doesn’t indicate whether you booted the PAE version of the kernel image that supports more than 4 GB of physical memory (Ntkrnlpa.exe). However, you can tell if you booted the PAE kernel by looking at the registry value HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\PhysicalAddressExtension. You can also determine which version of the kernel you’re running by using WinDbg and opening a local kernel debugging session. Be sure you have the symbols loaded (enter the .reload command), and then type the “list module” command to list details for the kernel image (nt): lm mv nt. The output below shows a PAE multiprocessor kernel, as you can tell by the name.
- lkd> lm vm nt
- start end module name
- 82000000 823a1000 nt (pdb symbols)
- Loaded symbol image file: ntkrpamp.exe
- Image path: ntkrpamp.exe
- Image name: ntkrpamp.exe
- Timestamp: Tue Oct 09 21:46:20 2007 (470C2EEC)
- CheckSum: 00366023
- ImageSize: 003A1000
- File version: 6.0.6000.20697
- Product version: 6.0.6000.20697
- File flags: 0 (Mask 3F)
- File OS: 40004 NT Win32
- File type: 1.0 App
- File date: 00000000.00000000
- Translations: 0409.04b0
- CompanyName: Microsoft Corporation
- ProductName: Microsoft® Windows® Operating System
- InternalName: ntkrpamp.exe
- OriginalFilename: ntkrpamp.exe
- ProductVersion: 6.0.6000.20697
- FileVersion: 6.0.6000.20697 (vista_ldr.071009-1543)
- FileDescription: NT Kernel & System
- LegalCopyright: © Microsoft Corporation. All rights reserved.