The Linux Symmetrical Multiprocessing (SMP) Model
Types of Multiprocessing
A multiprocessing system consists of a number of processors communicating via a bus or a network. There are two types of multiprocessing systems: loosely coupled and tightly coupled.
Loosely coupled systems consist of processors that operate stand-alone. Each processor has its own bus, memory, and I/O subsystem, and communicates with other processors through the network medium. Loosely coupled systems can be either homogeneous or heterogeneous.
Tightly coupled systems consist of processors that share the memory, bus, devices, and sometimes cache. Tightly coupled systems run a single instance of the operating system. Tightly coupled systems can be classified into symmetric and asymmetric systems. Asymmetric systems are configured so that each processor is assigned a specific task. Asymmetric systems have a single "master" processor that controls all others. Symmetric systems treat all processors the same way—processes have equal access to all system resources. In the symmetric model, all tasks are spread equally across all processors.
Symmetric systems are subdivided into further classes consisting of dedicated and shared cache systems. Symmetrical Multiprocessing (SMP) systems have become very popular and have become the default choice for many large servers.
Concurrency and Data Serialization
In an ideal world, an SMP system with n processors would perform n times better than a uniprocessor system. In reality, this is not the case. The main reason that no SMP system is 100% scalable is because of the overhead involved in maintaining additional processors.
Locks, Lock Granularity, and Locking Overhead
Locks basically protect multiple threads from accessing or modifying a piece of critical information at the same time. Locks are especially used on SMP systems where multiple processors execute multiple threads at the same time. The problem with locking is that if two or more processors are competing for the same lock at the same time, only one is granted the lock, and the other waits, spinning, for the lock to be released. In other words, the other processors are not really doing any useful work. Locking, therefore, must be limited to the smallest amount of time possible.
Another common technique used to address this problem is to employ finer-grain locking. With finer-grain locking, instead of using a single lock to protect 100 things, 100 locks are used instead. Although the concept seems very simple, most of the time, it is hard to implement because of various interactions, dependencies, and deadlock. You need to program methodically to prevent deadlock situations, compared to having a single lock.
Another important area to consider is locking overhead. All locking techniques come with a price. Operating system designers need to choose the right kind of locking primitive to address a rights issue. In Linux 2.6, most global locks are removed and most of the locking primitives are optimized for extremely low overhead.
Cache coherency is a problem that occurs in multiprocessors, because each processor has an individual cache, and multiple copies of certain data exist in the system. When the data is changed, only one processor’s cache has the new value. All other processors’ cache has old values.
Processor affinity is one of the most important things that can improve system performance. As processes access various resources in the system, lots of information about the resources will be in processor caches, so it’s better for a processor to run on the same processor due to the cache warmth. In some architectures, especially with NUMA, some resources are closer to the processor compared to others in the same system. In these systems, processor affinity is extremely important for system performance.
The file system is one of the most important parts of an operating system. In the following sections, the Linux alternative in file systems explains how well Linux has you covered.