In this section we examine the effects of the ratio of time spent in library code vs. user code in more detail. To this end we used our ProGenitor program to generate a family of three programs which are identical in all respects except one: the chance of a user function calling another user function as opposed to a library function.
For easy reference, we have named the three programs based on the defining parameter of the chance of a user function calling another user function. In the ``user'' program, each function call made by a user function has a high probability (mean of 99%) of being to another user function. In the ``library'' program it is just the opposite; each function call made by a user function has a low probability (mean of 1%) of being to another user function. The ``equal'' program is in the middle; each function call made by a user function has approximately a 50% chance of being to another user function.
Table 6.16: Common User File Parameters of Programs Generated to Examine
the Effects of the Library/User Ratio on
Performance
Table 6.16 lists the parameters for the user files that are common between the three programs.
Table 6.17: Library File Parameters of Programs Generated to Examine
the Effects of the Library/User Ratio on
Performance
Table 6.17 lists the parameters for the library files for the three programs, all of which are the same for all of the programs. The meaning of the parameters is explained in detail in Section 5.1. However, an explanation of the format of the values is in order.
In addition to fixed values, some of the parameters have been specified as following either a uniform or normal distribution, as described in Chapter 5. Uniform distributions are specified with a ``u'' followed by the minimum and maximum allowed values. Normal distributions are specified with an ``n'' followed by the mean, the standard deviation, and the minimum and maximum allowed values, in that order.
Table 6.18 summarizes the one parameter that varies between the three programs.
Table 6.18: Chance of Calling Another User Function
Each value is specified as a normal distribution with a small standard deviation so that there is a little variance in the value generated for each function call, but not much.
Table 6.19 summarizes the total execution times of the continuous compiler for all three of the test programs. Times are again in seconds.
Table 6.19: Variation of Library/User Ratio
As expected, we see a steady increase in performance as the amount of time spent in library functions increases. The ``library'' program performs better than the ``equal'' program which in turn performs better than the ``user'' program. For comparison purposes, each program would need 96.140 seconds to compile and 40.000 seconds to execute using a traditional compilation model, for a total of 136.140 seconds. Even the worst case performance of the ``user'' program beats that by a fair margin.
When we examine the values to compare the performance of the two replacement strategies on the three programs, we see they are about equal. This suggests that the behavior file was generated in such a way as to not cause the problem seen with ghostview where we were stuck interpreting the first few functions entered for the entire lifetime of the program. This is, unfortunately, a drawback to the way the ProGenitor program is implemented. With the current version of ProGenitor, there is no way to give any function more importance over another. In other words, there is no way to emulate specific types of program structures, such as event-loops.
When we look at the values to compare the seven compilation strategies, we again see a difference from the programs studied earlier. This time it the smallest-first strategy which performs the best for both the ``user'' and ``equal'' programs, and it does so for both replace-at-call and replace-preemptive. For the ``library'' program, like the real programs studied in Section 6.5, it is the again the longest-overall strategy that performs the best, for both replacement strategies.