Source code of Windows XP (NT5)
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.

301 lines
7.5 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name :
  4. dpte.hxx
  5. Abstract:
  6. This module determines the size of transfer chunks to be used when
  7. calling TransmitFile()
  8. Author:
  9. Bilal Alam ( t-bilala ) 9-April-1997
  10. Environment:
  11. User Mode -- Win32
  12. Project:
  13. Internet Services Asynchronous Thread Queue DLL
  14. --*/
  15. #ifndef DPTE_HXX_INCLUDED
  16. #define DPTE_HXX_INCLUDED
  17. #ifndef PAGE_SIZE
  18. #define MINIMUM_CHUNK_SIZE 4096
  19. #else
  20. #define MINIMUM_CHUNK_SIZE PAGE_SIZE
  21. #endif
  22. #define DEFAULT_CHUNK_SIZE 65536
  23. #define ROUND_CHUNK_SIZE( cb ) ( (((cb) + 512)/1024) * 1024)
  24. /* ChunkAlgorithms
  25. The goal is to improve upon the existing behaviour where TransmitFile()
  26. calls set the nNumberOfBytesPerSend = 0. This (for NT server) causes
  27. 64K to be used for each TransmitFile() and this is problematic for slow
  28. links since huge amounts of memory are kept in use. To address this
  29. problem, a ChunkAlgorithm is used to dynamically set the chunk size for
  30. the TransmitFile() call. The policy for each algorithm determines when
  31. to decrease the chunk size and when to increase it again.
  32. */
  33. /* Plugging this stuff in
  34. - In the registry, algorithm number and parameter are set (default case
  35. is DefaultChunkAlgorithm,0 )
  36. - Construct appropriate chunk algorithm (global to ATQ)
  37. - In the ATQ timeout call, call Evaluate() method of chunk algorithm
  38. - Before doing TransmitFile() call QueryChunkSize() to get chunk size to
  39. pass into TransmitFile()
  40. - For SPUDTransmitFileAndRecv(), set the
  41. AFD_TRANSMIT_FILE_INFO.SendPacketLength member appropriately.
  42. - Store the chunk size in the ATQ context so that when the TransmitFile()
  43. completes, you can appropriately update the statistics (if necessary)
  44. through the DecreaseUsage() method.
  45. */
  46. /* ChunkAlgorithm is base class from which all chunksize algorithms are
  47. derived.
  48. */
  49. class ChunkAlgorithm
  50. {
  51. public:
  52. ChunkAlgorithm( DWORD dwSize = DEFAULT_CHUNK_SIZE ) :
  53. _cbChunkSize( dwSize )
  54. {
  55. }
  56. virtual ~ChunkAlgorithm( VOID )
  57. {
  58. }
  59. // SetParameter()
  60. //
  61. // Used to set parameters for use by the chunk algorithms.
  62. virtual BOOL SetParameter( DWORD dwParmNumber, DWORD dwValue ) = 0;
  63. // Evaluate()
  64. //
  65. // This is called every ATQ_TIMEOUT to re-evaluate the chunk size and if
  66. // necessary, change the size for subsequent requests.
  67. virtual VOID Evaluate( VOID ) = 0;
  68. // IncreaseUsage()
  69. //
  70. // When a TransmitFile() call is about to occur, ATQ will call this
  71. // method to update the statistic maintaining current PTE usage. For
  72. // algorithms that don't keep statistics, the virtual function will be
  73. // a NOP.
  74. virtual VOID IncreaseUsage( DWORD cbUsage ) = 0;
  75. // DecreaseUsage()
  76. //
  77. // When a TransmitFile() call has completed, ATQ will call this
  78. // method to update the statistic maintaining current PTE usage. For
  79. // algorithms that don't keep statistics, the virtual function will be
  80. // a NOP.
  81. virtual VOID DecreaseUsage( DWORD cbUsage ) = 0;
  82. // QueryChunkSize()
  83. //
  84. // Before calling TransmitFile() this function will be called to get
  85. // the chunk size to be passed into TransmitFile().
  86. DWORD QueryChunkSize( VOID )
  87. {
  88. return _cbChunkSize;
  89. }
  90. protected:
  91. DWORD _cbChunkSize;
  92. };
  93. /* DefaultAlgorithm sets the chunksize for TransmitFile() to be a constant.
  94. By default, this is the algorithm used with the fixed value being 0.
  95. (this default case is the original behaviour of ATQ). The fixed value
  96. can be non-zero in which case all TransmitFile() call will use this value
  97. as the chunk size.
  98. */
  99. class DefaultAlgorithm : public ChunkAlgorithm
  100. {
  101. public:
  102. DefaultAlgorithm( VOID ) : ChunkAlgorithm( 0 )
  103. {
  104. }
  105. ~DefaultAlgorithm( VOID )
  106. {
  107. }
  108. BOOL SetParameter( DWORD dwParmNumber, DWORD dwValue )
  109. {
  110. ATQ_ASSERT( dwParmNumber == 1 );
  111. if ( dwParmNumber == 1 )
  112. {
  113. _cbChunkSize = dwValue;
  114. return TRUE;
  115. }
  116. else
  117. {
  118. return FALSE;
  119. }
  120. }
  121. VOID IncreaseUsage( DWORD cbUsage )
  122. {
  123. }
  124. VOID DecreaseUsage( DWORD cbUsage )
  125. {
  126. }
  127. VOID Evaluate( VOID )
  128. {
  129. }
  130. };
  131. /* DivideAlgorithm keeps statistics on the current amount of PTE usage and
  132. compares this to a given threshold value. The closer the amount gets to
  133. the threshold, the lower the chunk size becomes. Beware of this algorithm
  134. since it actually takes statistics and thus significantly can slow down
  135. the mainline code path for TransmitFile().
  136. */
  137. class DivideAlgorithm : public ChunkAlgorithm
  138. {
  139. public:
  140. DivideAlgorithm( VOID )
  141. {
  142. }
  143. ~DivideAlgorithm( VOID )
  144. {
  145. }
  146. BOOL SetParameter( DWORD dwParmNumber, DWORD dwValue )
  147. {
  148. ATQ_ASSERT( dwParmNumber == 1 );
  149. if ( dwParmNumber == 1 )
  150. {
  151. _cbThreshold = dwValue;
  152. return TRUE;
  153. }
  154. else
  155. {
  156. return FALSE;
  157. }
  158. }
  159. VOID Evaluate( VOID )
  160. {
  161. DWORD cbCurrentUsage = _cbCurrentUsage;
  162. DWORD cbFree = _cbThreshold - cbCurrentUsage;
  163. if ( _cbThreshold > cbCurrentUsage )
  164. {
  165. _cbChunkSize =
  166. ROUND_CHUNK_SIZE( DEFAULT_CHUNK_SIZE / ( _cbThreshold / cbFree ) );
  167. if ( _cbChunkSize < MINIMUM_CHUNK_SIZE )
  168. {
  169. _cbChunkSize = MINIMUM_CHUNK_SIZE;
  170. }
  171. }
  172. else
  173. {
  174. _cbChunkSize = MINIMUM_CHUNK_SIZE;
  175. }
  176. }
  177. VOID IncreaseUsage( DWORD cbUsage )
  178. {
  179. InterlockedExchangeAdd( (LPLONG) &_cbCurrentUsage, (LONG) cbUsage );
  180. }
  181. VOID DecreaseUsage( DWORD cbUsage )
  182. {
  183. InterlockedExchangeAdd( (LPLONG) &_cbCurrentUsage, ( (LONG) cbUsage ) * -1 );
  184. }
  185. private:
  186. DWORD _cbCurrentUsage;
  187. DWORD _cbThreshold;
  188. };
  189. /* MemoryLoadAlgorithm uses the GlobalMemoryStatus() function to determine
  190. what the chunk size should be for TransmitFile(). This API call will return
  191. (amongst other things) a load value from 0-100. This value is used to
  192. set the chunk size.
  193. */
  194. class MemoryLoadAlgorithm : public ChunkAlgorithm
  195. {
  196. public:
  197. MemoryLoadAlgorithm( VOID )
  198. {
  199. rChunkSizeTable[ 0 ] = DEFAULT_CHUNK_SIZE;
  200. rChunkSizeTable[ 1 ] = DEFAULT_CHUNK_SIZE;
  201. rChunkSizeTable[ 2 ] = DEFAULT_CHUNK_SIZE;
  202. rChunkSizeTable[ 3 ] = DEFAULT_CHUNK_SIZE;
  203. rChunkSizeTable[ 4 ] = DEFAULT_CHUNK_SIZE >> 1;
  204. rChunkSizeTable[ 5 ] = DEFAULT_CHUNK_SIZE >> 2;
  205. rChunkSizeTable[ 6 ] = DEFAULT_CHUNK_SIZE >> 3;
  206. rChunkSizeTable[ 7 ] = DEFAULT_CHUNK_SIZE >> 4;
  207. rChunkSizeTable[ 8 ] = MINIMUM_CHUNK_SIZE;
  208. rChunkSizeTable[ 9 ] = MINIMUM_CHUNK_SIZE;
  209. rChunkSizeTable[ 10] = MINIMUM_CHUNK_SIZE;
  210. }
  211. ~MemoryLoadAlgorithm( VOID )
  212. {
  213. }
  214. BOOL SetParameter( DWORD dwParmNumber, DWORD dwValue )
  215. {
  216. return TRUE;
  217. }
  218. VOID Evaluate( VOID )
  219. {
  220. MEMORYSTATUS memStatus;
  221. GlobalMemoryStatus( &memStatus );
  222. InterlockedExchange( (LPLONG) &_cbChunkSize,
  223. rChunkSizeTable[ memStatus.dwMemoryLoad / 10 ] );
  224. }
  225. VOID IncreaseUsage( DWORD cbUsage )
  226. {
  227. }
  228. VOID DecreaseUsage( DWORD cbUsage )
  229. {
  230. }
  231. private:
  232. DWORD rChunkSizeTable[ 11 ];
  233. };
  234. #endif