- 论坛徽章:
- 0
|
GCC hacks in the Linux kernel
Discover GCC extensions for the C language
M. Tim Jones, Consultant Engineer, Emulex Corp.
18 Nov 2008
The Linux? kernel uses several special capabilities of the GNU Compiler Collection (GCC) suite. These capabilities range from giving you shortcuts and simplifications to providing the compiler with hints for optimization. Discover some of these special GCC features and learn how to use them in the Linux kernel.
GCC and Linux are a great pair. Although they are independent pieces of software, Linux is totally dependent on GCC to enable it on new architectures. Linux further exploits features in GCC, called extensions, for greater functionality and optimization. This article explores many of these important extensions and shows you how they're used within the Linux kernel.
GCC in its current stable version (version 4.3.2) supports three versions of the C standard:
* The original International Organization for Standardization (ISO) standard of the C language (ISO C89 or C90)
* ISO C90 with amendment 1
* The current ISO C99 (the default standard that GCC uses and that this article assumes)
Note: This article assumes that you are using the ISO C99 standard. If you specify a standard older than the ISO C99 version, some of the extensions described in this article may be disabled. To specify the actual standard that GCC uses, you can use the -std option from the command line. Use the GCC manual to verify which extensions are supported in which versions of the standard (see Resources for a link).
Applicable versions
This article focuses on the use of GCC extensions in the 2.6.27.1 Linux kernel and version 4.3.2 of GCC. Each C extension refers to the file in the Linux kernel source where the example can be found.
The available C extensions can be classified in several ways. This article puts them in two broad categories:
* Functionality extensions bring new capabilities from GCC.
* Optimization extensions help you generate more efficient code.
Functionality extensions
Let's start by exploring some of the GCC tricks that extend the standard C language.
Type discovery
GCC permits the identification of a type through the reference to a variable. This kind of operation permits a form of what's commonly referred to as generic programming. Similar functionality can be found in many modern programming languages such as C++, Ada, and the Java? language. Linux uses typeof to build type-dependent operations such as min and max. Listing 1 shows how you can use typeof to build a generic macro (from ./linux/include/linux/kernel.h).
Listing 1. Using typeof to build a generic macro
#define min(x, y) ({ \
typeof(x) _min1 = (x); \
typeof(y) _min2 = (y); \
(void) (&_min1 == &_min2); \
_min1 len, skb->csum));
if (likely(!sum)) {
if (unlikely(skb->ip_summed == CHECKSUM_HW))
netdev_rx_csum_fault(skb->dev);
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
return sum;
}
Prefetching
Another important method of improving performance is through caching of necessary data close to the processor. Caching minimizes the amount of time it takes to access the data. Most modern processors have three classes of memory:
* Level 1 cache commonly supports single-cycle access
* Level 2 cache supports two-cycle access
* System memory supports longer access times
To to minimize access latency, and thus improve performance, it's best to have your data in the closest memory. Performing this task manually is called prefetching. GCC supports manual prefetching of data through a built-in function called __builtin_prefetch. You use this function to pull data into the cache shortly before it's needed. As shown below, the __builtin_prefetch function takes three arguments:
* The address of the data
* The rw parameter, which you use to indicate whether the data is being pulled in for Read or preparing for a Write operation
* The locality parameter, which you use to define whether the data should be left in cache or purged after use
void __builtin_prefetch( const void *addr, int rw, int locality );
Prefetching is used extensively by the Linux kernel. Most often it is used through macros and wrapper functions. Listing 6 is an example of a helper function that uses a wrapper over the built-in function (from ./linux/include/linux/prefetch.h). The function implements a preemptive look-ahead mechanism for streamed operations. Using this function can generally result in better performance by minimizing cache misses and stalls.
Listing 6. Wrapper function for range prefetching
#ifndef ARCH_HAS_PREFETCH
#define prefetch(x) __builtin_prefetch(x)
#endif
static inline void prefetch_range(void *addr, size_t len)
{
#ifdef ARCH_HAS_PREFETCH
char *cp;
char *end = addr + len;
for (cp = addr; cp < end; cp += PREFETCH_STRIDE)
prefetch(cp);
#endif
}
Variable attributes
In addition to the function attributes discussed earlier in this article, GCC provides attributes for variables and type definitions. One of the most important of these is the aligned attribute, which is used for object alignment in memory. In addition to being important for performance, object alignment may be required for particular devices or hardware configurations. The aligned attribute takes a single argument that specifies the desired type of alignment.
The following example is used for software suspend (from ./linux/arch/i386/mm/init.c). The PAGE_SIZE object is defined as needing page alignment.
char __nosavedata swsusp_pg_dir[PAGE_SIZE]
__attribute__ ((aligned (PAGE_SIZE)));
The example in Listing 7 illustrates a couple of points regarding optimization:
* The packed attribute packs the elements of a structure so that it consumes the least amount of space possible. This means that if a char variable is defined, it will consume no more than a byte (8 bits). Bit fields are compressed into a bit rather than consuming more storage.
* This source presentation is optimized by use of a single __attribute__ specification that defines multiple attributes with a comma-delimited list.
Listing 7. Structure packing and setting multiple attributes
static struct swsusp_header {
char reserved[PAGE_SIZE - 20 - sizeof(swp_entry_t)];
swp_entry_t image;
char orig_sig[10];
char sig[10];
} __attribute__((packed, aligned(PAGE_SIZE))) swsusp_header;
Going further
This article provides only a glimpse of the techniques made available by GCC in the Linux kernel. You can read more about all the available extensions for both C and C++ in the GNU GCC manual (see Resources for a link). And although the Linux kernel makes great use of these extensions, they are all available to you for use in your own applications as well. As GCC continues to evolve, new extension are sure to further improve the performance and increase the functionality of the Linux kernel.
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/12592/showart_1673244.html |
|