User transparent mechanism for profile feedback optimization6158049Abstract A profile feedback optimization system is provided. The system accepts as input an original application and produces an optimized version of the application. The system first instruments the original application through an instrumentation process such that when it executes, it generates profile data. During instrumentation, the system configures images in the application to trap any function calls to critical functions. This allows the instrumented version of the application to execute transparently and appear as the original version. The instrumentation process converts each original image of the application to a version that references other instrumented images. The instrumentation process also configures the operating system to execute the instrumented version instead of the original version when the user selects the application for execution. Once instrumented, the instrumented application is executed. During execution, profile data produced from the instrumented images is saved in a database. Once profile data has been generated, an optimization process is used to optimize the original version of the application based upon the profile data. The optimized version is also configured to execute just as the original application, but references optimized images instead of original images. Claims What is claimed is: Description FIELD OF THE INVENTION
TABLE 1
______________________________________
Imports/Exports for Un-instrumented Executable Images
FILE IMPORTS EXPORTS
______________________________________
main.exe dll1.exe FunctionA
main
dll2.exe FunctionD
dll1.exe dll2.exe FunctionC,
FunctionA
FunctionD FunctionB
Forward: FunctionX:dll3.exe
dll2.exe dll3.exe FunctionX
FunctionC
FunctionD
dll3.exe kernel32.dll FunctionE
SearchPath FunctionX
Forward FunctionY:Kernel32.dll
kernel32.exe
-- FunctionY
SearchPath
CreateProcess
GetCommandLine
GetModuleFileName
LoadLibrary
LoadLibraryEx
GetModuleHandle
GetProcessAddress
. . .
. . .
. . .
______________________________________
Whereas the export section of an image lists functions provided by that image, the import section lists filenames of other images and all functions imported from those images. In Table 1, main.exe imports example FunctionA from dll1.exe and FunctionD from dll2.exe, and exports only one function, main, which is called by the operating system when the application 103 is first started. Dll1.exe lists dll2.exe in its import section since, during execution, dll1.exe requires FunctionC and FunctionD which are provided by (i.e., exported from) dll2.exe. Dll1.exe exports functions FunctionA, FunctionB and FunctionX for use by any other image that imports dll1.exe. Note that FunctionX is preceded by a "forward" statement "Forward:dll3.exe." This forward statement indicates that the actual executable object code for FunctionX is not contained within the object code for dll1.exe. Rather, the code for FunctionX is actually contained in the image file designated after the colon ":", which in this case is dll3.exe. FunctionX is said to be "forwarded" in dll1.exe, or, stated another way, dll1.exe forwards calls to FunctionX to dll3.exe. In a similar manner, dll2.exe imports dll3.exe in order to access FunctionX which is exported from dll3.exe. Dll2.exe exports FunctionC and FunctionD for use by any images that import dll2.exe, which in this example are the images main.exe and dll1.exe. Dll3.exe imports only one image, Kernel32.dll, which is a system library that is provided in operating system 106. That is, kernel32.dll is not generated by the compiler 102 when source code 101 is compiled. Kernel32dll is a standard function library that provides object code for functions that are commonly used by application programs, such as application 103. Dll3.exe exports FunctionE, FunctionX, and forwards FunctionY to Kernel32.dll. Finally, Kernel32 does not import any object code files, and exports FunctionY, and other functions. Aside from the example FunctionY, the functions that are listed in the export section for Kernel32.dll in Table 1 are of specific interest to this invention during the instrumentation, execution and optimization processes. Those functions are SearchPath, CreateProcess, GetCommandLine, GetModuleFileName, LoadLibrary, LoadLibraryEx, GetModuleHandle, GetProcessAddress. These function are called "critical" functions. Critical functions are of interest since calls to these functions provide information or services that must be modified to allow the instrumented images to execute transparently, as if they were the original images. This is an important aspect of the system, as will be explained in further detail below. The instrumentation process step 150 is based in part on the observation that if the import and export sections of images in an application program are analyzed, beginning with import section of the main executable image (e.g., main.exe), all executable image files that are referenced during execution of that application can be determined. Accordingly, as each image of an application is instrumented with profile code, the import, export and forward references to other image files or functions are modified to ensure that they reference only other instrumented images, instead of their non-instrumented counterparts. Stated in another way, during instrumentation, file name references are changed in the import and export sections to reflect only other instrumented image file names. Accordingly, when a user executes the instrumented main image 115-a in step 151 (to generate profile data), this main image 115-a will only refer to functions in other instrumented images 115-b-d. Instrumented images 115-b-d in turn will have their import and export sections modified to reflect only other respective instrumented images. When the instrumentation process is complete, reference to non-instrumented images that have an instrumented counterpart (i.e., an instrumented version) will not exist in any images related to an application. As will be explained, altering references in the import and export sections avoids the need for the user to have to copy, rename, or move the original non-instrumented original application images 103 a-d in fear of an instrumented image 115 references a non-instrumented image 103. FIG. 4 is a flow chart showing instrumentation steps 200 through 208 according to the present invention. Steps 200 through 208 are represented by step 150 in FIG. 2 and are performed by the TAS process 104-b in conjunction with the image modifier 104-c. Steps 200 through 208 convert non-instrumented, original application images 103-a through 103-d into corresponding instrumented images 115-a through 115-d. To instrument an entire application, step 200 first loads the original, un-instrumented main image 103-a of the application into memory. Step 201 then analyzes the import section of the main image 103-a and loads any imported images that are referenced. Step 201 then repetitively loads each newly-referenced image that has not already been loaded and performs a similar analysis of its import section. This process repeats until every image referenced by an application has been analyzed. That is, step 201 recursively determines every image that is imported by the images that comprise an application. In the example in Table 1, step 201 loads dll1.exe 103-b and dll2.exe 103-c since they are imported in main.exe 103-a. Then step 201 loads dll3.exe 103-d since this image is listed in the import section of dll2.exe 103-c and has not already been loaded. Finally, step 201 loads kernel32.dll 109, since the import section in dll3.exe 103-d references kernel32.dll 109 which has not already been loaded. Step 202 then loads into memory any images that are referenced via forward entries in the images that were loaded in step 201. Images referenced via forward entries are only loaded in step 201 if they do not already exist in memory (i.e., have not already been loaded). In the example in Table 1, only the images dll3.exe and kernel32.dll are referenced by forward statements in the export sections of dll1.exe and dll3.exe, respectively. Since dll3.exe and kernel32.dll get loaded into memory during step 201, in this example, they are not loaded in step 202. Next, step 203 inserts profiling instructions into each image loaded in steps 201 and/or 202. The image modifier 104-c strategically inserts additional object code into the pre-existing object code of an image. The content, location and purpose of this additional object code, called instrumentation code, is not particularly relevant. Various known instrumentation and profiling strategies are known to those skilled in the art, and these details are not pertinent here. What is important is that the additional instrumentation code, when executed along with the rest of an instrumented image, will output profile data concerning that image or a function in that image. Once all of the images for an application have been modified in step 203, the invention configures the operating system 106 to properly execute the newly available instrumented application. From the user's perspective, the instrumented application effectively replaces the original application. The original application, however, is still available for use if needed. In effect, the system provides a mechanism to "spoof" the user into running the instrumented application with the same command that would be used to run the original non-instrumented version. This is accomplished in step 204 via the registry 106-a. The registry 106-a is a portion of the operating system 106 that identifies what specific image to execute upon receipt of a command from a user. In essence, part of the registry 106-a is a lookup table that matches user commands with programs that are to be executed. Specific to this system, a registry entry is created that instructs the operating system to run the instrumented application whenever the user give the command to run the original application. Step 204 therefore configures the registry 106-a of the operating system 106 with the location of the main image 115-a of the instrumented application. In the preferred embodiment, which operates on the Windows NT operating system, registry entries comprise keys and optional subkeys. One specific key, called "HKEY.sub.-- LOCAL.sub.-- MACHINE.backslash.SOFTWARE.backslash.Microsoft.backslash.Windows.backslash .NT.backslash.Current Version.backslash.Image File Execution Options", uses subkeys to list images that may be executed, along with various options that may be invoked when those images are executed. The registry 106-a is typically used to store operating system and application specific information. After instrumentation, a registry entry for "main.exe" is created to cause the instrumented version 115 a-d of the application to be executed instead of the original version 103 a-d. Step 204 creates a key in the registry 106-a for "main.exe" and creates a value for this key beginning with the word "debugger", as follows:
______________________________________
KEY: Image File Execution Options
KEY: Main.exe
debugger=. . . .backslash.Database.backslash.Instrument.backslash.main.ins
t.
______________________________________
The "debugger" value associated with the main.exe key is used to invoke a specified debugger application when the application specified in the key is executed. This registry modification instructs the operating system to execute the program specified after "debugger=", when the application program specified after the word "KEY" is invoked. That is, if the user executes "main" or "main.exe", the modified registry will cause the operating system to execute "main.inst". Note that the program specified after "debugger=" is ". . . .backslash.Database.backslash.Instrument.backslash.main.inst." In this example, "main.inst" is the instrumented version of the application which is stored in profile optimizer database 105. In the preferred embodiment, the TAS process 104-b creates a the key and the "debugger" value in registry 106-a. After the registry 106-a is updated, step 205 of the instrumentation process updates the image import sections (Column 2, Table 1) of each instrumented image. Step 205 changes the name of any non-instrumented image, referenced in each import section of each instrumented image, to the name of a corresponding instrumented image file. That is, for all image names in the import sections of images loaded in step 201 and 202, step 205 renames the image names to their instrumented counterparts. For example, with respect to Column 2 in Table 1, step 205 changes the non-instrumented image names dll1.exe, dll2.exe and dll3.exe in the import section in each of the image files to the names of the corresponding instrumented versions of these files dll1.inst, dll2.inst and dll3.inst. Step 206 then updates forward statements so that they only reference instrumented versions of the images. That is, for any functions that are forwarded to other image files, step 206 ensures that the image file name is an instrumented image instead of a non-instrumented image. As an example, in the export section of dll1.exe in Column 3 in Table 1, image file name dll3.exe appears as "forward:FunctionX:dll3.exe." Accordingly, step 206 modifies the forward reference to appear as "forward:FunctionX:dll3.inst" in the export section of the corresponding instrumented image dll1.inst 115-b. Recall that Table 1 illustrates imports and exports for a non-instrumented image. Table 2 below, as contrasted with Table 1, illustrates how the import and export sections differ between non-instrumented application images 103-a through 103-d and the instrumented counterparts of those images 115-a through 115-d.
TABLE 2
______________________________________
Imports/Exports for Instrumented Executables
FILE IMPORTS EXPORTS
______________________________________
main.inst
dll1.inst FunctionA
main
dll2.inst Function D
dll1.inst
dll2.inst Function C
FunctionA
Function D FunctionB
Forward: FunctionX:dll3.inst
dll2.inst
dll3.inst FunctionX
FunctionC
FunctionD
dll3.inst
npi.dll SearchPath
FunctionE
FunctionX
Forward FunctionY:npi.dll
npi.dll Kernel32.dll SearchPath
CreateProcess
GetCommandLine
GetModuleFileName
LoadLibrary
LoadLibraryEx
GetModuleHandle
GetProcessAddress
Forward FunctionY:Kernel32.dll
Forward . . . :Kernel32.dll
Forward . . . :Kernel32.dll
. . .
Kernel32.dll
-- FunctionY
. . .
______________________________________
Note that each import reference that previously (Table 1) referenced a non-instrumented image now references a corresponding instrumented version of the same image in Table 2. Further, note that each function that was forwarded to a non-instrumented image is, in the instrumented version, forwarded to a corresponding instrumented image containing that instrumented function. Table 2 also illustrates the processing that takes place in step 207. Step 207 updates any import or export references that were made to the "Kernel32.dll" image 109 to reference an image named "npi.dll" (shown as 110 in FIG. 3). For example, in the non-instrumented image dll3.exe 103-d, as shown in Table 1, FunctionY is forwarded from the export section to the system supplied image file Kernel32.dll. Step 207 converts the forwarded FunctionY export reference in the corresponding instrumented image dll3.inst 115-d to refer to an image file named "npi.dll." Npi.dll 110 is the critical function file and is stored in the profile optimizer database 105. The primary purpose of Npi.dll 110 is to trap, during execution of an instrumented image, certain critical function calls that normally would be directed to functions in Kernel32.dll 109. Generally, step 207 provides a transparent execution environment for the instrumented application for all system level function calls. In other words, by rewriting the critical functions of Kernel32.dll 109 and placing the rewritten versions in nip.dll 110, when an instrumented image invokes a critical function, the npi.dll version is used. The eight functions are called critical functions because these functions provide information and services that return information that must be modified to allow an instrumented version of the application 110 to execute and "appear as" the original application 103. For example, one purpose for trapping these types of function calls during execution of an instrumented application 115 is to ensure that the images or files or locations that they reference during execution are themselves properly instrumented files. For example, one of the functions provided in Kernel32.dll 109 is "LoadLibrary". During execution of an instrumented image, the LoadLibrary function may be called to load any specified image. The image to be loaded, for example, could be specified by a user at runtime as a parameter. This may be a problem for an instrumented version of the application because control could be transferred to a non-instrumented image. However, in the present system this problem is avoided and no shell program is required during execution. To do so, npi.dll 110 contains a rewritten version of LoadLibrary which intercepts the call made to the regular LoadLibrary function (i.e., the one in Kernel32.dll 109) and replaces the image name specified as the parameter with the name of a corresponding instrumented image. The LoadLibrary function in npi.dll 110 then calls the "real" LoadLibrary function in Kernel32.dll 109 along with the modified parameter. If LoadLibrary attempts to load an image that does not have a corresponding instrumented version, the npi.dll version of LoadLibrary first invokes the Image Modifier 104-c to create an instrumented version of the specified image. After the instrumented version is created, the npi.dll 110 version of LoadLibrary then calls the real LoadLibrary in Kernel32.dll 109 and provides the name of the newly created instrumented version of the image as the parameter. Including LoadLibrary, there are a total of eight critical functions that are trapped by npi.dll 110. The functions are SearchPath, CreateProcess, GetCommandLine, GetModuleFileName, LoadLibrary, LoadLibraryEx, GetModuleHandle, and GetProcessAddress. A version of each of these functions is provided by the invention in npi.dll 110. A description of each function and a summary of its operation during execution will be given when the details of step 151 (i.e., execution of the instrumented application) are provided. Note in Table 2 that each of the eight critical functions is exported from npi.dll 110, and that all other functions provided by kernel32.dll 109 are forwarded directly to kernel32.dll 109. After step 207 is complete, step 208 outputs the entire set of instrumented images into profile optimizer database 105. After step 208 is complete, the instrumentation process (FIG. 4) is finished. At this point, every import and export section of every instrumented image 115-a through 115-d has been modified to refer to other instrumented images. The user can now exercise the instrumented version of the application by executing it a number of times (step 151 in FIG. 2) in order to generate profile data. Step 300 in FIG. 5 illustrates the typical processing performed by user 108 in order to execute the instrumented application 115-a through 115-d. (step 151 of FIG. 2) Step 300 reads and executes the instrumented application images 115-a through 115-d contained in profile optimizer database 105. During each execution, the instrumented object code images 115-a through 115-d produce profile data files, beginning with 116-e. Step 300 can be executed any number of times by the user 108. The purpose of multiple executions is so that various aspects of the instrumented application can be "exercised." Generally, the idea is to create large amounts of profile data that accurately reflects execution of the application in many different ways. This profile data is then used for optimization. FIG. 6 illustrates a block diagram of the execution process (e.g. step 300 in FIG. 5). In FIG. 6, user 108 "runs" the main image 115-a of the instrumented application via manager 104-a. Alternatively, the user may merely select "main" or "main.exe" for execution via a keyboard, mouse or other means. Irrespective of how the user 108 invokes the application, the operating system 106 consults the registry 106-a for the actual program to execute. Since the registry 106-a has been modified via the instrumentation process (Step 204, FIG. 3), the instrumented version of the application is executed instead of the original version. The user therefore need not be concerned with specifying the instrumented version versus the original version. The execution of the images 115-a through 115-d is performed via the operating system 106, just as if a regular application were being executed. That is, no special shell program is needed to capture and save the profile data files 116-e through 116-l. Each time the instrumented application is executed, instrumented functions in images 115-a through 115-d produce profile data files (i.e., main.profl 116-e, dll1.profl 116-f, etc.) due to the instrumentation code they contain. Thus, during the first execution, profile data files 116-e through 116-h are created. During the next execution of the instrumented application profile data files 116-I through 116-l are created, and so forth. There is a separate profile data file created for each image during each execution. During the execution of an instrumented application, instrumented images 115-a through 115-d can make calls to any of the eight critical functions. As noted previously, these functions are SearchPath, CreateProcess, GetCommandLine, GetModuleFileName, LoadLibrary, LoadLibraryEx, GetModuleHandle, and GetProcessAddress. Recall that these critical function calls are trapped by rewritten versions of these functions in npi.dll 110. Each of the critical functions will now be explained along with its relevance to this invention. The SearchPath function can be invoked by an image to search for a file using a search algorithm. The algorithm first looks for a file in the directory from which the calling application was loaded. The instrumented images (i.e. the instrumented application) are stored in profile optimizer database 105, whereas the original un-instrumented version of the application (i.e., original application images 103) is stored elsewhere. Since the instrumented application is invoked from the profile optimizer database 105, rather than from elsewhere in the filesystem of the computer, npi.dll 110 must intercept calls to SearchPath to determine to correct location of the file being sought. The rewritten version of SearchPath in npi.dll 110 searches for files beginning with the location (i.e. the directory) of the non-instrumented original application, rather than the profile optimizer database directory from which the current instrumented image is executing. By trapping SearchPath calls and first checking the directory of the original application for the file(s) sought, the instrumented version of the application "thinks" it is executing in the original application's home directory. The CreateProcess function uses the SearchPath function to find an application that is to be invoked. Npi.dll 110 intercepts calls to CreateProcess so that a proper search for the sought after application can be performed, starting in the home directory or file system location of the original non-instrumented original application images 103. The GetCommandLine function can be used by an image to obtain the command that the operating system 106 used to invoke the application that is currently executing. When the user executes the instrumented version of the application, the user enters, for example, "main.exe" at the DOS prompt, or double-clicks on the application icon if using a Windows interface. As explained above, the registry converts this command into "main.inst" in order to run the instrumented version of the application. However, when GetCommandLine is called, npi.dll 110 traps this call and replaces "main.inst" with "main.exe." This insulates the user and the application from "knowing" that "main.inst" is running instead of "main.exe." The GetModuleFileName function returns the full pathname of a file containing an image. When an instrumented image calls GetModuleFileName, npi.dll 110 intercepts the call to prevent the function from returning the pathname of a file in the profile optimizer database 105. Instead, the modified version returns the full pathname of the corresponding original image. LoadLibrary, as discussed in the former example, and LoadLibraryEx are similar to each other in operation. Each of these functions loads a specific image. Npi.dll 110 intercepts these calls during runtime and replaces the original image name with the filename of a corresponding instrumented image, and then calls the actual LoadLibrary or LoadLibraryEx in Kernel32.dll 109 to proceed to load the image specified. If the corresponding instrumented image does not exist, npi.dll 110 first invokes the image modifier 104-c to create an instrumented version of the image using the instrumentation process explained above. That is, during runtime, an application may dynamically be capable of specifying images that should be executed. These images may be in addition to the images listed in import and export sections of images 115-a through 115-d which are part of the instrumented application. Accordingly, if one of the LoadLibrary functions is called to load an image which has not yet been instrumented, the npi.dll 110 version of LoadLibrary can invoke the instrumentation process (i.e., FIGS. 3 and 4) to create an instrumented version (according to the instrumentation process described above) of the image. This can take place during runtime. This newly instrumented version of an image is then used as the image name for an actual call to the "real" LoadLibrary function call in Kernel32.dll 109. GetModuleHandle is a function which returns a handle to a specified image which is loaded into the address space of the currently executing application. Npi.dll 110 intercepts calls to GetModuleHandle and replaces the original image name with the name of the corresponding instrumented image. Npi.dll 110 then calls the real GetModuleHandle function in Kernel32.dll 109 in order to get the handle of the instrumented image, instead of the non-instrumented version which does not actually exist in the address space. The last function call intercepted by npi.dll 110 is GetProcAddress. This function returns the address of the specified function in the specified image. Npi.dll 110 intercepts calls to GetProcAddress so that it can detect when the instrumented application is requesting the address of one of the eight critical functions in Kernel32.dll 109 that are being intercepted by npi.dll 110. If the instrumented application object code images 115-a through 115-d requests the address of one of these critical functions in kernel32.dll 109, npi.dll 110 instead returns the address of the rewritten version in npi.dll 110. In this manner, npi.dll 110 provides wrapper functions for the eight critical functions. The processing described above completes the transparency concept of the invention. That is, when an instrumented application is executing, the user and the application are unaware that an instrumented version of the application, which is stored in a different location, is actually executing. It is noted that these eight functions are trapped in the preferred embodiment but that the present invention is not meant to be limited as such. For instance, other functions that are determined to effect execution of an instrumented application in a similar manner as the eight discussed herein could also be trapped. The final operation in the profile feedback optimization system of this invention is the optimization process (Step 152 in FIG. 2). The optimization process is carried out by the image modifier 104-c and is illustrated in FIG. 8. Generally, the image modifier 104-c reads as input the original non-optimized application images 103-a through 103-d as well as all of the profile data files (i.e., 116-e through 116-l in FIG. 8). The image modifier 104-c analyzes the profile data and creates an optimized version of the application as images 107-m through 107-p. FIG. 7 illustrates steps 400 through 404 which occur during the optimization process. In step 400, the original main image 103-a of the original application is loaded into memory along with its corresponding profile data files main.profl 116-e, main.prof2 116-i, and so forth. In step 401, all imported DLL images 103-b through 103-d are loaded into memory along with their corresponding profile data files 116-f through 116-h, 116-j through 116-l, and so forth. Next, in step 402, any non-optimized DLL images that contain forwarded functions are loaded into memory along with their corresponding profile data files. Essentially, steps 400 through 401 load into memory the entire set of images for a complete application, along with all of the profile data files produced during the execution process described previously. Step 403 then optimizes the original images of the application 103 based upon the contents of the profile data files 116-e, 116-f, and so forth. The actual optimization employed is not particularly relevant, as optimization techniques are know to those skilled in the art. However, what is important is that the optimize step 403 modifies the registry 106-a in a similar manner as did step 204 of the instrumentation process of FIG. 4. The difference, however, is that the registry is updated to configure the name of the application from the instrumented version to the optimized version that will be written to the profile optimizer database 105 or to disk in step 404. That is, just as the registry 106-a was updated in the instrumentation process (FIG. 4) to cause the instrumented version of the application to run instead of the original non-instrumented version, step 404 updates the registry to run the new optimized version of the application. To do so, step 404 can change the "debugger" subkey noted above to read: debugger= . . . .backslash.Database.backslash.Optimize.backslash.main.opt This causes the optimized version of the main image "main.opt" 107-m to be executed when the user runs the application by specifying "main.exe." Step 403 also performs processing equivalent in nature to steps 205 through 207 of the instrumentation process in FIG. 4. That is, each image created in the optimized version of the application will reference only other optimized images in its import and export sections and in the forward statements. Furthermore, the eight critical function calls will be trapped by npi.dll 110. Table 3 below illustrates the final optimized versions of the import and export sections of optimized images 107-m through 107-q.
TABLE 3
______________________________________
Imports/Exports for Optimized Executables
FILE IMPORTS EXPORTS
______________________________________
main.opt
dll1.opt FunctionA
main
dll2.opt FunctionD
dll1.opt
dll2.opt Function C,
FunctionA
FunctionD FunctionB
Forward: FunctionX:dll3.opt
dll2.opt
dll3.opt Function X
FunctionC
FunctionD
dll3.opt
npi.dll SearchPath
FunctionE
FunctionX
Forward FunctionY:npi.dll
npi.dll Kernel32.dll SearchPath
CreateProcess
GetCommandLine
GetModuleFileName
LoadLibrary
LoadLibraryEx
GetModuleHandle
GetProcessAddress
Forward FunctionY:Kernel32.dll
Forward . . . :Kernel32.dll
Forward . . . :Kernel32.dll
. . .
Kernel32.dll
-- FunctionY
. . .
______________________________________
Step 404 is the final step of the optimization process which outputs the optimized images 107-m through 107-p to profile optimizer database 105. When complete, each optimized application image 107-m through 107-p in profile optimizer database 105 corresponds to a respective original application image 103-a through 103-d. The registry 106-a contains the subkey that will execute the optimized version of the application when a user 108 specifies that he or she wishes to execute the application. In this manner, the invention provides a system for profile feedback optimization that manages all of the details of file manipulation and configuration management. By keeping all files in the profile optimizer database, the original application remains available for use if needed. Moreover, by performing the above processing, a transparent application substitution environment is provided in which the user performing optimization merely needs to instrument, execute, and optimize the application in three simple steps. While this invention has been particularly shown and described with references to preferred embodiments thereof, it will be understood by those skilled in the art that various changes in form and details may be made therein without departing from the spirit and scope of the invention as defined by the appended claims. Those skilled in the art will recognize or be able to ascertain using no more than routine experimentation, many equivalents to the specific embodiments of the invention described specifically herein. Such equivalents are intended to be encompassed in the scope of the claims.
|
Same subclass Same class Consider this |
||||||||||
