thwack.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <ip.h>
  4. #include <auth.h>
  5. #include "ppp.h"
  6. #include "thwack.h"
  7. typedef struct Huff Huff;
  8. enum
  9. {
  10. MaxFastLen = 9,
  11. BigLenCode = 0x1f4, /* minimum code for large lenth encoding */
  12. BigLenBits = 9,
  13. BigLenBase = 4 /* starting items to encode for big lens */
  14. };
  15. enum
  16. {
  17. StatBytes,
  18. StatOutBytes,
  19. StatLits,
  20. StatMatches,
  21. StatOffBits,
  22. StatLenBits,
  23. StatDelay,
  24. StatHist,
  25. MaxStat
  26. };
  27. struct Huff
  28. {
  29. short bits; /* length of the code */
  30. ulong encode; /* the code */
  31. };
  32. static Huff lentab[MaxFastLen] =
  33. {
  34. {2, 0x2}, /* 10 */
  35. {3, 0x6}, /* 110 */
  36. {5, 0x1c}, /* 11100 */
  37. {5, 0x1d}, /* 11101 */
  38. {6, 0x3c}, /* 111100 */
  39. {7, 0x7a}, /* 1111010 */
  40. {7, 0x7b}, /* 1111011 */
  41. {8, 0xf8}, /* 11111000 */
  42. {8, 0xf9}, /* 11111001 */
  43. };
  44. void
  45. thwackinit(Thwack *tw)
  46. {
  47. int i;
  48. qlock(&tw->acklock);
  49. tw->slot = 0;
  50. memset(tw->hash, 0, sizeof(tw->hash));
  51. memset(tw->blocks, 0, sizeof(tw->blocks));
  52. for(i = 0; i < EWinBlocks; i++){
  53. tw->blocks[i].hash = tw->hash[i];
  54. if(tw->data[i] != nil){
  55. freeb(tw->data[i]);
  56. tw->data[i] = nil;
  57. }
  58. }
  59. qunlock(&tw->acklock);
  60. }
  61. void
  62. thwackcleanup(Thwack *tw)
  63. {
  64. int i;
  65. qlock(&tw->acklock);
  66. for(i = 0; i < EWinBlocks; i++){
  67. if(tw->data[i] != nil){
  68. freeb(tw->data[i]);
  69. tw->data[i] = nil;
  70. }
  71. }
  72. qunlock(&tw->acklock);
  73. }
  74. /*
  75. * acknowledgement for block seq & nearby preds
  76. */
  77. void
  78. thwackack(Thwack *tw, ulong seq, ulong mask)
  79. {
  80. int slot, b;
  81. qlock(&tw->acklock);
  82. slot = tw->slot;
  83. for(;;){
  84. slot--;
  85. if(slot < 0)
  86. slot += EWinBlocks;
  87. if(slot == tw->slot)
  88. break;
  89. if(tw->blocks[slot].seq != seq)
  90. continue;
  91. tw->blocks[slot].acked = 1;
  92. if(mask == 0)
  93. break;
  94. do{
  95. b = mask & 1;
  96. seq--;
  97. mask >>= 1;
  98. }while(!b);
  99. }
  100. qunlock(&tw->acklock);
  101. }
  102. /*
  103. * find a string in the dictionary
  104. */
  105. static int
  106. thwmatch(ThwBlock *b, ThwBlock *eblocks, uchar **ss, uchar *esrc, ulong h)
  107. {
  108. int then, toff, w, ok;
  109. uchar *s, *t;
  110. s = *ss;
  111. if(esrc < s + MinMatch)
  112. return 0;
  113. toff = 0;
  114. for(; b < eblocks; b++){
  115. then = b->hash[(h ^ b->seq) & HashMask];
  116. toff += b->maxoff;
  117. w = (ushort)(then - b->begin);
  118. if(w >= b->maxoff)
  119. continue;
  120. /*
  121. * don't need to check for the end because
  122. * 1) s too close check above
  123. * 2) entries too close not added to hash tables
  124. */
  125. t = w + b->data;
  126. if(s[0] != t[0] || s[1] != t[1] || s[2] != t[2])
  127. continue;
  128. ok = b->edata - t;
  129. if(esrc - s > ok)
  130. esrc = s + ok;
  131. t += 3;
  132. for(s += 3; s < esrc; s++){
  133. if(*s != *t)
  134. break;
  135. t++;
  136. }
  137. *ss = s;
  138. return toff - w;
  139. }
  140. return 0;
  141. }
  142. /*
  143. * knuth vol. 3 multiplicative hashing
  144. * each byte x chosen according to rules
  145. * 1/4 < x < 3/10, 1/3 x < < 3/7, 4/7 < x < 2/3, 7/10 < x < 3/4
  146. * with reasonable spread between the bytes & their complements
  147. *
  148. * the 3 byte value appears to be as almost good as the 4 byte value,
  149. * and might be faster on some machines
  150. */
  151. /*
  152. #define hashit(c) (((ulong)(c) * 0x6b43a9) >> (24 - HashLog))
  153. */
  154. #define hashit(c) ((((ulong)(c) & 0xffffff) * 0x6b43a9b5) >> (32 - HashLog))
  155. /*
  156. * lz77 compression with single lookup in a hash table for each block
  157. */
  158. int
  159. thwack(Thwack *tw, int mustadd, uchar *dst, int ndst, Block *bsrc, ulong seq, ulong stats[ThwStats])
  160. {
  161. ThwBlock *eblocks, *b, blocks[CompBlocks];
  162. uchar *s, *ss, *sss, *esrc, *half, *twdst, *twdmax;
  163. ulong cont, cseq, bseq, cmask, code, twbits;
  164. int n, now, toff, lithist, h, len, slot, bits, use, twnbits, lits, matches, offbits, lenbits, nhist;
  165. n = BLEN(bsrc);
  166. if(n > ThwMaxBlock || n < MinMatch)
  167. return -1;
  168. twdst = dst;
  169. twdmax = dst + ndst;
  170. /*
  171. * add source to the coding window
  172. * there is always enough space
  173. */
  174. qlock(&tw->acklock);
  175. slot = tw->slot;
  176. b = &tw->blocks[slot];
  177. b->seq = seq;
  178. b->acked = 0;
  179. now = b->begin + b->maxoff;
  180. if(tw->data[slot] != nil){
  181. freeb(tw->data[slot]);
  182. tw->data[slot] = nil;
  183. }
  184. s = bsrc->rptr;
  185. b->data = s;
  186. b->edata = s + n;
  187. b->begin = now;
  188. b->maxoff = n;
  189. /*
  190. * set up the history blocks
  191. */
  192. cseq = seq;
  193. cmask = 0;
  194. *blocks = *b;
  195. b = blocks;
  196. b->maxoff = 0;
  197. b++;
  198. nhist = 0;
  199. while(b < blocks + CompBlocks){
  200. slot--;
  201. if(slot < 0)
  202. slot += EWinBlocks;
  203. if(slot == tw->slot)
  204. break;
  205. if(tw->data[slot] == nil || !tw->blocks[slot].acked)
  206. continue;
  207. bseq = tw->blocks[slot].seq;
  208. if(cseq == seq){
  209. if(seq - bseq >= MaxSeqStart)
  210. break;
  211. cseq = bseq;
  212. }else if(cseq - bseq > MaxSeqMask)
  213. break;
  214. else
  215. cmask |= 1 << (cseq - bseq - 1);
  216. *b = tw->blocks[slot];
  217. nhist += b->maxoff;
  218. b++;
  219. }
  220. qunlock(&tw->acklock);
  221. eblocks = b;
  222. *twdst++ = seq - cseq;
  223. *twdst++ = cmask;
  224. cont = (s[0] << 16) | (s[1] << 8) | s[2];
  225. esrc = s + n;
  226. half = s + (n >> 1);
  227. twnbits = 0;
  228. twbits = 0;
  229. lits = 0;
  230. matches = 0;
  231. offbits = 0;
  232. lenbits = 0;
  233. lithist = ~0;
  234. while(s < esrc){
  235. h = hashit(cont);
  236. sss = s;
  237. toff = thwmatch(blocks, eblocks, &sss, esrc, h);
  238. ss = sss;
  239. len = ss - s;
  240. for(; twnbits >= 8; twnbits -= 8){
  241. if(twdst < twdmax)
  242. *twdst++ = twbits >> (twnbits - 8);
  243. else if(!mustadd)
  244. return -1;
  245. }
  246. if(len < MinMatch){
  247. toff = *s;
  248. lithist = (lithist << 1) | (toff < 32) | (toff > 127);
  249. if(lithist & 0x1e){
  250. twbits = (twbits << 9) | toff;
  251. twnbits += 9;
  252. }else if(lithist & 1){
  253. toff = (toff + 64) & 0xff;
  254. if(toff < 96){
  255. twbits = (twbits << 10) | toff;
  256. twnbits += 10;
  257. }else{
  258. twbits = (twbits << 11) | toff;
  259. twnbits += 11;
  260. }
  261. }else{
  262. twbits = (twbits << 8) | toff;
  263. twnbits += 8;
  264. }
  265. lits++;
  266. blocks->maxoff++;
  267. /*
  268. * speed hack
  269. * check for compression progress, bail if none achieved
  270. */
  271. if(s > half){
  272. if(!mustadd && 4 * blocks->maxoff < 5 * lits)
  273. return -1;
  274. half = esrc;
  275. }
  276. if(s + MinMatch <= esrc){
  277. blocks->hash[(h ^ blocks->seq) & HashMask] = now;
  278. if(s + MinMatch < esrc)
  279. cont = (cont << 8) | s[MinMatch];
  280. }
  281. now++;
  282. s++;
  283. continue;
  284. }
  285. blocks->maxoff += len;
  286. matches++;
  287. /*
  288. * length of match
  289. */
  290. len -= MinMatch;
  291. if(len < MaxFastLen){
  292. bits = lentab[len].bits;
  293. twbits = (twbits << bits) | lentab[len].encode;
  294. twnbits += bits;
  295. lenbits += bits;
  296. }else{
  297. code = BigLenCode;
  298. bits = BigLenBits;
  299. use = BigLenBase;
  300. len -= MaxFastLen;
  301. while(len >= use){
  302. len -= use;
  303. code = (code + use) << 1;
  304. use <<= (bits & 1) ^ 1;
  305. bits++;
  306. }
  307. twbits = (twbits << bits) | (code + len);
  308. twnbits += bits;
  309. lenbits += bits;
  310. for(; twnbits >= 8; twnbits -= 8){
  311. if(twdst < twdmax)
  312. *twdst++ = twbits >> (twnbits - 8);
  313. else if(!mustadd)
  314. return -1;
  315. }
  316. }
  317. /*
  318. * offset in history
  319. */
  320. toff--;
  321. for(bits = OffBase; toff >= (1 << bits); bits++)
  322. ;
  323. if(bits < MaxOff+OffBase-1){
  324. twbits = (twbits << 3) | (bits - OffBase);
  325. if(bits != OffBase)
  326. bits--;
  327. twnbits += bits + 3;
  328. offbits += bits + 3;
  329. }else{
  330. twbits = (twbits << 4) | 0xe | (bits - (MaxOff+OffBase-1));
  331. bits--;
  332. twnbits += bits + 4;
  333. offbits += bits + 4;
  334. }
  335. twbits = (twbits << bits) | toff & ((1 << bits) - 1);
  336. for(; s != ss; s++){
  337. if(s + MinMatch <= esrc){
  338. h = hashit(cont);
  339. blocks->hash[(h ^ blocks->seq) & HashMask] = now;
  340. if(s + MinMatch < esrc)
  341. cont = (cont << 8) | s[MinMatch];
  342. }
  343. now++;
  344. }
  345. }
  346. if(twnbits & 7){
  347. twbits <<= 8 - (twnbits & 7);
  348. twnbits += 8 - (twnbits & 7);
  349. }
  350. for(; twnbits >= 8; twnbits -= 8){
  351. if(twdst < twdmax)
  352. *twdst++ = twbits >> (twnbits - 8);
  353. else if(!mustadd)
  354. return -1;
  355. }
  356. if(twdst >= twdmax && !mustadd)
  357. return -1;
  358. qlock(&tw->acklock);
  359. tw->data[tw->slot] = bsrc;
  360. tw->slot++;
  361. if(tw->slot >= EWinBlocks)
  362. tw->slot = 0;
  363. qunlock(&tw->acklock);
  364. if(twdst >= twdmax)
  365. return -1;
  366. stats[StatBytes] += blocks->maxoff;
  367. stats[StatLits] += lits;
  368. stats[StatMatches] += matches;
  369. stats[StatOffBits] += offbits;
  370. stats[StatLenBits] += lenbits;
  371. stats[StatDelay] = stats[StatDelay]*7/8 + dst[0];
  372. stats[StatHist] = stats[StatHist]*7/8 + nhist;
  373. stats[StatOutBytes] += twdst - dst;
  374. return twdst - dst;
  375. }