Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

943 lines
32 KiB

  1. /*
  2. * HrProcessorEntry.c v0.10
  3. * Generated in conjunction with Management Factory scripts:
  4. * script version: SNMPv1, 0.16, Apr 25, 1996
  5. * project: D:\TEMP\EXAMPLE\HOSTMIB
  6. ****************************************************************************
  7. * *
  8. * (C) Copyright 1995 DIGITAL EQUIPMENT CORPORATION *
  9. * *
  10. * This software is an unpublished work protected under the *
  11. * the copyright laws of the United States of America, all *
  12. * rights reserved. *
  13. * *
  14. * In the event this software is licensed for use by the United *
  15. * States Government, all use, duplication or disclosure by the *
  16. * United States Government is subject to restrictions as set *
  17. * forth in either subparagraph (c)(1)(ii) of the Rights in *
  18. * Technical Data And Computer Software Clause at DFARS *
  19. * 252.227-7013, or the Commercial Computer Software Restricted *
  20. * Rights Clause at FAR 52.221-19, whichever is applicable. *
  21. * *
  22. ****************************************************************************
  23. *
  24. * Facility:
  25. *
  26. * Windows NT SNMP Extension Agent
  27. *
  28. * Abstract:
  29. *
  30. * This module contains the code for dealing with the get, set, and
  31. * instance name routines for the HrProcessorEntry. Actual instrumentation code is
  32. * supplied by the developer.
  33. *
  34. * Functions:
  35. *
  36. * A get and set routine for each attribute in the class.
  37. *
  38. * The routines for instances within the class.
  39. *
  40. * Author:
  41. *
  42. * D. D. Burns @ Webenable Inc
  43. *
  44. * Revision History:
  45. *
  46. * V1.00 - 04/28/97 D. D. Burns Genned: Thu Nov 07 16:42:19 1996
  47. *
  48. */
  49. #include <nt.h>
  50. #include <ntrtl.h>
  51. #include <nturtl.h>
  52. #include <windows.h>
  53. #include <malloc.h>
  54. #include <snmp.h>
  55. #include "mib.h"
  56. #include "smint.h"
  57. #include "hostmsmi.h"
  58. #include "user.h" /* Developer supplied include file */
  59. #include "HMCACHE.H" /* Cache-related definitions */
  60. #include "HRDEVENT.H" /* HrDevice Table-related definitions */
  61. #include <stdio.h>
  62. /*
  63. |==============================================================================
  64. | "Processor-Information Buffer" Definition
  65. |
  66. | This definition defines a logical "Processor Information Block" where we
  67. | can store all the information returned from an NtQuerySystemInformation()
  68. | call that requests "SystemProcessorPerformanceInformation" for each running
  69. | processor.
  70. */
  71. typedef
  72. struct pi_block {
  73. struct pi_block *other; // Associated "other" buffer
  74. LARGE_INTEGER sys_time; // Time when "pi_array" was last
  75. // refreshed in 100ns ticks
  76. SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
  77. *pi_array; // Array: One element per processor
  78. DWORD pi_size; // Size in bytes of "pi_array" storage
  79. }
  80. PI_BLOCK;
  81. /*
  82. |==============================================================================
  83. | "Processor-Information Buffer" Instances
  84. |
  85. | We create two instances of a Processor Information Buffer, one for the
  86. | "oldest" and a second for "newest" samples of timer values. Maintaining
  87. | two enables us to compute the average over time for processor loads.
  88. |
  89. | These blocks are initialized by code in "Gen_HrProcessor_Cache()" in
  90. | this module.
  91. |
  92. | These buffers are refreshed in an alternating manner by function
  93. | "hrProcessLoad_Refresh()" (in this module) that itself is invoked on a
  94. | timer-driven basis. (See source for the function).
  95. */
  96. static
  97. PI_BLOCK pi_buf1; // First Buffer
  98. static
  99. PI_BLOCK pi_buf2; // Second Buffer
  100. /*
  101. |==============================================================================
  102. | Oldest "Processor-Information Buffer"
  103. |
  104. | This cell points at one of the two PI_BLOCKs above. It always points to
  105. | the buffer block that has the "oldest" data in it.
  106. */
  107. static
  108. PI_BLOCK *oldest_pi=NULL;
  109. #if defined(PROC_CACHE) // For debug cache dump only
  110. static
  111. int processor_count;
  112. #endif
  113. /*
  114. * GetHrProcessorFrwID
  115. * The product ID of the firmware associated with the processor.
  116. *
  117. * Gets the value for HrProcessorFrwID.
  118. *
  119. * Arguments:
  120. *
  121. * outvalue address to return variable value
  122. * accesss Reserved for future security use
  123. * instance address of instance name as ordered native
  124. * data type(s)
  125. *
  126. * Return Codes:
  127. *
  128. * Standard PDU error codes.
  129. *
  130. * SNMP_ERRORSTATUS_NOERROR Successful get
  131. * SNMP_ERRORSTATUS_GENERR Catch-all failure code
  132. * mibtget.c v0.10
  133. *
  134. | =============== From WebEnable Design Spec Rev 3 04/11/97==================
  135. | hrProcessorFrwID
  136. |
  137. | ACCESS SYNTAX
  138. | read-only ProductID
  139. |
  140. | "The product ID of the firmware associated with the processor."
  141. |
  142. | DISCUSSION:
  143. |
  144. | <POA-11> The underlying syntax of this attribute is Object Identifier. None
  145. | of the documented Win32 API functions seem capable of reporting this value.
  146. | We are allowed to report "unknownProductID" ("0.0") in liew of the real
  147. | value, and this will be hardcoded unless an alternative is specified.
  148. |
  149. | RESOLVED >>>>>>>>
  150. | <POA-11> Returning an unknown Product ID is acceptable.
  151. | RESOLVED >>>>>>>>
  152. |
  153. |============================================================================
  154. | 1.3.6.1.2.1.25.3.3.1.1.<instance>
  155. | | | | |
  156. | | | | *-hrProcessorFrwID
  157. | | | *-hrProcessorEntry
  158. | | *-hrProcessorTable
  159. | *-hrDevice
  160. */
  161. UINT
  162. GetHrProcessorFrwID(
  163. OUT ProductID *outvalue ,
  164. IN Access_Credential *access ,
  165. IN InstanceName *instance )
  166. {
  167. /*
  168. | The deal on this attribute is that we'll never have a valid OID value
  169. | for this attribute. Consequently, we always return the standard
  170. | "unknown" OID value ("0.0") regardless of the instance value (which
  171. | by now in the calling sequence of things has been validated anyway).
  172. */
  173. if ( (outvalue->ids = SNMP_malloc(2 * sizeof( UINT ))) == NULL) {
  174. return SNMP_ERRORSTATUS_GENERR;
  175. }
  176. outvalue->idLength = 2;
  177. /*
  178. | Load in the OID value for "unknown" for ProductID: "0.0"
  179. */
  180. outvalue->ids[0] = 0;
  181. outvalue->ids[1] = 0;
  182. return SNMP_ERRORSTATUS_NOERROR ;
  183. } /* end of GetHrProcessorFrwID() */
  184. /*
  185. * GetHrProcessorLoad
  186. * The average, over the last minute, of the percentage of time that this
  187. * processor was not idle.
  188. *
  189. * Gets the value for HrProcessorLoad.
  190. *
  191. * Arguments:
  192. *
  193. * outvalue address to return variable value
  194. * accesss Reserved for future security use
  195. * instance address of instance name as ordered native
  196. * data type(s)
  197. *
  198. * Return Codes:
  199. *
  200. * Standard PDU error codes.
  201. *
  202. * SNMP_ERRORSTATUS_NOERROR Successful get
  203. * SNMP_ERRORSTATUS_GENERR Catch-all failure code
  204. * mibtget.c v0.10
  205. *
  206. | =============== From WebEnable Design Spec Rev 3 04/11/97==================
  207. | hrProcessorLoad
  208. |
  209. | ACCESS SYNTAX
  210. | read-only INTEGER (0..100)
  211. |
  212. | "The average, over the last minute, of the percentage of time that this
  213. | processor was not idle."
  214. |
  215. | DISCUSSION:
  216. |
  217. | <POA-12> It seems likely to me that this performance statistic might be
  218. | maintained or be derivable from performance information maintained in the
  219. | Registry. Please describe.
  220. |
  221. | RESOLVED >>>>>>>>
  222. | <POA-12> I think we should just use the PerfMon code for this.
  223. | RESOLVED >>>>>>>>
  224. |
  225. |============================================================================
  226. | We reference a continuously updated module-local cache of CPU time-usage
  227. | info maintained in the buffer-blocks "pi_buf1" and "pi_buf2" defined
  228. | at the beginning of this module. In the code below, we reach into these
  229. | caches and compute the processor load for the processor specified.
  230. |============================================================================
  231. | 1.3.6.1.2.1.25.3.3.1.2.<instance>
  232. | | | | |
  233. | | | | *-hrProcessorLoad
  234. | | | *-hrProcessorEntry
  235. | | *-hrProcessorTable
  236. | *-hrDevice
  237. */
  238. UINT
  239. GetHrProcessorLoad(
  240. OUT Integer *outvalue ,
  241. IN Access_Credential *access ,
  242. IN InstanceName *instance )
  243. {
  244. ULONG index; /* As fetched from instance structure */
  245. CACHEROW *row; /* Row entry fetched from cache */
  246. ULONG p; /* Selected Processor (number from 0) */
  247. SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
  248. *oldest, *newest;/* --> CPU data for "n" and "n+1minute" */
  249. LONGLONG llDendiff; /* Difference Denominator */
  250. LONGLONG llNewNum; /* Numerator of Newest Time-count */
  251. LONGLONG llOldNum; /* Numerator of Oldest Time-count */
  252. double fNum,fDen; /* Floated versions of LONGLONGs */
  253. double fload; /* Percentage Load */
  254. /*
  255. | Grab the instance information
  256. */
  257. index = GET_INSTANCE(0);
  258. /*
  259. | Use it to find the right entry in the cache
  260. */
  261. if ((row = FindTableRow(index, &hrDevice_cache)) == NULL) {
  262. return SNMP_ERRORSTATUS_GENERR;
  263. }
  264. /*
  265. | By convention with "Gen_HrProcessor_Cache()" the cache initialization
  266. | routine, the "hidden context" for devices which are "Processors" is
  267. | the Processor Number, starting with 0.
  268. */
  269. p = row->attrib_list[HIDDEN_CTX].u.unumber_value;
  270. /*
  271. | We compute the load using "SystemProcessorPerformanceInformation" that
  272. | has been gathered for all processors in buffers maintained in "pi_buf1"
  273. | and "pi_buf2".
  274. |
  275. | Obtain pointers to the "newest" and "oldest" slug of information for
  276. | the specified processor out of "pi_buf1/2".
  277. */
  278. oldest = &(oldest_pi->pi_array[p]);
  279. newest = &(oldest_pi->other->pi_array[p]);
  280. /*
  281. | The performance info (as of this writing) we need comes from:
  282. |
  283. | typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
  284. | LARGE_INTEGER IdleTime;
  285. | LARGE_INTEGER KernelTime;
  286. | LARGE_INTEGER UserTime;
  287. | LARGE_INTEGER DpcTime; // DEVL only
  288. | LARGE_INTEGER InterruptTime; // DEVL only
  289. | ULONG InterruptCount;
  290. | } ....
  291. |
  292. | where "IdleTime" is taken to be time spent by this processor in its
  293. | idlethread.
  294. |
  295. | "KernelTime" is taken to be total time spent by processor in kernel
  296. | mode code (including the idle thread).
  297. |
  298. | "UserTime" is taken to be total time spent by processor in user mode
  299. | code.
  300. |
  301. | all in ticks of 100ns (one tenth of a millionth of a second).
  302. |
  303. | So total "Not-Idle" time is "(KernelTime-IdleTime) + UserTime" in ticks.
  304. | Total time for the interval is the difference in the "sys_time" that is
  305. | associated with each buffer ("oldest_pi->" and "oldest_pi->other->").
  306. |
  307. */
  308. llNewNum = (newest->KernelTime.QuadPart - newest->IdleTime.QuadPart)
  309. + newest->UserTime.QuadPart;
  310. llOldNum = (oldest->KernelTime.QuadPart - oldest->IdleTime.QuadPart)
  311. + oldest->UserTime.QuadPart;
  312. /* (Newest System-Time) - (Oldest System-Time) */
  313. llDendiff = oldest_pi->other->sys_time.QuadPart - oldest_pi->sys_time.QuadPart;
  314. /* If there will be no divide by 0 */
  315. if ( llDendiff != 0 ) {
  316. /*
  317. | Now float these guys and convert to a percentage.
  318. */
  319. fNum = (double) (llNewNum - llOldNum);
  320. fDen = (double) llDendiff;
  321. fload = (fNum / fDen) * 100.0;
  322. }
  323. else {
  324. fload = 0.0;
  325. }
  326. *outvalue = (int) fload; // Truncate to integer
  327. return SNMP_ERRORSTATUS_NOERROR ;
  328. } /* end of GetHrProcessorLoad() */
  329. /*
  330. * HrProcessorEntryFindInstance
  331. *
  332. * This routine is used to verify that the specified instance is
  333. * valid.
  334. *
  335. * Arguments:
  336. *
  337. * FullOid Address for the full oid - group, variable,
  338. * and instance information
  339. * instance Address for instance specification as an oid
  340. *
  341. * Return Codes:
  342. *
  343. * SNMP_ERRORSTATUS_NOERROR Instance found and valid
  344. * SNMP_ERRORSTATUS_NOSUCHNAME Invalid instance
  345. *
  346. */
  347. UINT
  348. HrProcessorEntryFindInstance( IN ObjectIdentifier *FullOid ,
  349. IN OUT ObjectIdentifier *instance )
  350. {
  351. UINT tmp_instance ; /* Instance arc value */
  352. CACHEROW *row; /* Row entry fetched from cache */
  353. //
  354. // Developer instrumentation code to find appropriate instance goes here.
  355. // For non-tables, it is not necessary to modify this routine. However, if
  356. // there is any context that needs to be set, it can be done here.
  357. //
  358. if ( FullOid->idLength <= HRPROCESSORENTRY_VAR_INDEX )
  359. // No instance was specified
  360. return SNMP_ERRORSTATUS_NOSUCHNAME ;
  361. else if ( FullOid->idLength != HRPROCESSORENTRY_VAR_INDEX + 1 )
  362. // Instance length is more than 1
  363. return SNMP_ERRORSTATUS_NOSUCHNAME ;
  364. else
  365. // The only valid instance for a non-table are instance 0. If this
  366. // is a non-table, the following code validates the instances. If this
  367. // is a table, developer modification is necessary below.
  368. tmp_instance = FullOid->ids[ HRPROCESSORENTRY_VAR_INDEX ] ;
  369. /*
  370. | For hrProcessorTable, the instance arc(s) is a single arc, and
  371. | it must correctly select an entry in the hrDeviceTable cache.
  372. |
  373. | Check that here.
  374. */
  375. if ( (row = FindTableRow(tmp_instance, &hrDevice_cache)) == NULL ) {
  376. return SNMP_ERRORSTATUS_NOSUCHNAME ;
  377. }
  378. else
  379. {
  380. /*
  381. | The instance arc selects an hrDeviceTable row entry, but is that
  382. | entry actually for a device of type "Processor"?
  383. |
  384. | (We examine the last arc of the OID that specifies the device
  385. | type in the row entry selected by the instance arc).
  386. */
  387. if (row->attrib_list[HRDV_TYPE].u.unumber_value !=
  388. HRDV_TYPE_LASTARC_PROCESSOR) {
  389. return SNMP_ERRORSTATUS_NOSUCHNAME;
  390. }
  391. // the instance is valid. Create the instance portion of the OID
  392. // to be returned from this call.
  393. instance->ids[ 0 ] = tmp_instance ;
  394. instance->idLength = 1 ;
  395. }
  396. return SNMP_ERRORSTATUS_NOERROR ;
  397. } /* end of HrProcessorEntryFindInstance() */
  398. /*
  399. * HrProcessorEntryFindNextInstance
  400. *
  401. * This routine is called to get the next instance. If no instance
  402. * was passed than return the first instance (1).
  403. *
  404. * Arguments:
  405. *
  406. * FullOid Address for the full oid - group, variable,
  407. * and instance information
  408. * instance Address for instance specification as an oid
  409. *
  410. * Return Codes:
  411. *
  412. * SNMP_ERRORSTATUS_NOERROR Instance found and valid
  413. * SNMP_ERRORSTATUS_NOSUCHNAME Invalid instance
  414. *
  415. */
  416. UINT
  417. HrProcessorEntryFindNextInstance( IN ObjectIdentifier *FullOid ,
  418. IN OUT ObjectIdentifier *instance )
  419. {
  420. //
  421. // Developer supplied code to find the next instance of class goes here.
  422. // If this is a class with cardinality 1, no modification of this routine
  423. // is necessary unless additional context needs to be set.
  424. // If the FullOid does not specify an instance, then the only instance
  425. // of the class is returned. If this is a table, the first row of the
  426. // table is returned.
  427. //
  428. // If an instance is specified and this is a non-table class, then NOSUCHNAME
  429. // is returned so that correct MIB rollover processing occurs. If this is
  430. // a table, then the next instance is the one following the current instance.
  431. // If there are no more instances in the table, return NOSUCHNAME.
  432. //
  433. CACHEROW *row;
  434. ULONG tmp_instance;
  435. if ( FullOid->idLength <= HRPROCESSORENTRY_VAR_INDEX )
  436. {
  437. /*
  438. | Too short: must return the instance arc that selects the first
  439. | entry in the table if there is one.
  440. */
  441. tmp_instance = 0;
  442. }
  443. else {
  444. /*
  445. | There is at least one instance arc. Even if it is the only arc
  446. | we use it as the "index" in a request for the "NEXT" one.
  447. */
  448. tmp_instance = FullOid->ids[ HRPROCESSORENTRY_VAR_INDEX ] ;
  449. }
  450. /* Now go off and try to find the next instance in the table */
  451. if ((row = FindNextTableRow(tmp_instance, &hrDevice_cache)) == NULL) {
  452. return SNMP_ERRORSTATUS_NOSUCHNAME ;
  453. }
  454. /*
  455. | The instance arc selects an hrDeviceTable row entry, but is that
  456. | entry actually for a device of type "Processor"?
  457. |
  458. | (We examine the last arc of the OID that specifies the device
  459. | type in the row entry selected by the instance arc).
  460. */
  461. do {
  462. if (row->attrib_list[HRDV_TYPE].u.unumber_value ==
  463. HRDV_TYPE_LASTARC_PROCESSOR) {
  464. /* Found an hrDeviceTable entry for the right device type */
  465. break;
  466. }
  467. /* Step to the next row in the table */
  468. row = GetNextTableRow( row );
  469. }
  470. while ( row != NULL );
  471. /* If we found a proper device-type row . . . */
  472. if ( row != NULL) {
  473. instance->ids[ 0 ] = row->index ;
  474. instance->idLength = 1 ;
  475. }
  476. else {
  477. /*
  478. | Fell off the end of the hrDeviceTable without finding a row
  479. | entry that had the right device type.
  480. */
  481. return SNMP_ERRORSTATUS_NOSUCHNAME ;
  482. }
  483. return SNMP_ERRORSTATUS_NOERROR ;
  484. } /* end of HrProcessorEntryFindNextInstance() */
  485. /*
  486. * HrProcessorEntryConvertInstance
  487. *
  488. * This routine is used to convert the object id specification of an
  489. * instance into an ordered native representation. The object id format
  490. * is that object identifier that is returned from the Find Instance
  491. * or Find Next Instance routines. It is NOT the full object identifier
  492. * that contains the group and variable object ids as well. The native
  493. * representation is an argc/argv-like structure that contains the
  494. * ordered variables that define the instance. This is specified by
  495. * the MIB's INDEX clause. See RFC 1212 for information about the INDEX
  496. * clause.
  497. *
  498. *
  499. * Arguments:
  500. *
  501. * oid_spec Address of the object id instance specification
  502. * native_spec Address to return the ordered native instance
  503. * specification
  504. *
  505. * Return Codes:
  506. *
  507. * SUCCESS Conversion complete successfully
  508. * FAILURE Unable to convert object id into native format
  509. *
  510. */
  511. UINT
  512. HrProcessorEntryConvertInstance( IN ObjectIdentifier *oid_spec ,
  513. IN OUT InstanceName *native_spec )
  514. {
  515. static char *array; /* The address of this (char *) is passed back */
  516. /* as though it were an array of length 1 of these */
  517. /* types. */
  518. static ULONG inst; /* The address of this ULONG is passed back */
  519. /* (Obviously, no "free()" action is needed) */
  520. /* We only expect the one arc in "oid_spec" */
  521. inst = oid_spec->ids[0];
  522. array = (char *) &inst;
  523. native_spec->count = 1;
  524. native_spec->array = &array;
  525. return SUCCESS ;
  526. } /* end of HrProcessorEntryConvertInstance() */
  527. /*
  528. * HrProcessorEntryFreeInstance
  529. *
  530. * This routine is used to free an ordered native representation of an
  531. * instance name.
  532. *
  533. * Arguments:
  534. *
  535. * instance Address to return the ordered native instance
  536. * specification
  537. *
  538. * Return Codes:
  539. *
  540. *
  541. */
  542. void
  543. HrProcessorEntryFreeInstance( IN OUT InstanceName *instance )
  544. {
  545. /* No action needed for hrProcessor Table */
  546. } /* end of HrProcessorEntryFreeInstance() */
  547. /*
  548. | End of Generated Code
  549. */
  550. /* Gen_HrProcessor_Cache - Gen. a initial cache for HrDevice PROCESSOR Table */
  551. /* Gen_HrProcessor_Cache - Gen. a initial cache for HrDevice PROCESSOR Table */
  552. /* Gen_HrProcessor_Cache - Gen. a initial cache for HrDevice PROCESSOR Table */
  553. BOOL
  554. Gen_HrProcessor_Cache(
  555. ULONG type_arc
  556. )
  557. /*
  558. | EXPLICIT INPUTS:
  559. |
  560. | "type_arc" is the number "n" to be used as the last arc in the
  561. | device-type OID:
  562. |
  563. | 1.3.6.1.2.1.25.3.1.n
  564. | | | |
  565. | | | * Identifying arc for type
  566. | | *-hrDeviceTypes (OIDs specifying device types)
  567. | *-hrDevice
  568. |
  569. | for devices created by this cache-population routine.
  570. |
  571. | IMPLICIT INPUTS:
  572. |
  573. | None.
  574. |
  575. | OUTPUTS:
  576. |
  577. | On Success:
  578. | Function returns TRUE indicating that the HrDevice cache has been fully
  579. | populated with all rows required for Processor devices.
  580. |
  581. | On any Failure:
  582. | Function returns FALSE (indicating "not enough storage" or other
  583. | internal logic error).
  584. |
  585. | THE BIG PICTURE:
  586. |
  587. | At subagent startup time, the cache for each table in the MIB is
  588. | populated with rows for each row in the table. This function is
  589. | invoked by the start-up code in "Gen_HrDevice_Cache()" to
  590. | populate the cache for the HrDevice table with processor-specific
  591. | entries.
  592. |
  593. | OTHER THINGS TO KNOW:
  594. |
  595. | This function is loading entries into the existing HrDevice cache
  596. | for devices of type "processor" as well as setting up what logically
  597. | amounts to a "cache" of information used to compute the value of
  598. | hrProcessorLoad.
  599. |
  600. | Specifically, this function initializes module-local cells that
  601. | describe buffers containing processor-time information for each
  602. | processor.
  603. |
  604. | This function holds a convention with the GET routines earlier in
  605. | this module that the "HIDDEN_CTX" attribute for processors contains
  606. | a number that can be used to select which processor information
  607. | is to be returned. We generate this number here.
  608. |============================================================================
  609. | 1.3.6.1.2.1.25.3.3.1...
  610. | | | |
  611. | | | *hrProcessorEntry
  612. | | *hrProcessorTable
  613. | *-hrDevice
  614. |
  615. */
  616. {
  617. SYSTEM_INFO sys_info; /* Filled in by GetSystemInfo for processors */
  618. UINT i; /* Handy-Dandy loop index */
  619. char *descr; /* Selected description string */
  620. /* Acquire system information statistics */
  621. GetSystemInfo(&sys_info);
  622. /*
  623. | Build a description based on the system info. We presume all processors
  624. | are identical.
  625. */
  626. switch (sys_info.wProcessorArchitecture) {
  627. case PROCESSOR_ARCHITECTURE_INTEL:
  628. switch (sys_info.wProcessorLevel) {
  629. case 3: descr = "Intel 80386"; break;
  630. case 4: descr = "Intel 80486"; break;
  631. case 5: descr = "Intel Pentium"; break;
  632. default: descr = "Intel"; break;
  633. }
  634. break;
  635. case PROCESSOR_ARCHITECTURE_ALPHA:
  636. switch (sys_info.wProcessorLevel) {
  637. case 21064: descr = "Alpha 21064"; break;
  638. case 21066: descr = "Alpha 21066"; break;
  639. case 21164: descr = "Alpha 21164"; break;
  640. default: descr = "DEC Alpha"; break;
  641. }
  642. break;
  643. case PROCESSOR_ARCHITECTURE_MIPS:
  644. switch (sys_info.wProcessorLevel) {
  645. case 4: descr = "MIPS R4000"; break;
  646. default: descr = "MIPS"; break;
  647. }
  648. break;
  649. case PROCESSOR_ARCHITECTURE_PPC:
  650. switch (sys_info.wProcessorLevel) {
  651. case 1: descr = "PPC 601"; break;
  652. case 3: descr = "PPC 603"; break;
  653. case 4: descr = "PPC 604"; break;
  654. case 6: descr = "PPC 603+"; break;
  655. case 9: descr = "PPC 604+"; break;
  656. case 20: descr = "PPC 620"; break;
  657. default: descr = "PPC"; break;
  658. }
  659. break;
  660. case PROCESSOR_ARCHITECTURE_UNKNOWN:
  661. default:
  662. descr = "Unknown Processor Type";
  663. }
  664. /*
  665. | For every processor we have in the system, fill in a row in the hrDevice
  666. | table.
  667. */
  668. for (i = 0; i < sys_info.dwNumberOfProcessors; i += 1) {
  669. /*
  670. | "Hidden Context" is a generated number starting at 0 which we'll
  671. | consider to be the processor number..
  672. */
  673. if (AddHrDeviceRow(type_arc, // DeviceType OID Last-Arc
  674. descr, // Device Description
  675. &i, // Hidden Ctx "Processor #"
  676. CA_NUMBER // Hidden Ctx type
  677. ) == NULL ) {
  678. /* Something blew */
  679. return ( FALSE );
  680. }
  681. }
  682. /*
  683. | Now initialize the PI_BLOCK instances needed to compute the hrProcessorLoad
  684. | and the pointer to the PI_BLOCK instance that is to be considered the
  685. | "oldest".
  686. */
  687. /*
  688. | Storage for both buffers. . . .*/
  689. pi_buf1.pi_size = sys_info.dwNumberOfProcessors *
  690. sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION);
  691. if ((pi_buf1.pi_array = (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *)
  692. malloc(pi_buf1.pi_size)) == NULL) {
  693. return ( FALSE ); // Out of Memory
  694. }
  695. pi_buf2.pi_size = sys_info.dwNumberOfProcessors *
  696. sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION);
  697. if ((pi_buf2.pi_array = (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *)
  698. malloc(pi_buf2.pi_size)) == NULL) {
  699. return ( FALSE ); // Out of Memory
  700. }
  701. /*
  702. | Now "hook" the two buffer blocks together so we can switch between them
  703. | symmetrically.
  704. */
  705. pi_buf1.other = &pi_buf2;
  706. pi_buf2.other = &pi_buf1;
  707. #if defined(PROC_CACHE) // For debug cache dump only
  708. processor_count = sys_info.dwNumberOfProcessors;
  709. #endif
  710. /*
  711. | Pretend the first is the oldest and get it refreshed.
  712. */
  713. oldest_pi = &pi_buf1; // Select it
  714. hrProcessLoad_Refresh(); // Refresh it, and select the other as "oldest"
  715. SleepEx(1, FALSE); // Pause one millisecond to avoid divide by 0
  716. hrProcessLoad_Refresh(); // Refresh the second and select other as "oldest"
  717. /*
  718. | Now each Processor Information Block contains full information (about
  719. | all processors) separated in time by 1 millisecond. The "oldest" will
  720. | be refreshed periodically every minute by the timer which is initialized
  721. | via a call to "TrapInit()" made from source "mib.c" after the initialization
  722. | of caches is complete. Once the timer begins ticking regularly, the time
  723. | samples in these two PI_BLOCK buffers will differ by one minute, (the period
  724. | of the timer) which is the period required by the definition of
  725. | "hrProcessorLoad".
  726. */
  727. return ( TRUE );
  728. }
  729. /* hrProcessLoad_Refresh - Processor Load Time-Information Refresh Routine */
  730. /* hrProcessLoad_Refresh - Processor Load Time-Information Refresh Routine */
  731. /* hrProcessLoad_Refresh - Processor Load Time-Information Refresh Routine */
  732. void
  733. hrProcessLoad_Refresh(
  734. void
  735. )
  736. /*
  737. | EXPLICIT INPUTS:
  738. |
  739. | None.
  740. |
  741. | IMPLICIT INPUTS:
  742. |
  743. | The "Processor-Information Buffer" specified by module-local cell
  744. | "oldest_pi" is refreshed with new time information fetched from
  745. | the kernel.
  746. |
  747. | OUTPUTS:
  748. |
  749. | On Success:
  750. | The PI_Block specified by "oldest_pi" is refreshed and "oldest_pi"
  751. | is set to point to the other PI_BLOCK.
  752. |
  753. | On any Failure:
  754. | Function simply returns.
  755. |
  756. | THE BIG PICTURE:
  757. |
  758. | At subagent startup time, a timer is created by code in "TrapInit()"
  759. | set to "tick" at an interval of one minute.
  760. |
  761. | Each time the timer goes off, the SNMP Agent calls the
  762. | "SnmpExtensionTrap()" standard entry point for the sub agent. Rather
  763. | than handle a trap, that function will invoke this function which
  764. | gathers CPU performance data so that the hrProcessLoad value can be
  765. | properly computed.
  766. |
  767. | OTHER THINGS TO KNOW:
  768. |
  769. | We alternate the buffer into which the newest CPU data is placed
  770. | by simply changing "oldest_pi" (each time we're invoked) to point
  771. | to the "other" buffer after we're done refreshing the oldest buffer.
  772. | In this manner, we always have two buffers of Processor Load info
  773. | allowing us to compute the load during the times associated with
  774. | those two buffers.
  775. */
  776. {
  777. NTSTATUS ntstatus;
  778. DWORD bytesused;
  779. /* Get the current system-time in 100ns intervals . . .*/
  780. ntstatus = NtQuerySystemTime (&oldest_pi->sys_time);
  781. /*
  782. | . . . and as rapidly thereafter refresh the oldest buffer with information
  783. | on all processors */
  784. ntstatus = NtQuerySystemInformation(SystemProcessorPerformanceInformation,
  785. oldest_pi->pi_array,
  786. oldest_pi->pi_size,
  787. &bytesused);
  788. #if defined(PROC_CACHE)
  789. /* =========================== DEBUG DUMP ================================== */
  790. {
  791. FILE *pfile; /* Dump goes here */
  792. time_t ltime; /* For debug message */
  793. int i; /* Loop index */
  794. SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
  795. *oldest, *newest;/* --> CPU data for "n" and "n+1minute" */
  796. if ((pfile=fopen(PROC_FILE, "a+")) != NULL) {
  797. time( &ltime);
  798. fprintf(pfile, "\n=============== Open for appending: %s", ctime( &ltime ));
  799. fprintf(pfile, "Periodic Refresh of \"oldest_pi\" @ %x\n", oldest_pi);
  800. /* For each processor . . . */
  801. for (i=0; i < processor_count; i += 1) {
  802. fprintf(pfile, "For Processor %d:\n", i);
  803. oldest = &(oldest_pi->pi_array[i]);
  804. //newest = &(oldest_pi->other->pi_array[i]);
  805. fprintf(pfile, " IdleTime = (HI) %x (LO) %x\n",
  806. oldest->IdleTime.HighPart, oldest->IdleTime.LowPart);
  807. fprintf(pfile, " KernelTime = (HI) %x (LO) %x\n",
  808. oldest->KernelTime.HighPart, oldest->KernelTime.LowPart);
  809. fprintf(pfile, " UserTime = (HI) %x (LO) %x\n",
  810. oldest->UserTime.HighPart, oldest->UserTime.LowPart);
  811. }
  812. }
  813. fclose(pfile);
  814. }
  815. /* =========================== DEBUG DUMP ================================== */
  816. #endif
  817. /* Now the other buffer contains the "oldest" data, so change "oldest_pi" */
  818. oldest_pi = oldest_pi->other;
  819. }