Please enable JavaScript to view this site.

Performance Validator Help

 

The Performance Validator stub service libraries

 

The NT Service API is very simple, consisting of functions to load, start and unload the Performance Validator DLL.

 

We have also provided some debugging functions to help you debug the implementation of the NT Service API because getting data into and out of services is not always straightforward.

 

The stub service libraries used for this are shown in the following table:

 


32 bit Performance Validator

64 bit Performance Validator

32 bit service

svlPVStubService.lib

svlPVStubServiceMD.lib

svlPVStubServiceMT.lib

svlPVStubService.lib

svlPVStubServiceMD.lib

svlPVStubServiceMT.lib

64 bit service

N/A

svlPVStubService_x64.lib

svlPVStubServiceMD_x64.lib

svlPVStubServiceMT_x64.lib

 

All the functions exported from these libraries are exported as extern "C" so that C and C++ users can use them.

 

Library name suffixes

 

The MD suffix indicates the library was built with the /MD compiler switch.

The MT suffix indicates the library was built with the /MT compiler switch.

 

2010 or 2012?

 

If you are using Visual Studio 2010 or earlier, use libraries from a directory with 2010 in the directory name.

 

If you are using Visual Studio 2012 or later, use libraries from a directory with 2012 in the directory name.

 

 

Header files

 

The simple header file svlPVStubService.h and svlServiceError.h is found in the svlPVStubService directory of the install area.

 

The header files provides an error enumeration and the API functions.

 

 

API changes - February 2018

 

To make the API easier to use with services we changed the API by adding many debugging functions to allow you to easily log information. We also extended the error enumeration to provide additional error status values.

 

We also split the function of loading and starting the validator into two functions - a load function and a start function.

 

We split the functionality so that you could setup a service callback prior to calling the start function. The service callback allows the service control manager to be informed that the service is still active during time consuming operations, such as starting the validator when the service is non-trivial in scope. Failure to inform the service control manager results in the service being killed by the service control manager because it thinks the service has hung. This change in the API is to ensure you get better results from using our software.

 

What do you need to do to move from the old API to the new API?

 

Change all SVL_SERVICE_ERROR declarations to SVL_SERVICE_ERROR.

 

Your previous startup code probably looked like this:

 

   SVL_SERVICE_ERROR errCode;
 
   errCode = svlPVStub_LoadPerformanceValidator();

 

Change it to this:

 

   SVL_SERVICE_ERROR errCode;
 
   errCode = svlPVStub_LoadPerformanceValidator();
 
   errCode = svlPVStub_SetServiceCallback(serviceCallback, NULL);
 
   errCode = svlPVStub_StartPerformanceValidator();

 

The serviceCallback would look something like this:

 

   void serviceCallback(void   *userParam)
   {
       static DWORD dwCheckPoint = 1;
   
       ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
       ssStatus.dwServiceSpecificExitCode = 0;
 
       ssStatus.dwControlsAccepted = 0;
      
       ssStatus.dwCurrentState = dwCurrentState;
       ssStatus.dwWin32ExitCode = dwWin32ExitCode;
       ssStatus.dwWaitHint = dwWaitHint;
       ssStatus.dwCheckPoint = dwCheckPoint++;
      
       // Report the status of the service to the service control manager.
 
       return SetServiceStatus(sshStatusHandle, &ssStatus);
   }

 

In the code above we have omitted error handling. To see how to use the new logging function with error handling please examine the source code service.cpp in the example service project.

 

Important.

 

Once your service is running (rather than starting) your service callback should set the appropriate running status SERVICE_RUNNING rather than SERVICE_START_PENDING.

An alternative solution is to prevent the service callback from being called once the service status has been set to running. Do this by calling svlCVStub_SetServiceCallback(NULL, NULL);.

 

API Reference

 

SVL_SERVICE_ERROR Enumeration

 

typedef enum _svlServiceError
{
   SVL_OK,                                                              // Normal behaviour
   SVL_ALREADY_LOADED,                                                  // Stub DLL already loaded into service
   SVL_LOAD_FAILED,                                                     // Failed to load stub DLL into service
   SVL_FAILED_TO_ENABLE_STUB_SYMBOLS,                                   // Loaded DLL, but failed to enable stub symbols because couldn't find function
   SVL_NOT_LOADED,                                                      // Couldn't unload DLL because DLL not loaded
   SVL_FAIL_UNLOAD,                                                     // Couldn't unload DLL because couldn't find function
   SVL_FAIL_TO_CLEANUP_INTERNAL_HEAP,                                   // Couldn't get the internal stub heap and thus couldn't clean it up
   SVL_FAIL_MODULE_HANDLE                                               // Couldn't get the stub DLL handle so couldn't continue
   SVL_FAIL_SETSERVICECALLBACK,                                         // Couldn't call the set service callback

   SVL_FAIL_COULD_NOT_FIND_ENTRY_POINT,                                 // Couldn't find the DLL entry point to start the validator

   SVL_FAIL_TO_START,                                                   // Failed to start the Validator

   SVL_FAIL_SETSERVICECALLBACKTHRESHOLD,                                // Couldn't call the set service callback threshold

   SVL_FAIL_PATHS_DO_NOT_MATCH,                                        // Path to service in env vars doesn't match the service being run

   SVL_FAIL_INCORRECT_PRODUCT_PREFIX,                                // Wrong validator

   SVL_FAIL_X86_VALIDATOR_FOUND_EXPECTED_X64_VALIDATOR,        // Found wrong bit depth validator

   SVL_FAIL_X64_VALIDATOR_FOUND_EXPECTED_X86_VALIDATOR,        // Found wrong bit depth validator

   SVL_FAIL_DID_YOU_MONITOR_A_SERVICE_FROM_VALIDATOR,                // Looks like Monitor A Service wasn't used

   SVL_FAIL_ENV_VAR_NOT_FOUND,                                        // Env Var not found

   SVL_FAIL_VALIDATOR_ENV_VAR_NOT_FOUND,                                // Env Var identifying validator not found

   SVL_FAIL_VALIDATOR_ID_NOT_SPECIFIED,                                // Validator process not specified

   SVL_FAIL_VALIDATOR_ID_NOT_A_PROCESS,                                // Validator process identified doesn't exist

   SVL_FAIL_VALIDATOR_NOT_FOUND,                                        // Validator process identified doesn't exist

} SVL_SERVICE_ERROR;

 

The API consists of the following functions. Each function will be documented in detail after the list of functions.

 

extern "C" SVL_SERVICE_ERROR svlPVStub_LoadPerformanceValidator();
 
extern "C" SVL_SERVICE_ERROR svlPVStub_LoadPerformanceValidator6432();
 
extern "C" SVL_SERVICE_ERROR svlPVStub_StartPerformanceValidator();

 

extern "C" SVL_SERVICE_ERROR svlPVStub_StartPerformanceValidatorForIIS();
 
extern "C" SVL_SERVICE_ERROR svlPVStub_UnloadPerformanceValidator();
 
extern "C" SVL_SERVICE_ERROR svlPVStub_SetServiceCallback(serviceCallback_FUNC callback,
                                                          void*                userParam);
 
// debugging functions
 
extern "C" void svlPVStub_setLogFileName(const wchar_t* fileName);
 
extern "C" void svlPVStub_deleteLogFile();
 
extern "C" void svlPVStub_writeToLogFileA(const char* text);
 
extern "C" void svlPVStub_writeToLogFileW(const wchar_t* text);
 
extern "C" void svlPVStub_writeToLogFile(SVL_SERVICE_ERROR errCode);
 
extern "C" void svlPVStub_writeToLogFileLastError(DWORD errCode);
 
extern "C" void svlPVStub_dumpPathToLogFile();

 

 

Loading the Performance Validator DLL into your service

 

To load the Performance Validator stub dll svlPerformanceValidatorStub(_x64).dll into your service, use the function below, not LoadLibrary().

 

extern "C" SVL_SERVICE_ERROR svlPVStub_LoadPerformanceValidator();

 

This loads the DLL and sets up a few internal variables in the DLL to ensure that symbols are sent from the stub to the Performance Validator user interface.

 

This is necessary because the Performance Validator user interface can't open a process handle to a service and so is unable to get symbols from the process.

 

To solve this, symbols are sent from the stub to the user interface as needed.

 

If you just call LoadLibrary() on the DLL, symbols will not be sent to the Performance Validator user interface and you won't get meaningful function names in your performance information.

 

This function can be used when monitoring:

 

32 bit services or applications with Performance Validator
 

64 bit services or applications with Performance Validator x64

 

There is another version of the function when monitoring 32 bit builds with Performance Validator x64

 

extern "C" SVL_SERVICE_ERROR svlPVStub_LoadPerformanceValidator6432();

 

 

Which function you should call is shown in the table below.

 


32 bit Performance Validator

64 bit Performance Validator

32 bit service

svlPVStub_LoadPerformanceValidator()

svlPVStub_LoadPerformanceValidator6432()

64 bit service

N/A

svlPVStub_LoadPerformanceValidator()

 

 

Shutting down the Performance Validator DLL from your service.

 

Similarly to starting, you'll need to use the following to shutdown the Performance Validator stub dll.

 

extern "C" SVL_SERVICE_ERROR svlPVStub_ShutdownPerformanceValidator();

 

This sends the shutting down notification and removes any hooks for your process.

 

 

Unloading the Performance Validator DLL from your service.

 

Use this method to unload the Performance Validator stub dll, and not FreeLibrary().

 

extern "C" SVL_SERVICE_ERROR svlPVStub_UnloadPerformanceValidator();

 

 

Setting a service notification callback

 

Once you have successfully loaded the Performance Validator DLL you can setup a service callback so that the service control manager can be kept updated during the process of starting the validator.

 

When a service is starting, Windows requires the service to inform the Service Control Manager (SCM) that is starting at least every ten seconds.

 

Failure to do so results in Windows concluding that the service has failed to start, and the service is terminated.

 

Instrumenting your service may well take more than 10 seconds, depending on the complexity and size of your service.

 

The solution is for Performance Validator to periodically call a user supplied callback from which you can regularly inform the SCM of the appropriate status.

 

extern "C" SVL_SERVICE_ERROR svlPVStub_SetServiceCallback(serviceCallback_FUNC callback, void *userParam);

 

userParam is a value you can supply which will then be passed to the callback every time the callback is called during instrumentation.

 

Here is an example callback which ignores the userParam.

 

   void serviceCallback(void   *userParam)
   {
       static DWORD dwCheckPoint = 1;
   
       ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
       ssStatus.dwServiceSpecificExitCode = 0;
 
       ssStatus.dwControlsAccepted = 0;
      
       ssStatus.dwCurrentState = dwCurrentState;
       ssStatus.dwWin32ExitCode = dwWin32ExitCode;
       ssStatus.dwWaitHint = dwWaitHint;
      
       ssStatus.dwCheckPoint = dwCheckPoint++;
      
       // Report the status of the service to the service control manager.
 
       return SetServiceStatus(sshStatusHandle, &ssStatus);
   }

 

 

Starting Performance Validator DLL in your service

 

Once you have successfully loaded the Performance Validator DLL you can start the Validator inspecting the service.

 

extern "C" SVL_SERVICE_ERROR svlPVStub_StartPerformanceValidator();

 

 

Setting a filename for all logging data to be written to

 

To use any of the following logging functions you first need to set the name of the filename used for logging.

Setting this filename also sets the filename used by some of these API functions - you will find additional logging data from those functions that will help debug any issues with the service.

 

extern "C" void svlPVStub_setLogFileName(const wchar_t* fileName);
 

 

Deleting the logfile

 

This function deletes the log file.

 
extern "C" void svlPVStub_deleteLogFile();
 

 

Writing ANSI text to the logfile

 

Call this function to write a standard ANSI character string to the log file.

 
extern "C" void svlPVStub_writeToLogFileA(const char* text);
 

 

Write UNICODE text to the logfile

 

Call this function to write a unicode character string to the log file. The characters are cast to ANSI prior to writing. As such you can't write Korean to the log file. This is simply a convenience function to write wide characters as simply as ANSI characters.

 
extern "C" void svlPVStub_writeToLogFileW(const wchar_t* text);
 

 

Writing error code descriptions to the logfile

 

Call this function to write a human readable description of the SVL_SERVICE_ERROR error code to the log file.

 
extern "C" void svlPVStub_writeToLogFile(SVL_SERVICE_ERROR errCode);
 

 

Writing LastError code descriptions to the logfile

 

Call this function to write a human readable description of the Windows error code to the log file.

 
extern "C" void svlPVStub_writeToLogFileLastError(DWORD errCode);
 

 

Dumping the PATH environment to the logfile

 

Call this function to write the contents of the PATH environment variable to the log file. This can be useful if you want to know what the search path is when trying to debug why a DLL wasn't found during an attempt to load the Validator DLL.

 
extern "C" void svlPVStub_dumpPathToLogFile();

 

 

Performance Validator DLL behaviour

 

The DLL prepares itself in different ways and shuts itself down differently depending on whether:

 

The DLL is directly linked to the application for use with the API or injected with Performance Validator

 

The DLL expects to oversee and manage the application shutdown.

 

The DLL is loaded by using the function above

 

The DLL expects to be removed prior to application shutdown and the its behaviour is undefined once you enter the program shutdown sequence.

 

This difference in behaviour is intentional and is done to allow the use of the stub DLL in services.

 

 

Linker Problems

 

Some linkers cannot link the stub service library file.  If you have this problem see What do I do if I cannot use svlPVStubService.lib?

 

 

Troubleshooting - Service fails to start

 

If a service takes too long to start the service control manager kills the service.

 

The way to stop this is for a service to call ReportStatusToSCMgr() to tell the service control manager that the service is still OK.

 

Performance Validator can't do this for you as the call requires some data from any earlier call you have made.

 

The solution is that you provide a callback using svlPVStub_SetServiceCallback() that Performance Validator can call during the process of attaching to the service, and you can call the appropriate function.

 

Example code to set the callback:

 

 errCode = svlPVStub_SetServiceCallback(serviceCallback,                // the callback

                                              NULL);                                // some user data (we don't have any, so set NULL)

 if (bLogging)

 {

         if (errCode != SVL_OK)

         {

                 svlPVStub_writeToLogFileW(L"Setting service callback failed. \r\n");

                 svlPVStub_writeToLogFile(errCode);

         }

 

         svlPVStub_writeToLogFileW(L"Starting Performance Validator\r\n");

 }

 

 

 

Example callback:

 

static void serviceCallback(void        *userParam)

{

 // just tell the Service Control Manager that we are still busy

 // in this example userParam is not used

 //

 // note that prior to the Validator loading it's DLL ssStatus.dwCurrentState must have been initialised, most likely to SERVICE_START_PENDING

 // you could pass a fixed value here, but it would need to change once the service has finished starting up so that you don't unintentionally change the service state

 // when this callback is called. This callback is called whenever instrumentation happens (when a DLL is loaded). Thus you can't assume this is only called during service startup,

 // it may also get called later in the service lifetime.

 

 ReportStatusToSCMgr(ssStatus.dwCurrentState,        // service state

                         NO_ERROR,                        // exit code

                         3000);                                // wait hint

}

 

We strongly recommend that you set a service callback. It won't harm your program and it will remove any likelihood of your service being killed by the service control manager.

 

 

Troubleshooting - Service starts, Performance Validator gets no data

 

If you have problems getting Performance Validator to monitor your service you'll need to find out what's failing.

 

Until Performance Validator loads correctly and successfully connects to the graphical user interface you have no way of knowing what is happening.

 

The solution is to set a log file that Performance Validator can write status messages to. You can also write your own status messages to this log file.

 

Set the log file using svlPVStub_setLogFileName. Write to it using svlPVStub_writeToLogFile(), svlPVStub_writeToLogFileA(), svlPVStub_writeToLogFileW().

 

Then when things are not working as expected take a look at the log file to see the errors. The Performance Validator will often suggest what the problem is.

 

We strongly recommend that you configure the log file and use it when working with services. It has saved us a lot of time.

 

 

Examples

 

Example demonstrating how to monitor a service.

 

Example demonstrating how to monitor an application launched from a service (how to monitor any application running on a service account).