持之以恒的成语故事:线程亲和

来源:百度文库 编辑:中财网 时间:2024/04/28 13:09:14
Home
Topics
Community Resources
Forums
Shop
Magazine
Buyer's Guide
Login 
Home
CPU Affinity
July 1st, 2003 by Robert Love inSoftware
Bind specific processes to specific processors with a new system call.
Average:Select ratingCancel ratingPoorOkayGoodGreatAwesomeYour rating: None Average: 4.5 (10 votes)

The ability in Linux to bind one or more processes to one or more processors, called CPU affinity, is a long-requested feature. The idea is to say “always run this process on processor one” or “run these processes on all processors but processor zero”. The scheduler then obeys the order, and the process runs only on the allowed processors.
Other operating systems, such as Windows NT, have long provided a system call to set the CPU affinity for a process. Consequently, demand for such a system call in Linux has been high. Finally, the 2.5 kernel introduced a set of system calls for setting and retrieving the CPU affinity of a process.
In this article, I look at the reasons for introducing a CPU affinity interface to Linux. I then cover how to use the interface in your programs. If you are not a programmer or if you have an existing program you are unable to modify, I cover a simple utility for changing the affinity of a given process using its PID. Finally, we look at the actual implementation of the system call.
Soft vs. Hard CPU Affinity
There are two types of CPU affinity. The first, soft affinity, also called natural affinity, is the tendency of a scheduler to try to keep processes on the same CPU as long as possible. It is merely an attempt; if it is ever infeasible, the processes certainly will migrate to another processor. The new O(1) scheduler in 2.5 exhibits excellent natural affinity. On the opposite end, however, is the 2.4 scheduler, which has poor CPU affinity. This behavior results in the ping-pong effect. The scheduler bounces processes between multiple processors each time they are scheduled and rescheduled. Table 1 is an example of poor natural affinity; Table 2 shows what good natural affinity looks like.
Table 1. The Ping-Pong Effect
Table 2. Good Affinitiy
Hard affinity, on the other hand, is what a CPU affinity system call provides. It is a requirement, and processes must adhere to a specified hard affinity. If a processor is bound to CPU zero, for example, then it can run only on CPU zero.
Why One Needs CPU Affinity
Before we cover the new system calls, let's discuss why anyone would need such a feature. The first benefit of CPU affinity is optimizing cache performance. I said the O(1) scheduler tries hard to keep tasks on the same processor, and it does. But in some performance-critical situations—perhaps a large database or a highly threaded Java server—it makes sense to enforce the affinity as a hard requirement. Multiprocessing computers go through a lot of trouble to keep the processor caches valid. Data can be kept in only one processor's cache at a time. Otherwise, the processor's cache may grow out of sync, leading to the question, who has the data that is the most up-to-date copy of the main memory? Consequently, whenever a processor adds a line of data to its local cache, all the other processors in the system also caching it must invalidate that data. This invalidation is costly and unpleasant. But the real problem comes into play when processes bounce between processors: they constantly cause cache invalidations, and the data they want is never in the cache when they need it. Thus, cache miss rates grow very large. CPU affinity protects against this and improves cache performance.
A second benefit of CPU affinity is a corollary to the first. If multiple threads are accessing the same data, it might make sense to bind them all to the same processor. Doing so guarantees that the threads do not contend over data and cause cache misses. This does diminish the performance gained from multithreading on SMP. If the threads are inherently serialized, however, the improved cache hit rate may be worth it.
The third and final benefit is found in real-time or otherwise time-sensitive applications. In this approach, all the system processes are bound to a subset of the processors on the system. The specialized application then is bound to the remaining processors. Commonly, in a dual-processor system, the specialized application is bound to one processor, and all other processes are bound to the other. This ensures that the specialized application receives the full attention of the processor.
Getting the New System Calls
The system calls are new, so they are not available yet in all systems. You need at least kernel 2.5.8-pre3 and glibc 2.3.1; glibc 2.3.0 supports the system calls, but it has a bug. The system calls are not yet in 2.4, but patches are available at www.kernel.org/pub/linux/kernel/people/rml/cpu-affinity.
Many distribution kernels also support the new system calls. In particular, Red Hat 9 is shipping with both kernel and glibc support for the new calls. Real-time solutions, such as MontaVista Linux, also fully support the new interface.
Affinity Masks
On most systems, Linux included, the interface for setting CPU affinity uses a bitmask. A bitmask is a series of n bits, where each bit individually corresponds to the status of some other object. For example, CPU affinity (on 32-bit machines) is represented by a 32-bit bitmask. Each bit represents whether the given task is bound to the corresponding processor. Count the bits from right to left, bit 0 to bit 31 and, thus, processor zero to processor 31. For example:
11111111111111111111111111111111 = 4,294,967,295
is the default CPU affinity mask for all processes. Because all bits are set, the process can run on any processor. Conversely:
00000000000000000000000000000001 = 1is much more restrictive. Only bit 0 is set, so the process may run only on processor zero. That is, this affinity mask binds a process to processor zero.
 
Get it? What do the next two masks equal in decimal? What is the result of using them as the affinity mask of a process?
1000000000000000000000000000000000000000000000000000000000000011
The first is equal to 2,147,483,648 and, because bit 31 is set, binds the process to processor number 31. The second is equal to 3, and it binds the process in question to processor zero and processor one.
The Linux CPU affinity interface uses a bitmask like that shown above. Unfortunately, C does not support binary constants, so you always have to use the decimal or hexadecimal equivalent. You may get a compiler warning for very large decimal constants that set bit 31, but they will work.
Using the New System Calls
With the correct kernel and glibc in hand, using the system calls is easy:
#define _GNU_SOURCE#include longsched_setaffinity(pid_t pid, unsigned int len, unsigned long *user_mask_ptr);longsched_getaffinity(pid_t pid, unsigned int len, unsigned long *user_mask_ptr);
The first system call is used to set the affinity of a process, and the second system call retrieves it.
In either system call, the PID argument is the PID of the process whose mask you wish to set or retrieve. If the PID is set to zero, the PID of the current task is used.
The second argument is the length in bytes of the CPU affinity bitmask, currently four bytes (32 bits). This number is included in case the kernel ever changes the size of the CPU affinity mask and allows the system calls to be forward-compatible with any changes; breaking syscalls is bad form, after all. The third argument is a pointer to the bitmask itself.
Let us look at retrieving the CPU affinity of a task:
unsigned long mask;unsigned int len = sizeof(mask);if (sched_getaffinity(0, len, &mask) < 0) { perror("sched_getaffinity"); return -1; }printf("my affinity mask is: %08lx\n", mask);
As a convenience, the returned mask is binary ANDed against the mask of all processors in the system. Thus, processors in your system that are not on-line have corresponding bits that are not set. For example, a uniprocessor system always returns 1 for the above call (bit 0 is set and no others).
Setting the mask is equally easy:
unsigned long mask = 7; /* processors 0, 1, and 2 */unsigned int len = sizeof(mask);if (sched_setaffinity(0, len, &mask) < 0) { perror("sched_setaffinity");}
This example binds the current process to the first three processors in the system.
You then can call sched_getaffinity() to ensure the change took effect. What does sched_getaffinity() return for the above setup if you have only two processors? What if you have only one? The system call fails unless at least one processor in the bitmask exists. Using a mask of zero always fails. Likewise, binding to processor seven if you do not have a processor seven will fail.
It is possible to retrieve the CPU affinity mask of any process on the system. You can set the affinity of only the processes you own, however. Of course, root can set any process' affinity.
I Want a Tool!
If you are not a programmer, or if you cannot modify the source for whatever reason, you still can bind processes. Listing 1 is the source code for a simple command-line utility to set the CPU affinity mask of any process, given its PID. As we discussed above, you must own the process or be root to do this.
Listing 1. bind
Usage is simple; once you learn the decimal equivalent of the CPU mask, you need:
usage: bind pid cpu_mask
As an example, assume we have a dual computer and want to bind our Quake process (with PID 1600) to processor two. We would enter the following:
bind 1600 2
 
Getting Really Crafty
In the previous example, we bound Quake to one of the two processors in our system. To ensure top-notch frame rates, we need to bind all the other processes on the system to the other processor. You can do this by hand or by writing a crafty script, but neither is efficient. Instead, make use of the fact that CPU affinity is inherited across a fork(). All of a process' children receive the same CPU affinity mask as their parent.
Then, all we need to do is have init bind itself to one processor. All other processes, by nature of init being the root of the process tree and thus the superparent of all processes, are then likewise bound to the one processor.
The cleanest way to do this type of bind is to hack this feature into init itself and pass in the desired CPU affinity mask using the kernel command line. We can accomplish our goal with a simpler solution, though, without having to modify and recompile init. Instead, we can edit the system startup script. On most systems this is /etc/rc.d/rc.sysinit or /etc/rc.sysinit, the first script run by init. Place the sample bind program in /bin, and add these lines to the start of rc.sysinit:
/bin/bind 1 1/bin/bind $$ 1
These lines bind init (whose PID is one) and the current process to processor zero. All future processes will fork from one of these two processes and thus inherit the CPU affinity mask. You then can bind your process (whether it be a real-time nuclear control system or Quake) to processor one. All processes will run on processor zero except our special process (and any children), which will run on processor one. This ensures that the entire processor is available for our special process.
Kernel Implementation of CPU Affinity
Long before Linus merged the CPU affinity system calls, the kernel supported and respected a CPU affinity mask. There was no interface by which user space could set the mask.
Each process' mask is stored in its task_struct as an unsigned long, cpus_allowed. The task_struct structure is called the process descriptor. It stores all the information about a process. The CPU affinity interface merely reads and writes cpus_allowed.
Whenever the kernel attempts to migrate a process from one processor to another, it first checks to see if the destination processor's bit is set in cpus_allowed. If the bit is not set, the kernel does not migrate the process. Further, whenever the CPU affinity mask is changed, if the process is no longer on an allowed processor it is migrated to one that is allowed. This ensures the process begins on a legal processor and can migrate only to a legal processor. Of course, if it is bound to only a single processor, it does not migrate anywhere.
Conclusion
The CPU affinity interface introduced in 2.5 and back-ported elsewhere provides a simple yet powerful mechanism for controlling which processes are scheduled onto which processors. Users with more than one processor may find the system calls useful in squeezing another drop of performance out of their systems or for ensuring that processor time is available for even the most demanding real-time task. Of course, users with only one processor need not feel left out. They also can use the system calls, but they aren't going to be too useful.
Resources
 

email: rml@tech9.net
 
Robert Love is a kernel hacker involved in various projects, including the preemptive kernel and the scheduler. He is a Mathematics and Computer Science student at the University of Florida and a kernel engineer at MontaVista Software. He enjoys photography.
__________________________
 
 
Special Magazine Offer -- Free Gift with Subscription
Receive a free digital copy of Linux Journal's System Administration Special Edition as well as instant online access to current and past issues. CLICK HERE for offer
Linux Journal: delivering readers the advice and inspiration they need to get the most out of their Linux systems since 1994.
Printer-friendly version
 Delicious
 Digg
 Reddit
 Newsvine
 Technorati
Comment viewing options
Flat list - collapsedFlat list - expandedThreaded list - collapsedThreaded list - expanded
Date - newest firstDate - oldest first
10 comments per page30 comments per page50 comments per page70 comments per page90 comments per page150 comments per page200 comments per page250 comments per page300 comments per page
Select your preferred way to display the comments and click "Save settings" to activate your changes.

Check?
On February 13th, 2009 Robbienes (not verified) says:
How can you determine on which processor a process is running?
reply

linux
On October 2nd, 2007 garbage enigmatic encounter mp3 download (not verified) says:
Wine? How do I run . Bye.
reply

setting the cpu affinity for 128 processors
On November 16th, 2005 Swamynath (not verified) says:
HOw to set the affinity for 128 processors. Since thhe bit pattern is unsigned long only 32 bits can be set. I am not sure how to do it for number of cpus greater than 32.?
reply

Help
On October 18th, 2005 Anonymous (not verified) says:
Hi
i want to Linux to bind one or more processes to one or more processors using Java code.but i dont know is it possible thru java.Any help?
reply

Re: Kernel Korner: CPU Affinity
On October 29th, 2003 Anonymous says:
Hi,
I was just wondering if there's a similar way to bind IRQ's to a specific processor? That way drivers designed for single CPU can be used safely on a SMP machine as well.
Mark.
reply

Re: Kernel Korner: CPU Affinity
On November 13th, 2003 Anonymous says:
Just look at /proc/sys/irq/xx/smp_affinity
You can read about it in Documentation/filesystems/proc.txt
reply
Post new comment
Please note that comments may not appear immediately, so there is no need to repost your comment.
Your name:
E-mail:The content of this field is kept private and will not be shown publicly.
Homepage:
Subject:
Comment: *
Allowed HTML tags:
 

    1. Lines and paragraphs break automatically.
      More information about formatting options

      Subscribe
      Renew
      Free Issue
      Customer service
      The Latest
      Job-chopping Chipmaker Bites the Bankruptcy BulletMar-03-09
      Playing Restricted Media When Using UbuntuMar-03-09
      Web Content Filtering with OpenDNSMar-02-09
      LF Looks to Train Techs to Meet Linux DemandMar-02-09
      Better Than Solitaire: Frozen BubbleMar-02-09
      Get ready for "fourth party" servicesMar-01-09
      more
      Newsletter
      Each week Linux Journal editors will tell you what's hot in the world of Linux. You will receive late breaking news, technical tips and tricks, and links to in-depth stories featured onwww.linuxjournal.com.Sign up for our Email Newsletter  
      Tech Tip Videos

      Playing Restricted Media When Using Ubuntu
      Mar-03-09

      Better Than Solitaire: Frozen Bubble
      Mar-02-09

      Commandline 101: Basic Directory Commands
      Feb-26-09

      Install Software from the Command Line in openSUSE
      Feb-25-09
      See more Linux Journal Videos
      Recently Popular
      Playing Restricted Media When Using Ubuntu5
      Boot with GRUB4.21154
      Why Python?4.491455
      Better Than Solitaire: Frozen Bubble5
      Job-chopping Chipmaker Bites the Bankruptcy Bullet5
      How to Hijack an EU Open Source Strategy Paper4.87879
      more
      From the Magazine
      March 2009, #179
      Linux achieves world domination!! Now, that was The Day The Earth Stood Still...wait, maybe I'm thinking of something else. Oh yeah, scratch that, that's the cover story this month. In any case, don't miss reading about how Linux contributed to the making of this great movie. When you finish that one, don't miss our feature articles about GNOME Do, Xfce, Adobe AIR and a flock of alternative browsers including Opera, CrossOver Chromium and Flock.
      Plus, take a look at this month's Cooking with Linux to see what's new in the recently released KDE 4.2. If you enjoyed last month's cover story, get ready to set up your own virtual reality system with OpenSim. And, if last month's issue left you salivating for more about jQuery, find out how to get started writing your own jQuery plugins. Oh, and are you backed up? If not, make sure you read “When Disaster Strikes: Hard Drive Crashes” before you do anything else. If you thought the people in The Day The Earth Stood Still were having a bad day, wait till your hard drive crashes—aliens would be a welcome sight compared to that. There's all that and much more in this month's issue of Linux Journal!
      Read this issue
      Contribute to the Linux Journal Flickr Pool
      Follow Linux Journal on Twitter
      Add Linux Journal to your RSS reader
      Meet other readers on Facebook
      Get Linux Journal Miis
      Subscribe
      Advertise
      Contact us
      Privacy statement
      Report problems
      RSS Feeds
      Copyright © 1994 - 2009 Linux Journal. All rights reserved.