Hawk
Software
jump to page text
· Home
· Free software
· Commercial software
· Articles
· Download
· Message boards
· Links
· Contact info
· Press
|
Library Memory Standard, 2nd Draft
A proposal for high performance libraries
By Phil Frisbie, Jr.
Background
Many programmers use libraries to speed up the development time of applications. The standard C
library is an example of a library used by most C applications. Other third party libraries
provide enhanced functions for such things as graphics, sound, networking, and input. Many
libraries also offer cross platform compatibility so that porting applications is easier.
Libraries vary in quality and functionality, but many have one flaw in common, and that is poor
memory integration with the application. These libraries need to allocate temporary memory, and
they simply use the C run-time (CRT) malloc and free functions. While this is fine for many
applications, it can cause problems with high performance applications that use a custom memory
manager (CMM).
High performance applications, such as games, can often receive a large boost in performance by
using a CMM. The CRT memory functions are designed to be general purpose, but the CMM can be
tuned to the type of memory allocations common in the application. The CMM can also include
additional run-time debugging to help quickly track down memory access errors. When an
application using a CMM is linked to a library that uses CRT memory functions, it will not
perform it's best, it can make debugging harder, and it could cause memory leaks if memory is
allocated by the CRT and the application tries to free it using the CMM.
There is another problem unique to Windows when the library is supplied as a DLL. There are two
CRT DLLs (single and multithreaded) that the application or library might dynamically link to,
or it may even be statically linked to one of those CRTs. So, there are 16 possible combinations
of application and library run times! The following proposal also eliminates this problem.
The proposal
The Library Memory Standard is composed of four parts:
The API interface between the application and the library.
The internal library API.
The optional CMM for use inside the library (the library internal CMM, or LCMM).
Documentation listing the library functions that allocate and free memory.
The API interface provides a way to allow the library to be made aware of the application's CMM.
The API is two functions with six type defines, as prototyped below. (Note: 'xyz' is the prefix
used by the example library, and will be substituted by the library prefix in a real library)
/* These two function callbacks are required in the application */
typedef void *(*CMMmalloc)(size_t size, char *name);
typedef void (*CMMfree)(void *memblock, char *name);
/* This function callback is optional in the application */
typedef void *(*CMMrealloc)(void *memblock, size_t size, char *name);
/* These are required in the library interface */
void xyzSetCMM(CMMmalloc m, CMMfree f, CMMrealloc r);
void xyzHint(enum hint, int value);
The three function prototypes, CMMmalloc, CMMfree, and CMMrealloc are callback functions to be
included in the application. The last parameter, a char string, may be used for debugging or
memory profiling, or it may be ignored. A NULL char string must be accepted properly by these
functions.
The first function, xyzSetCMM, is used to hook the library's memory allocation functions.
This function, and xyzHint, should be called before any other library functions so that all
memory allocations will use the application's CMM. If the application's CMM does not implement
the equivalent to realloc, then pass NULL so that the library will use it's own realloc
function.
The second function, xyzHint, is used to control the optional LCMM. If there is not an LCMM,
then it will simply be a NOP. The hints will include at least the following: CMM_USE_LCMM, and
CMM_CHUNK_SIZE. The CMM_USE_LCMM hint with a value of '0' will disable the use of the LCMM, and
a value of '1' will enable it. The LCMM will be enabled by default, so if the LCMM is to be
disabled xyzHint should be called before any other library calls, including xyzSetCMM. Enabling
or disabling the LCMM is only guaranteed to succeed before other library functions are called,
and the library may ignore additional calls to enable or disable the LCMM. The CMM_CHUNK_SIZE
will hint at the preferred chunk size that the LCMM should use to allocate memory.
The LCMM will then attempt to only allocate memory using the chunk size or a multiple of the
chunk size. If the chunk size is not hinted, the default can be anything the LCMM prefers.
The internal library API consists of three functions:
void *LMSmalloc(size_t size, char *name);
void LMSfree(void *memblock, char *name);
void *LMSrealloc(void *memblock, size_t size, char *name);
These three functions are basically the ANSI C memory functions with an additional parameter.
This additional parameter, a null terminated string no longer than 31 characters, can be
used for debugging and/or memory profiling in either the CMM or LCMM. For example, if the CMM
supports the debugging string, the following will help it track the allocation:
struct player_t *p;
p = (struct plater_t *)LMSmalloc(sizeof(struct player_t), "struct player_t");
....
LMSfree(p, "struct player_t");
Or the library could use this to record the source file name and line of the allocation:
#define mymalloc(pointer, size) {\
char filename__[256] = __FILE__; \
char temp__[300]; \
sprintf(temp__, "%s, line %d", filename__, __LINE__); \
pointer = LMSmalloc(size, temp__); \
}
mymalloc(p, sizeof(struct player_t));
If the library programmers do not want to use the char * argument, which might be the case for
a closed source product, they may use NULL. However, to help
future debugging, they would be advised to at least use an obfuscated name such as 'struct 112'
or '5643', anything that will help them debug a memory allocation error if an application
programmer finds one.
The optional LCMM will boost the performance of the library if the application does not have a
CMM, but even if the application does have a CMM, it may not work well for the library. The LCMM
will cause more memory to be allocated to the library, so performance testing should be done to
see if the performance boost is worth the extra memory usage. The library code needed to
implement the LCMM is beyond the scope of this proposal. If it is provided, it should be highly
tuned to the needs of the library.
The last item, the documentation listing the library functions that allocate and free memory, is
perhaps the easiest but most tedious part, and very important to the application programmer. This
documentation should at least list which functions allocate and/or free memory. The approximate
amount of memory allocated could also be useful in cases where the library will be using the
application's CMM. The application's CMM could then be tuned for the common allocation sizes
needed by the library.
Conclusion
These guidelines are designed to make libraries not only easier to use, but faster and better
documented. They are not intentionally biased towards any operating system, compiler, or library
type. Although my examples are specific to C applications and libraries, these guidelines can be
adapted to any language that supports allocating and freeing memory dynamically.
Comments and suggestions are welcome, and this proposal will be updated accordingly. Send all
comments to Phil Frisbie, Jr..
Page last modified:
10 August 2005
© 1998-2006 Hawk Software
|
|