home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / winbase / winnt / perftool / perfdlls / perfgen / perfgen.c < prev    next >
Text File  |  1996-10-22  |  15KB  |  487 lines

  1. /*++ 
  2.  
  3. Copyright (c) 1995-6  Microsoft Corporation
  4.  
  5. Module Name:
  6.  
  7.     perfgen.c
  8.  
  9. Abstract:
  10.  
  11.     This file implements an Extensible Performance Object that displays
  12.     generated signals
  13.  
  14. Created:    
  15.  
  16.     Bob Watson  28-Jul-1995
  17.  
  18. Revision History
  19.  
  20.  
  21. --*/
  22.  
  23. //
  24. //  Include Files
  25. //
  26.  
  27. #include <windows.h>
  28. #include <string.h>
  29. #include <winperf.h>
  30. #include <math.h>
  31. #include "genctrs.h" // error message definition
  32. #include "perfmsg.h"
  33. #include "perfutil.h"
  34. #include "datagen.h"
  35.  
  36. //  define constant value counter's value here, any number will do.
  37.  
  38. #define CONSTANT_VALUE_VALUE    49
  39. //
  40. //  References to constants which initialize the Object type definitions
  41. //
  42.  
  43. extern SIGGEN_DATA_DEFINITION SigGenDataDefinition;
  44.     
  45. DWORD   dwOpenCount = 0;        // count of "Open" threads
  46. BOOL    bInitOK = FALSE;        // true = DLL initialized OK
  47.  
  48. //
  49. //  Function Prototypes
  50. //
  51. //      these are used to insure that the data collection functions
  52. //      accessed by Perflib will have the correct calling format.
  53. //
  54.  
  55. PM_OPEN_PROC    OpenSigGenPerformanceData;
  56. PM_COLLECT_PROC CollectSigGenPerformanceData;
  57. PM_CLOSE_PROC   CloseSigGenPerformanceData;
  58.  
  59. typedef struct _WAVE_DATA {
  60.     DWORD   dwPeriod;
  61.     DWORD   dwAmplitude;
  62.     LPWSTR  szInstanceName;
  63. } WAVE_DATA, *PWAVE_DATA;
  64.  
  65. static WAVE_DATA wdInstance[]  =
  66. {
  67.     {1000,      100, L"  1 Second"},
  68.     {10000,     100, L" 10 Second"},
  69.     {20000,     100, L" 20 Second"},
  70.     {50000,     100, L" 50 Second"},
  71.     {100000,    100, L"100 Second"}
  72. };
  73.  
  74. static const DWORD    NUM_INSTANCES = 
  75.     (sizeof(wdInstance)/sizeof(wdInstance[0]));
  76.  
  77. static double   dPi = 3.1415926590;
  78. static double   d2Pi = 2.0 * 3.1415926590;
  79.  
  80.  
  81. static
  82. DWORD
  83. GetTimeInMilliSeconds ()
  84. {
  85.     SYSTEMTIME  st;
  86.     DWORD       dwReturn;
  87.  
  88.     GetSystemTime (&st);
  89.     dwReturn = (DWORD)st.wMilliseconds;
  90.     dwReturn += (DWORD)st.wSecond * 1000L;
  91.     dwReturn += (DWORD)st.wMinute * 60000L;
  92.     dwReturn += (DWORD)st.wHour * 3600000L;
  93.     dwReturn += (DWORD)st.wDay * 86500000L;
  94.  
  95.     // that's good enough for what it's for
  96.  
  97.     return dwReturn;
  98. }
  99.  
  100. DWORD APIENTRY
  101. OpenSigGenPerformanceData(
  102.     LPWSTR lpDeviceNames
  103.     )
  104.  
  105. /*++
  106.  
  107. Routine Description:
  108.  
  109.     This routine will initialize the data structures used to pass
  110.     data back to the registry
  111.  
  112. Arguments:
  113.  
  114.     Pointer to object ID of each device to be opened (PerfGen)
  115.  
  116. Return Value:
  117.  
  118.     None.
  119.  
  120. --*/
  121.  
  122. {
  123.     LONG status;
  124.     HKEY hKeyDriverPerf;
  125.     DWORD size;
  126.     DWORD type;
  127.     DWORD dwFirstCounter;
  128.     DWORD dwFirstHelp;
  129.  
  130.     //
  131.     //  Since WINLOGON is multi-threaded and will call this routine in
  132.     //  order to service remote performance queries, this library
  133.     //  must keep track of how many times it has been opened (i.e.
  134.     //  how many threads have accessed it). the registry routines will
  135.     //  limit access to the initialization routine to only one thread 
  136.     //  at a time so synchronization (i.e. reentrancy) should not be 
  137.     //  a problem
  138.     //
  139.  
  140.     if (!dwOpenCount) {
  141.         // open Eventlog interface
  142.  
  143.         hEventLog = MonOpenEventLog();
  144.  
  145.         // get counter and help index base values from registry
  146.         //      Open key to registry entry
  147.         //      read First Counter and First Help values
  148.         //      update static data strucutures by adding base to 
  149.         //          offset value in structure.
  150.  
  151.         status = RegOpenKeyEx (
  152.             HKEY_LOCAL_MACHINE,
  153.             "SYSTEM\\CurrentControlSet\\Services\\PerfGen\\Performance",
  154.             0L,
  155.             KEY_READ,
  156.             &hKeyDriverPerf);
  157.  
  158.         if (status != ERROR_SUCCESS) {
  159.             REPORT_ERROR_DATA (GENPERF_UNABLE_OPEN_DRIVER_KEY, LOG_USER,
  160.                 &status, sizeof(status));
  161.             // this is fatal, if we can't get the base values of the 
  162.             // counter or help names, then the names won't be available
  163.             // to the requesting application  so there's not much
  164.             // point in continuing.
  165.             goto OpenExitPoint;
  166.         }
  167.  
  168.         size = sizeof (DWORD);
  169.         status = RegQueryValueEx(
  170.                     hKeyDriverPerf, 
  171.                     "First Counter",
  172.                     0L,
  173.                     &type,
  174.                     (LPBYTE)&dwFirstCounter,
  175.                     &size);
  176.  
  177.         if (status != ERROR_SUCCESS) {
  178.             REPORT_ERROR_DATA (GENPERF_UNABLE_READ_FIRST_COUNTER, LOG_USER,
  179.                 &status, sizeof(status));
  180.             // this is fatal, if we can't get the base values of the 
  181.             // counter or help names, then the names won't be available
  182.             // to the requesting application  so there's not much
  183.             // point in continuing.
  184.             goto OpenExitPoint;
  185.         }
  186.  
  187.         size = sizeof (DWORD);
  188.         status = RegQueryValueEx(
  189.                     hKeyDriverPerf, 
  190.                     "First Help",
  191.                     0L,
  192.                     &type,
  193.                     (LPBYTE)&dwFirstHelp,
  194.             &size);
  195.  
  196.         if (status != ERROR_SUCCESS) {
  197.             REPORT_ERROR_DATA (GENPERF_UNABLE_READ_FIRST_HELP, LOG_USER,
  198.                 &status, sizeof(status));
  199.             // this is fatal, if we can't get the base values of the 
  200.             // counter or help names, then the names won't be available
  201.             // to the requesting application  so there's not much
  202.             // point in continuing.
  203.             goto OpenExitPoint;
  204.         }
  205.  
  206.         //
  207.         //  NOTE: the initialization program could also retrieve
  208.         //      LastCounter and LastHelp if they wanted to do 
  209.         //      bounds checking on the new number. e.g.
  210.         //
  211.         //      counter->CounterNameTitleIndex += dwFirstCounter;
  212.         //      if (counter->CounterNameTitleIndex > dwLastCounter) {
  213.         //          LogErrorToEventLog (INDEX_OUT_OF_BOUNDS);
  214.         //      }
  215.  
  216.         SigGenDataDefinition.SigGenObjectType.ObjectNameTitleIndex += dwFirstCounter;
  217.         SigGenDataDefinition.SigGenObjectType.ObjectHelpTitleIndex += dwFirstHelp;
  218.  
  219.         // assign index of default counter (Sine Wave)
  220.         SigGenDataDefinition.SigGenObjectType.DefaultCounter = 0;
  221.  
  222.         SigGenDataDefinition.SineWaveDef.CounterNameTitleIndex += dwFirstCounter;
  223.         SigGenDataDefinition.SineWaveDef.CounterHelpTitleIndex += dwFirstHelp;
  224.  
  225.         SigGenDataDefinition.TriangleWaveDef.CounterNameTitleIndex += dwFirstCounter;
  226.         SigGenDataDefinition.TriangleWaveDef.CounterHelpTitleIndex += dwFirstHelp;
  227.  
  228.         SigGenDataDefinition.SquareWaveDef.CounterNameTitleIndex += dwFirstCounter;
  229.         SigGenDataDefinition.SquareWaveDef.CounterHelpTitleIndex += dwFirstHelp;
  230.  
  231.         SigGenDataDefinition.ConstantValueDef.CounterNameTitleIndex += dwFirstCounter;
  232.         SigGenDataDefinition.ConstantValueDef.CounterHelpTitleIndex += dwFirstHelp;
  233.  
  234.         RegCloseKey (hKeyDriverPerf); // close key to registry
  235.  
  236.         bInitOK = TRUE; // ok to use this function
  237.     }
  238.  
  239.     dwOpenCount++;  // increment OPEN counter
  240.  
  241.     status = ERROR_SUCCESS; // for successful exit
  242.  
  243. OpenExitPoint:
  244.  
  245.     return status;
  246. }
  247.  
  248.  
  249. DWORD APIENTRY
  250. CollectSigGenPerformanceData(
  251.     IN      LPWSTR  lpValueName,
  252.     IN OUT  LPVOID  *lppData,
  253.     IN OUT  LPDWORD lpcbTotalBytes,
  254.     IN OUT  LPDWORD lpNumObjectTypes
  255. )
  256. /*++
  257.  
  258. Routine Description:
  259.  
  260.     This routine will return the data for the Signal Generator counters.
  261.  
  262. Arguments:
  263.  
  264.    IN       LPWSTR   lpValueName
  265.          pointer to a wide character string passed by registry.
  266.  
  267.    IN OUT   LPVOID   *lppData
  268.          IN: pointer to the address of the buffer to receive the completed 
  269.             PerfDataBlock and subordinate structures. This routine will
  270.             append its data to the buffer starting at the point referenced
  271.             by *lppData.
  272.          OUT: points to the first byte after the data structure added by this
  273.             routine. This routine updated the value at lppdata after appending
  274.             its data.
  275.  
  276.    IN OUT   LPDWORD  lpcbTotalBytes
  277.          IN: the address of the DWORD that tells the size in bytes of the 
  278.             buffer referenced by the lppData argument
  279.          OUT: the number of bytes added by this routine is writted to the 
  280.             DWORD pointed to by this argument
  281.  
  282.    IN OUT   LPDWORD  NumObjectTypes
  283.          IN: the address of the DWORD to receive the number of objects added 
  284.             by this routine 
  285.          OUT: the number of objects added by this routine is writted to the 
  286.             DWORD pointed to by this argument
  287.  
  288. Return Value:
  289.  
  290.       ERROR_MORE_DATA if buffer passed is too small to hold data
  291.          any error conditions encountered are reported to the event log if
  292.          event logging is enabled.
  293.  
  294.       ERROR_SUCCESS  if success or any other error. Errors, however are
  295.          also reported to the event log.
  296.  
  297. --*/
  298. {
  299.     //  Variables for reformating the data
  300.  
  301.     PERF_INSTANCE_DEFINITION *pPerfInstanceDefinition;
  302.     DWORD   dwThisInstance;
  303.     ULONG SpaceNeeded;
  304.     SIGGEN_DATA_DEFINITION *pSigGenDataDefinition;
  305.     DWORD   dwQueryType;
  306.     DWORD   dwTime;
  307.     DWORD   dwPhase;
  308.     double  dPhase, dSin;
  309.     LONG    lValue;
  310.     PSIGGEN_COUNTER   pSC;
  311.  
  312.     //
  313.     // before doing anything else, see if Open went OK
  314.     //
  315.     if (!bInitOK) {
  316.         // unable to continue because open failed.
  317.         *lpcbTotalBytes = (DWORD) 0;
  318.         *lpNumObjectTypes = (DWORD) 0;
  319.         return ERROR_SUCCESS; // yes, this is a successful exit
  320.     }
  321.     
  322.     // see if this is a foreign (i.e. non-NT) computer data request 
  323.     //
  324.     dwQueryType = GetQueryType (lpValueName);
  325.     
  326.     if (dwQueryType == QUERY_FOREIGN) {
  327.         // this routine does not service requests for data from
  328.         // Non-NT computers
  329.         *lpcbTotalBytes = (DWORD) 0;
  330.         *lpNumObjectTypes = (DWORD) 0;
  331.         return ERROR_SUCCESS;
  332.     }
  333.  
  334.     if (dwQueryType == QUERY_ITEMS){
  335.     if ( !(IsNumberInUnicodeList (SigGenDataDefinition.SigGenObjectType.ObjectNameTitleIndex, lpValueName))) {
  336.             // request received for data object not provided by this routine
  337.             *lpcbTotalBytes = (DWORD) 0;
  338.             *lpNumObjectTypes = (DWORD) 0;
  339.             return ERROR_SUCCESS;
  340.         }
  341.     }
  342.  
  343.     pSigGenDataDefinition = (SIGGEN_DATA_DEFINITION *) *lppData;
  344.  
  345.     SpaceNeeded = sizeof(SIGGEN_DATA_DEFINITION) +
  346.           (NUM_INSTANCES * (sizeof(PERF_INSTANCE_DEFINITION) +
  347.           (24) +    // size of instance names
  348.           sizeof (SIGGEN_COUNTER)));
  349.  
  350.     if ( *lpcbTotalBytes < SpaceNeeded ) {
  351.         *lpcbTotalBytes = (DWORD) 0;
  352.         *lpNumObjectTypes = (DWORD) 0;
  353.         return ERROR_MORE_DATA;
  354.     }
  355.  
  356.     // Get current time for this sample
  357.     //
  358.     dwTime = GetTimeInMilliSeconds();
  359.     //
  360.     // Copy the (constant, initialized) Object Type and counter definitions
  361.     //  to the caller's data buffer
  362.     //
  363.     memmove(pSigGenDataDefinition,
  364.        &SigGenDataDefinition,
  365.        sizeof(SIGGEN_DATA_DEFINITION));
  366.     //
  367.     //    Create data for return for each instance
  368.     //
  369.     pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)
  370.                                  &pSigGenDataDefinition[1];
  371.  
  372.     for (dwThisInstance = 0; dwThisInstance < NUM_INSTANCES; dwThisInstance++) {
  373.  
  374.         MonBuildInstanceDefinition(
  375.             pPerfInstanceDefinition,
  376.             (PVOID *)&pSC,
  377.             0,
  378.             0,
  379.             (DWORD)-1, // use name
  380.             wdInstance[dwThisInstance].szInstanceName);
  381.  
  382.         pSC->CounterBlock.ByteLength = sizeof (SIGGEN_COUNTER);
  383.  
  384.         //**********************************************************
  385.         //
  386.         // for this particular example, the data is "created" here.
  387.         // normally it would be read from the appropriate device or 
  388.         // application program.
  389.         //
  390.         //**********************************************************
  391.     
  392.         // comput phase for this instance period
  393.         dwPhase = dwTime % wdInstance[dwThisInstance].dwPeriod;
  394.         //
  395.         // compute sinewave value here
  396.         //
  397.         dPhase = (double)dwPhase / (double)wdInstance[dwThisInstance].dwPeriod;
  398.         dPhase *= d2Pi;
  399.  
  400.         // the cosine function is used to keep the phase aligned with the
  401.         // other wave forms
  402.         dSin = -cos(dPhase);
  403.         // adjust amplitude and add .5 to round to integer correctly
  404.         dSin *= (double)((wdInstance[dwThisInstance].dwAmplitude) / 2.0) + 0.5 ;
  405.     
  406.         lValue = (LONG)dSin;
  407.         lValue += wdInstance[dwThisInstance].dwAmplitude / 2;   // to move negative values above 0
  408.  
  409.         // save sine value
  410.         pSC->dwSineWaveValue = (DWORD)lValue;
  411.  
  412.         // compute triangle wave value here
  413.  
  414.         if (dwPhase < (wdInstance[dwThisInstance].dwPeriod / 2)) {
  415.             lValue = (LONG)((dwPhase * wdInstance[dwThisInstance].dwAmplitude) / (wdInstance[dwThisInstance].dwPeriod / 2));
  416.         } else {
  417.             lValue = (LONG)(((wdInstance[dwThisInstance].dwPeriod - dwPhase) * wdInstance[dwThisInstance].dwAmplitude) /
  418.                     (wdInstance[dwThisInstance].dwPeriod / 2));
  419.         }
  420.         // save triangle value
  421.         pSC->dwTriangleWaveValue = (DWORD) lValue;
  422.  
  423.         //
  424.         //  compute square wave value
  425.         //
  426.         if (dwPhase <= (wdInstance[dwThisInstance].dwPeriod / 2)) {
  427.             lValue = 0;
  428.         } else {
  429.             lValue = (LONG)wdInstance[dwThisInstance].dwAmplitude;
  430.         }
  431.         // save square value
  432.         pSC->dwSquareWaveValue = (DWORD) lValue;
  433.  
  434.         // finally the constant value (same fore every instance)
  435.         pSC->dwConstantValue = (DWORD)CONSTANT_VALUE_VALUE;
  436.  
  437.         // update instance pointer for next instance
  438.         pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)&pSC[1];
  439.     }
  440.     // update arguments for return
  441.  
  442.     *lppData = (PVOID)pPerfInstanceDefinition;
  443.     
  444.     *lpNumObjectTypes = 1;
  445.  
  446.     pSigGenDataDefinition->SigGenObjectType.TotalByteLength = 
  447.         *lpcbTotalBytes = (PBYTE)pPerfInstanceDefinition -
  448.                           (PBYTE) pSigGenDataDefinition;
  449.  
  450.     // update instance count
  451.     pSigGenDataDefinition->SigGenObjectType.NumInstances = NUM_INSTANCES;
  452.     
  453.     return ERROR_SUCCESS;
  454. }
  455.  
  456.  
  457. DWORD APIENTRY
  458. CloseSigGenPerformanceData(
  459. )
  460.  
  461. /*++
  462.  
  463. Routine Description:
  464.  
  465.     This routine closes the open handles to the Signal Gen counters.
  466.  
  467. Arguments:
  468.  
  469.     None.
  470.  
  471.  
  472. Return Value:
  473.  
  474.     ERROR_SUCCESS
  475.  
  476. --*/
  477.  
  478. {
  479.     if (!(--dwOpenCount)) { // when this is the last thread...
  480.  
  481.         MonCloseEventLog();
  482.     }
  483.  
  484.     return ERROR_SUCCESS;
  485.  
  486. }
  487.