jeffr_tech (jeffr_tech) wrote,
jeffr_tech
jeffr_tech

Using inlines to reduce code duplication

I recently was able to use a neat trick in my scheduler code that I thought I'd share. It might be old news to many of you and it doesn't come up a lot but it's useful when it does. The basic notion is that you can use inlines with const arguments to create a sort of parameterized function with no duplicated code post-compile.


Consider a common set of steps with minor deviations that you don't want to duplicate but you also don't want to pay the cost of extra conditionals in a very frequently executed function. In my case, it's the routine that searches the cpu tree for load conditions. It may have to find the least or most loaded cpu, or both least and most loaded cpus given some parameters. So I create an inline function that handles all three cases that takes an argument which specifies which cases are desired.

When this inline is invoked at a particular call site the required cases are specified with a constant so the dead code elimination phase of the compiler kills everything in the cases we don't care about. So I'm able to maintain a single function which traverses the tree without paying the cost of having a fully generic algorithm. In this case the function is actually recursive so I create three non-inlined functions which handle the three variations by calling the inline with the right parameters. The inline itself then has a switch statement to select the correct invocation. The switch actually just compiles away into nothing.

The code, abbreviated, looks something like this:

#define CPU_SEARCH_LOWEST       0x1
#define CPU_SEARCH_HIGHEST      0x2
#define CPU_SEARCH_BOTH         (CPU_SEARCH_LOWEST|CPU_SEARCH_HIGHEST)

static inline int
cpu_search(struct cpu_group *cg, struct cpu_search *low,
    struct cpu_search *high, const int match)
{

        if (cg->cg_children) {
                /* boilerplate goes here */
                for (i = 0; i < cg->cg_children; i++) {
                        if (match & CPU_SEARCH_LOWEST) {
                                ...
                        }
                        if (match & CPU_SEARCH_HIGHEST) {
                                ...
                        }
                        switch (match) {
                        case CPU_SEARCH_LOWEST:
                                load = cpu_search_lowest(child, &lgroup);
                                break;
                        case CPU_SEARCH_HIGHEST:
                                load = cpu_search_highest(child, &hgroup);
                                break;
                        case CPU_SEARCH_BOTH:
                                load = cpu_search_both(child, &lgroup, &hgroup);
                                break;
                        }
                        if (match & CPU_SEARCH_LOWEST) {
                                ...
                        }
                        if (match & CPU_SEARCH_HIGHEST) {
                                ...
                        }
                }
        } else {
                int cpu;

                CPUMASK_FOREACH(cpu, cg->cg_mask)
                        total += cpu_compare(cpu, low, high, match);
        }
        return (total);
}
int
cpu_search_lowest(struct cpu_group *cg, struct cpu_search *low)
{
        return cpu_search(cg, low, NULL, CPU_SEARCH_LOWEST);
}

int
cpu_search_highest(struct cpu_group *cg, struct cpu_search *high)
{
        return cpu_search(cg, NULL, high, CPU_SEARCH_HIGHEST);
}

int
cpu_search_both(struct cpu_group *cg, struct cpu_search *low,
    struct cpu_search *high)
{
        return cpu_search(cg, low, high, CPU_SEARCH_BOTH);
}




cpu_compare() is a small inline which does the same trick. I have verified that even at low optimization settings gcc will spit out three small functions with only the required code in each rather than one huge function with all of the code and lots of conditionals.

Subscribe
  • Post a new comment

    Error

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 37 comments
Previous
← Ctrl ← Alt
Next
Ctrl → Alt →
Previous
← Ctrl ← Alt
Next
Ctrl → Alt →