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.

577 lines
18 KiB

  1. /*
  2. * encstats.c
  3. *
  4. * Routines for calculating statistics on a block of data which
  5. * has been compressed, but not yet output.
  6. *
  7. * These routines are used to determine which encoding method to use
  8. * to output the block.
  9. */
  10. #include "encoder.h"
  11. static void tally_aligned_bits(t_encoder_context *context, ulong dist_to_end_at)
  12. {
  13. ulong *dist_ptr;
  14. ulong i;
  15. ulong match_pos;
  16. /*
  17. * Tally the lower 3 bits
  18. */
  19. dist_ptr = context->enc_DistData;
  20. for (i = dist_to_end_at; i > 0; i--)
  21. {
  22. match_pos = *dist_ptr++;
  23. /*
  24. * Only for matches which have >= 3 extra bits
  25. */
  26. if (match_pos >= MPSLOT3_CUTOFF)
  27. context->enc_aligned_tree_freq[match_pos & 7]++;
  28. }
  29. }
  30. /*
  31. * Determine whether it is advantageous to use aligned block
  32. * encoding on the block.
  33. */
  34. lzx_block_type get_aligned_stats(t_encoder_context *context, ulong dist_to_end_at)
  35. {
  36. byte i;
  37. ulong total_L3 = 0;
  38. ulong largest_L3 = 0;
  39. memset(
  40. context->enc_aligned_tree_freq,
  41. 0,
  42. ALIGNED_NUM_ELEMENTS * sizeof(context->enc_aligned_tree_freq[0])
  43. );
  44. tally_aligned_bits(context, dist_to_end_at);
  45. for (i = 0; i < ALIGNED_NUM_ELEMENTS; i++)
  46. {
  47. if (context->enc_aligned_tree_freq[i] > largest_L3)
  48. largest_L3 = context->enc_aligned_tree_freq[i];
  49. total_L3 += context->enc_aligned_tree_freq[i];
  50. }
  51. /*
  52. * Do aligned offsets if the largest frequency accounts for 20%
  53. * or more (as opposed to 12.5% for non-aligned offset blocks).
  54. *
  55. * Not worthwhile to do aligned offsets if we have < 100 matches
  56. */
  57. if ((largest_L3 > total_L3/5) && dist_to_end_at >= 100)
  58. return BLOCKTYPE_ALIGNED;
  59. else
  60. return BLOCKTYPE_VERBATIM;
  61. }
  62. /*
  63. * Calculates the frequency of each literal, and returns the total
  64. * number of uncompressed bytes compressed in the block.
  65. */
  66. static ulong tally_frequency(
  67. t_encoder_context *context,
  68. ulong literal_to_start_at,
  69. ulong distance_to_start_at,
  70. ulong literal_to_end_at
  71. )
  72. {
  73. ulong i;
  74. ulong d;
  75. ulong compressed_bytes = 0;
  76. d = distance_to_start_at;
  77. for (i = literal_to_start_at; i < literal_to_end_at; i++)
  78. {
  79. if (!IsMatch(i))
  80. {
  81. /* Uncompressed symbol */
  82. context->enc_main_tree_freq[context->enc_LitData[i]]++;
  83. compressed_bytes++;
  84. }
  85. else
  86. {
  87. /* Match */
  88. if (context->enc_LitData[i] < NUM_PRIMARY_LENGTHS)
  89. {
  90. context->enc_main_tree_freq[ NUM_CHARS + (MP_SLOT(context->enc_DistData[d])<<NL_SHIFT) + context->enc_LitData[i]] ++;
  91. }
  92. else
  93. {
  94. context->enc_main_tree_freq[ (NUM_CHARS + NUM_PRIMARY_LENGTHS) + (MP_SLOT(context->enc_DistData[d])<<NL_SHIFT)] ++;
  95. context->enc_secondary_tree_freq[context->enc_LitData[i] - NUM_PRIMARY_LENGTHS] ++;
  96. }
  97. compressed_bytes += context->enc_LitData[i]+MIN_MATCH;
  98. #ifdef EXTRALONGMATCHES
  99. if (( context->enc_LitData[ i ] + MIN_MATCH ) == MAX_MATCH ) {
  100. compressed_bytes += context->enc_ExtraLength[ i ];
  101. }
  102. #endif
  103. d++;
  104. }
  105. }
  106. return compressed_bytes;
  107. }
  108. /*
  109. * Get statistics
  110. */
  111. ulong get_block_stats(
  112. t_encoder_context *context,
  113. ulong literal_to_start_at,
  114. ulong distance_to_start_at,
  115. ulong literal_to_end_at
  116. )
  117. {
  118. memset(
  119. context->enc_main_tree_freq,
  120. 0,
  121. MAIN_TREE_ELEMENTS * sizeof(context->enc_main_tree_freq[0])
  122. );
  123. memset(
  124. context->enc_secondary_tree_freq,
  125. 0,
  126. NUM_SECONDARY_LENGTHS * sizeof(context->enc_secondary_tree_freq[0])
  127. );
  128. return tally_frequency(
  129. context,
  130. literal_to_start_at,
  131. distance_to_start_at,
  132. literal_to_end_at
  133. );
  134. }
  135. /*
  136. * Update cumulative statistics
  137. */
  138. ulong update_cumulative_block_stats(
  139. t_encoder_context *context,
  140. ulong literal_to_start_at,
  141. ulong distance_to_start_at,
  142. ulong literal_to_end_at
  143. )
  144. {
  145. return tally_frequency(
  146. context,
  147. literal_to_start_at,
  148. distance_to_start_at,
  149. literal_to_end_at
  150. );
  151. }
  152. /*
  153. * Used in block splitting
  154. *
  155. * This routine calculates the "difference in composition" between
  156. * two different sections of compressed data.
  157. *
  158. * Resolution must be evenly divisible by STEP_SIZE, and must be
  159. * a power of 2.
  160. */
  161. #define RESOLUTION 1024
  162. /*
  163. * Threshold for determining if two blocks are different
  164. *
  165. * If enough consecutive blocks are this different, the block
  166. * splitter will start investigating, narrowing down the
  167. * area where the change occurs.
  168. *
  169. * It will then look for two areas which are
  170. * EARLY_BREAK_THRESHOLD (or more) different.
  171. *
  172. * If THRESHOLD is too small, it will force examination
  173. * of a lot of blocks, slowing down the compressor.
  174. *
  175. * The EARLY_BREAK_THRESHOLD is the more important value.
  176. */
  177. #define THRESHOLD 1400
  178. /*
  179. * Threshold for determining if two blocks are REALLY different
  180. */
  181. #define EARLY_BREAK_THRESHOLD 1700
  182. /*
  183. * Must be >= 8 because ItemType[] array is in bits
  184. *
  185. * Must be a power of 2.
  186. *
  187. * This is the step size used to narrow down the exact
  188. * best point to split the block.
  189. */
  190. #define STEP_SIZE 64
  191. /*
  192. * Minimum # literals required to perform block
  193. * splitting at all.
  194. */
  195. #define MIN_LITERALS_REQUIRED 6144
  196. /*
  197. * Minimum # literals we will allow to be its own block.
  198. *
  199. * We don't want to create blocks with too small numbers
  200. * of literals, otherwise the static tree output will
  201. * take up too much space.
  202. */
  203. #define MIN_LITERALS_IN_BLOCK 4096
  204. static const long square_table[17] =
  205. {
  206. 0,1,4,9,16,25,36,49,64,81,100,121,144,169,196,225,256
  207. };
  208. /*
  209. * log2(x) = x < 256 ? log2_table[x] : 8 + log2_table[(x >> 8)]
  210. *
  211. * log2(0) = 0
  212. * log2(1) = 1
  213. * log2(2) = 2
  214. * log2(3) = 2
  215. * log2(4) = 3
  216. * log2(255) = 8
  217. * log2(256) = 9
  218. * log2(511) = 9
  219. * log2(512) = 10
  220. *
  221. * It's not a real log2; it's off by one because we have
  222. * log2(0) = 0.
  223. */
  224. static const byte log2_table[256] =
  225. {
  226. 0,1,2,2,3,3,3,3,
  227. 4,4,4,4,4,4,4,4,
  228. 5,5,5,5,5,5,5,5,
  229. 5,5,5,5,5,5,5,5,
  230. 6,6,6,6,6,6,6,6,
  231. 6,6,6,6,6,6,6,6,
  232. 6,6,6,6,6,6,6,6,
  233. 6,6,6,6,6,6,6,6,
  234. 7,7,7,7,7,7,7,7,
  235. 7,7,7,7,7,7,7,7,
  236. 7,7,7,7,7,7,7,7,
  237. 7,7,7,7,7,7,7,7,
  238. 7,7,7,7,7,7,7,7,
  239. 7,7,7,7,7,7,7,7,
  240. 7,7,7,7,7,7,7,7,
  241. 7,7,7,7,7,7,7,7,
  242. 8,8,8,8,8,8,8,8,
  243. 8,8,8,8,8,8,8,8,
  244. 8,8,8,8,8,8,8,8,
  245. 8,8,8,8,8,8,8,8,
  246. 8,8,8,8,8,8,8,8,
  247. 8,8,8,8,8,8,8,8,
  248. 8,8,8,8,8,8,8,8,
  249. 8,8,8,8,8,8,8,8,
  250. 8,8,8,8,8,8,8,8,
  251. 8,8,8,8,8,8,8,8,
  252. 8,8,8,8,8,8,8,8,
  253. 8,8,8,8,8,8,8,8,
  254. 8,8,8,8,8,8,8,8,
  255. 8,8,8,8,8,8,8,8,
  256. 8,8,8,8,8,8,8,8,
  257. 8,8,8,8,8,8,8,8
  258. };
  259. /*
  260. * Return the difference between two sets of matches/distances
  261. */
  262. static ulong return_difference(
  263. t_encoder_context *context,
  264. ulong item_start1,
  265. ulong item_start2,
  266. ulong dist_at_1,
  267. ulong dist_at_2,
  268. ulong size
  269. )
  270. {
  271. ushort freq1[800];
  272. ushort freq2[800];
  273. ulong i;
  274. ulong cum_diff;
  275. int element;
  276. /*
  277. * Error! Too many main tree elements
  278. */
  279. if (MAIN_TREE_ELEMENTS >= (sizeof(freq1)/sizeof(freq1[0])))
  280. return 0;
  281. memset(freq1, 0, sizeof(freq1[0])*MAIN_TREE_ELEMENTS);
  282. memset(freq2, 0, sizeof(freq2[0])*MAIN_TREE_ELEMENTS);
  283. for (i = 0; i < size; i++)
  284. {
  285. if (!IsMatch(item_start1))
  286. {
  287. element = context->enc_LitData[item_start1];
  288. }
  289. else
  290. {
  291. if (context->enc_LitData[item_start1] < NUM_PRIMARY_LENGTHS)
  292. element = NUM_CHARS + (MP_SLOT(context->enc_DistData[dist_at_1])<<NL_SHIFT) + context->enc_LitData[item_start1];
  293. else
  294. element = (NUM_CHARS + NUM_PRIMARY_LENGTHS) + (MP_SLOT(context->enc_DistData[dist_at_1]) << NL_SHIFT);
  295. dist_at_1++;
  296. }
  297. item_start1++;
  298. freq1[element]++;
  299. if (!IsMatch(item_start2))
  300. {
  301. element = context->enc_LitData[item_start2];
  302. }
  303. else
  304. {
  305. if (context->enc_LitData[item_start2] < NUM_PRIMARY_LENGTHS)
  306. element = NUM_CHARS + (MP_SLOT(context->enc_DistData[dist_at_2])<<NL_SHIFT) + context->enc_LitData[item_start2];
  307. else
  308. element = (NUM_CHARS + NUM_PRIMARY_LENGTHS) + (MP_SLOT(context->enc_DistData[dist_at_2]) << NL_SHIFT);
  309. dist_at_2++;
  310. }
  311. item_start2++;
  312. freq2[element]++;
  313. }
  314. cum_diff = 0;
  315. for (i = 0; i < (ulong) MAIN_TREE_ELEMENTS; i++)
  316. {
  317. ulong log2a, log2b, diff;
  318. #define log2(x) ((x) < 256 ? log2_table[(x)] : 8+log2_table[(x) >> 8])
  319. log2a = (ulong) log2(freq1[i]);
  320. log2b = (ulong) log2(freq2[i]);
  321. /* diff = (log2a*log2a) - (log2b*log2b); */
  322. diff = square_table[log2a] - square_table[log2b];
  323. cum_diff += abs(diff);
  324. }
  325. return cum_diff;
  326. }
  327. /*
  328. * Calculates where and if a block of compressed data should be split.
  329. *
  330. * For example, if we have just compressed text data, audio data, and
  331. * more text data, then the composition of matches and unmatched
  332. * symbols will be different between the text data and audio data.
  333. * Therefore we force an end of block whenever the compressed data
  334. * looks like it's changing in composition.
  335. *
  336. * This routine currently cannot tell the difference between blocks
  337. * which should use aligned offsets, and blocks which should not.
  338. * However, there is little to be gained from looking for this change,
  339. * since it the match finder doesn't make an effort to look for
  340. * aligned offsets either.
  341. *
  342. * Returns whether we split the block or not.
  343. */
  344. bool split_block(
  345. t_encoder_context *context,
  346. ulong literal_to_start_at,
  347. ulong literal_to_end_at,
  348. ulong distance_to_end_at, /* corresponds to # distances at literal_to_end_at */
  349. ulong *split_at_literal,
  350. ulong *split_at_distance /* optional parameter (may be NULL) */
  351. )
  352. {
  353. ulong i, j, d;
  354. int nd;
  355. /*
  356. * num_dist_at_item[n] equals the cumulative number of matches
  357. * at literal "n / STEP_SIZE".
  358. */
  359. ushort num_dist_at_item[(MAX_LITERAL_ITEMS/STEP_SIZE)+8]; /* +8 is slop */
  360. /*
  361. * default return
  362. */
  363. *split_at_literal = literal_to_end_at;
  364. if (split_at_distance)
  365. *split_at_distance = distance_to_end_at;
  366. /* Not worth doing if we don't have many literals */
  367. if (literal_to_end_at - literal_to_start_at < MIN_LITERALS_REQUIRED)
  368. return false;
  369. /* Not allowed to split blocks any more, so we don't overflow MAX_GROWTH? */
  370. if (context->enc_num_block_splits >= MAX_BLOCK_SPLITS)
  371. return false;
  372. /*
  373. * Keep track of the number of distances (matches) we've had,
  374. * at each step of STEP_SIZE literals.
  375. *
  376. * Look at 8 items at a time, and ignore the last
  377. * 0..7 items if they exist.
  378. */
  379. nd = 0;
  380. d = 0;
  381. for (i = 0; i < (literal_to_end_at >> 3); i++)
  382. {
  383. /*
  384. * if (i % (STEP_SIZE >> 3)) == 0
  385. */
  386. if ((i & ((STEP_SIZE >> 3)-1)) == 0)
  387. num_dist_at_item[nd++] = (ushort) d;
  388. d += context->enc_ones[ context->enc_ItemType[i] ];
  389. }
  390. /*
  391. * Must be a multiple of STEP_SIZE
  392. */
  393. literal_to_start_at = (literal_to_start_at + (STEP_SIZE-1)) & (~(STEP_SIZE-1));
  394. /*
  395. * See where the change in composition occurs
  396. */
  397. for ( i = literal_to_start_at + 2*RESOLUTION;
  398. i < literal_to_end_at - 4*RESOLUTION;
  399. i += RESOLUTION)
  400. {
  401. /*
  402. * If there appears to be a significant variance in composition
  403. * between
  404. * ___________
  405. * / \
  406. * A B i X Y Z
  407. * \ \___/ /
  408. * \_______________/
  409. */
  410. if (
  411. return_difference(
  412. context,
  413. i,
  414. i+1*RESOLUTION,
  415. (ulong) num_dist_at_item[i/STEP_SIZE],
  416. (ulong) num_dist_at_item[(i+1*RESOLUTION)/STEP_SIZE],
  417. RESOLUTION) > THRESHOLD
  418. &&
  419. return_difference(
  420. context,
  421. i-RESOLUTION,
  422. i+2*RESOLUTION,
  423. (ulong) num_dist_at_item[(i-RESOLUTION)/STEP_SIZE],
  424. (ulong) num_dist_at_item[(i+2*RESOLUTION)/STEP_SIZE],
  425. RESOLUTION) > THRESHOLD
  426. &&
  427. return_difference(
  428. context,
  429. i-2*RESOLUTION,
  430. i+3*RESOLUTION,
  431. (ulong) num_dist_at_item[(i-2*RESOLUTION)/STEP_SIZE],
  432. (ulong) num_dist_at_item[(i+3*RESOLUTION)/STEP_SIZE],
  433. RESOLUTION) > THRESHOLD
  434. )
  435. {
  436. ulong max_diff = 0;
  437. ulong literal_split = 0;
  438. /*
  439. * Narrow down the best place to split block
  440. *
  441. * This really could be done much better; we could end up
  442. * doing a lot of stepping;
  443. *
  444. * basically ((5/2 - 1/2) * RESOLUTION) / STEP_SIZE
  445. *
  446. * which is (2 * RESOLUTION) / STEP_SIZE,
  447. * which with RESOLUTION = 1024 and STEP_SIZE = 32,
  448. * equals 2048/32 = 64 steps.
  449. */
  450. for (j = i+RESOLUTION/2; j<i+(5*RESOLUTION)/2; j += STEP_SIZE)
  451. {
  452. ulong diff;
  453. diff = return_difference(
  454. context,
  455. j - RESOLUTION,
  456. j,
  457. (ulong) num_dist_at_item[(j-RESOLUTION)/STEP_SIZE],
  458. (ulong) num_dist_at_item[j/STEP_SIZE],
  459. RESOLUTION
  460. );
  461. /* Get largest difference */
  462. if (diff > max_diff)
  463. {
  464. /*
  465. * j should not be too small, otherwise we'll be outputting
  466. * a very small block
  467. */
  468. max_diff = diff;
  469. literal_split = j;
  470. }
  471. }
  472. /*
  473. * There could be multiple changes in the data in our literals,
  474. * so if we find something really weird, make sure we break the
  475. * block now, and not on some later change.
  476. */
  477. if (max_diff >= EARLY_BREAK_THRESHOLD &&
  478. (literal_split-literal_to_start_at) >= MIN_LITERALS_IN_BLOCK)
  479. {
  480. context->enc_num_block_splits++;
  481. *split_at_literal = literal_split;
  482. /*
  483. * Return the associated # distances, if required.
  484. * Since we split on a literal which is % STEP_SIZE, we
  485. * can read the # distances right off
  486. */
  487. if (split_at_distance)
  488. *split_at_distance = num_dist_at_item[literal_split/STEP_SIZE];
  489. return true;
  490. }
  491. }
  492. }
  493. /*
  494. * No good place found to split
  495. */
  496. return false;
  497. }