of non-deterministic programs. I.e., such programs may exhibit a different thread scheduling when they are executed with or without instrumentation.
Because of the fine-grained, deterministic activation control of man- agement code, a CPU manager can precisely restrict the further execution of a thread. A CPU manager allows each thread to exe- cute only a limited number of its own bytecode instructions before re-executing management code. This is essential to thwart denial-of- service attacks, which is one of our goals. Our CPU manager activation scheme allows for pre-accounting, since a CPU manager may permit a thread to execute a certain number of bytecode instructions only if this execution is guaranteed not to exceed a given quota.
Our primary design goal is full portability of the CPU manage- ment scheme, which shall be compatible with any JVM. As we rely on bytecode instrumentation, one important issue is to keep the over- head caused by the inserted bytecode low. While a certain overhead inevitably is the price one has to pay for platform-independent, fully portable CPU management, we have devised several optimization schemes to reduce the overhead, as discussed in Sections 4, 5, and 6.
Another design goal is to support the coexistence of code that has been transformed for CPU management with unmodified code. For instance, a middleware system may want to account only for the exe- cution of deployed components (e.g., Servlets, Enterprise Java Beans, etc.), but not for the execution of certain management tasks within the middleware platform. Accounting only for the execution of those parts of the code where the accounting information is actually needed helps to reduce the overall accounting overhead. For this reason, and because of the possibility of dynamic class loading in Java, we currently abstain from global (interprocedural or intermodular) program analysis and transformation, to enable the user to decide for each method whether it shall be rewritten for accounting or not. In other words, we require that all transformations maintain the compatibility of rewritten code with unmodified code.
3. Principles of the CPU Accounting Scheme
The general idea of our approach is that the bytecode of software components is rewritten in order to make their resource consump- tion explicit. We informally define a component as a group of threads running under the supervision of the same CPU Manager. As shown in Figure 1, threads maintain the count of executed bytecodes inside