figure 1: header file showing
version numbers.
#define PMC_VERSION_MAJOR0x03
#define PMC_VERSION_MINOR0x00
#define PMC_VERSION_PATCH0x0000
fact that there are version numbers.
The engineer clearly knew his software
would be modified not only by himself
but also by others, and he has specifically allowed for that by having major,
minor, and patch version numbers.
Simple? Yes. Found often? No.
The next set of lines—and remember this is only the first file I opened—
were also instructive, as shown in Figure 2. Frequent readers of KV might
think it was the comment that made
me happy, but they would be wrong.
It was the translation of constants
into intelligible textual names. Nothing is more frustrating when working
on a piece of software than having to
remember yet another stupid, usually
hex, constant. I am not impressed by
programmers who can remember they
numbered things from 0x100 and that
0x105 happens to be significant. Who
cares? I don’t. What I want is code that
uses descriptive names. Also note the
constants in the code aren’t very long,
but are just long enough to make it
easy to know in the code which chip
we’re talking about.
Figure 3 shows another fine example from the header file. I’ve used this
snippet so I can avoid including the
whole file. Here, machine-dependent
structures are separated from machine-independent structures. It would seem
obvious that you want to separate the
bits of data that are specific to a certain type of CPU or device from data
that is independent, but what seems
obvious is rarely done in practice. The
fact that the engineer thought about
which bits should go where indicates a
figure 2: translation of constants into descriptive names.
/*
* Kinds of CPUs known
*/
#define __PMC_CPUS() \
__PMC_CPU(AMD_K7, “AMD K7”) \
__PMC_CPU(AMD_K8, “AMD K8”) \
__PMC_CPU(INTEL_P5, “Intel Pentium”) \
__PMC_CPU(INTEL_P6, “Intel Pentium Pro”) \
__PMC_CPU(INTEL_CL, “Intel Celeron”) \
__PMC_CPU(INTEL_PII, “Intel Pentium II”) \
__PMC_CPU(INTEL_PIII, “Intel Pentium III”) \
__PMC_CPU(INTEL_PM, “Intel Pentium M”) \
__PMC_CPU(INTEL_PIV, “Intel Pentium IV”)
high level of quality in the code. Read
the descriptive comments for each
element and the indication of where
the proper types can be found, as in
the case of pmd_cputype being from
enum pmc_cputtype.
One final comment on this file.
Note that the programmer is writing
objects in C. Operating system kernels
and other low-level bits of code are still
written in C, and though there are plenty of examples now of people trying to
think differently in this respect (such
as Apple’s Mac OS X drivers being written in C++) low-level code will continue
to be written in C. That does not mean
programmers should stop using the
lessons they learned about data encapsulation, but rather that it is important
to do the right thing when possible.
The structure listed here is an object.
It has data and methods to act upon it.
The BSD kernels have used this methodology for 20-plus years at this point,
and it’s a lesson that should be learned
and remembered by others.
These are just a few examples from
this code, but in file after file I have
found the same level of quality, the
same beautiful code. If you’re truly
interested in seeing what good code
looks like, then I recommend you read
the code yourself. If any place is a “
happy place,” it is in code such as this.
KV
figure 3: machine-dependent structures
are separated from machine-independent structures.
/*
* struct pmc_mdep
*
* Machine dependent bits needed per CPU type.
*/
P.S. Complete code cross-references for
many operating system kernels, including FreeBSD, can be found at http://fxr.
watson.org/ and the code you’re looking for can be found at: http://fxr.
watson.org/fxr/source/dev/hwpmc/.
A similar set of cross-references
can be found on the codespelunking
site: http://www.codespelunking.org/
freebsd-current/htags/.
struct pmc_mdep {
uint32_t pmd_cputype; /* from enum pmc_cputype */
uint32_t pmd_npmc; /* max PMCs per CPU */
uint32_t pmd_nclass; /* PMC classes supported */
struct pmc_classinfo pmd_classes[PMC_CLASS_MAX];
int pmd_nclasspmcs[PMC_CLASS_MAX];
/*
* Methods
*/
int (*pmd_init)(int _cpu); /* machine dependent initialization */
int (*pmd_cleanup)(int _cpu); /* machine dependent cleanup */
Dear KV,
In his book The Mythical Man-Month,
Frederick P. Brooks admonishes us
with grandfatherly patience to plan
to build a prototype—and to throw it
away. You will anyway.
At one point this resulted in a fad-of-the-year called prototyping (the
programming methodology formerly
known as trial and error), demonstrating that too little and too much are
equally as bad.