|
|
< Previous PageNext Page > |
This section includes some basic tips on performance and stability. You should read the sections on security and performance for additional information. These tips cover only style issues, not general performance or stability issues.
Performance and Stability Tips
Stability Tips
Programming in the kernel is subject to a number of restrictions that do not exist in application programming. The first and most important is the stack size. The kernel has a limited amount of space allocated for thread stacks, which can cause problems if you aren’t aware of the limitation. This means the following:
Recursion must be bounded (to no more than a few levels).
Recursion should be rewritten as iterative routines where possible.
Large stack variables (function local) are dangerous. Do not use them. This also applies to large local arrays.
Dynamically allocated variables are preferred (using malloc
or equivalent) over local variables for objects more than a few bytes in size.
Functions should have as few arguments as possible.
Pass pointers to structures, not the broken out elements.
Don’t use arguments to avoid using global or class variables.
Do name global variables in a way that protects you from collision.
C++ functions should be declared static.
Functions not obeying these rules can cause a kernel panic, or in extreme cases, do not even compile.
In addition to issues of stack size, you should also avoid doing anything that would generate unnecessary load such as polling a device or address. A good example is the use of mutexes rather than spinlocks. You should also structure your locks in such a way to minimize contention and to minimize hold times on the most highly contended locks.
Also, since unused memory (and particularly wired memory) can cause performance degradation, you should be careful to deallocate memory when it is no longer in use, and you should never allocate large regions of wired memory. This may be unavoidable in some applications, but should be avoided whenever possible and disposed of at the earliest possible opportunity. Allocating large contiguous blocks of memory at boot time is almost never acceptable, because it cannot be released.
There are a number of issues that you should consider when deciding whether to use floating point math or AltiVec vector math in the kernel.
First, the kernel takes a speed penalty whenever floating-point math or AltiVec instructions are used in a system call context (or other similar mechanisms where a user thread executes in a kernel context), as floating-point and AltiVec registers are only maintained when they are in use.
Note: In cases where altivec or floating point has already been used in user space in the calling thread, there is no additional penalty for using them in the kernel. Thus, for things like audio drivers, the above does not apply.
In general, you should avoid doing using floating-point math or AltiVec instructions in the kernel unless doing so will result in a significant speedup. It is not forbidden, but is strongly discouraged.
Second, AltiVec was not supported in the kernel prior to Mac OS X 10.3. It was not possible to detect this support from within the kernel until a later 10.3 software update. If you must deploy your KEXT on earlier versions of Mac OS X, you must either provide a non-AltiVec version of your code or perform the AltiVec instructions in user space.
Finally, AltiVec data stream instructions (dst
, dstt
, dstst
, dss
, and dssall
) are not supported in the kernel, even for processors that support them in user space. Do not attempt to use them.
If you decide to use AltiVec in the kernel, your code can determine whether the CPU supports AltiVec using the sysctlbyname
call to get the hw.optional.altivec
property. For more information, see “The sysctlbyname System Call”.
Don’t sleep while holding resources (locks, for example). While this is not forbidden, it is strongly discouraged to avoid deadlock.
Be careful to allocate and free memory with matching calls. For example, do not use allocation routines from the I/O Kit and deallocation routines from BSD. Likewise, do not use IOMallocContiguous
with IOFreePageable
.
Use reference counts to avoid freeing memory that is still in use elsewhere. Be sure to deallocate memory when its reference count reaches zero, but not before.
Lock objects before operating on them, even to change reference counts.
Never dereference pointers without verifying that they are not NULL
. In particular, never do this:
int foo = *argptr; |
unless you have already verified that argptr
cannot possibly be NULL
.
Test code in sections and try to think up likely edge cases for calculations.
Never assume that your code will be run only on big endian processors.
Never assume that the size of an instance of a type will never change. Always use sizeof
if you need this information.
Never assume that a pointer will always be the same size as an int
or long
.
< Previous PageNext Page > |
Last updated: 2006-11-07
|
Get information on Apple products.
Visit the Apple Store online or at retail locations. 1-800-MY-APPLE Copyright © 2007 Apple Inc. All rights reserved. | Terms of use | Privacy Notice |