home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #16 / NN_1992_16.iso / spool / comp / os / coherent / 3248 < prev    next >
Encoding:
Text File  |  1992-07-25  |  12.2 KB  |  316 lines

  1. Path: sparky!uunet!comp.vuw.ac.nz!zl2tnm!toyunix!don
  2. Newsgroups: comp.os.coherent
  3. Subject: Re: Int vs. Polling Disk Access
  4. Message-ID: <800206@zl2tnm.gen.nz>
  5. From: don@zl2tnm.gen.nz (Don Stokes)
  6. Date: 25 Jul 92 10:25:51 GMT
  7. Sender: news@zl2tnm.gen.nz (GNEWS Version 2.0 news poster.)
  8. Distribution: world
  9. Organization: The Wolery
  10. Lines: 304
  11.  
  12. thigpen@lambda.msfc.nasa.gov (Keith Thigpen) writes:
  13. > I got my D: hard drive up, and Coherent installed. After copying some of
  14. > the raven software onto the Coh drive, I tried to uncompress (with a work
  15. > file), and it must have taken over 15 minutes to uncompress the file.
  16. > I vaguely remember someone saying earlier that very slow disk access might
  17. > be due to using the wrong disk access method. If so, how can I change my
  18. > interrupt based access to polled access? PLEASE say that I don't have to 
  19. > reinstall.
  20.  
  21. Uncompressing with a work file is slow.  Under Coh 4 you won't need to do
  22. this, but in the mean time there is a faster way.  Attached to this message
  23. is decompr16.c, which uses multiple processes to get around the 64k limit
  24. (which is the reason a 16-bit uncompresses need a workfile -- 12bit ones 
  25. aren't a problem as they can be done in core).  It goes like a rocket compared
  26. to using a workfile.  Be aware however that it sucks every bit of machine 
  27. available (at least on my boat-anchor 8MHz '286...); don't expect to get 
  28. much else done while it runs!
  29.  
  30. This isn't my code, I make no claim to it.  I just think it's neat.  8-)
  31.  
  32. Oh yes, it does say it's for Minix, but it compiled and ran first time under
  33. Coherent (ie just cc decompr16.c).
  34.  
  35. --
  36. Don Stokes, ZL2TNM (DS555)                        don@zl2tnm.gen.nz (home)
  37. Network Manager, Computing Services Centre            don@vuw.ac.nz (work)
  38. Victoria University of Wellington, New Zealand              +64-4-495-5052
  39.  
  40. ---cut-here---
  41. /* decompr16: decompress 16bit compressed files on a 16bit Intel processor
  42.  *    running minix.
  43.  * This kludge was hacked together by John N. White on 6/30/91 and
  44.  *    is Public Domain.
  45.  * Use chmem =500 decompr16.
  46.  * decompr16 needs about 280k to run in pipe mode. (56k per copy)
  47.  *
  48.  * This program acts as a filter:
  49.  *    decompr16 < compressed_file > decompressed_file
  50.  *
  51.  * The arguments -0 to -4 causes only the corresponding pass to be done. Thus:
  52.  *    decompr16 -0 < compressed_file | decompr16 -1 | decompr16 -2 |
  53.  *         decompr16 -3 | decompr16 -4 > decompressed_file
  54.  * will also work.
  55.  * If RAM is scarce these passes can be done sequentially using tmp files.
  56.  *
  57.  * Compress uses a modified LZW compression algorithm. A compressed file
  58.  * is a set of indices into a dictionary of strings. The number of bits
  59.  * used to store each index depends on the number of entries currently
  60.  * in the dictionary. If there are between 257 and 512 entries, 9 bits
  61.  * are used. With 513 entries, 10 bits are used, etc. The initial dictionary
  62.  * consists of 0-255 (which are the corresponding chars) and 256 (which
  63.  * is a special CLEAR code). As each index in the compressed file is read,
  64.  * a new entry is added to the dictionary consisting of the current string
  65.  * with the first char of the next string appended. When the dictionary
  66.  * is full, no further entries are added. If a CLEAR code is received,
  67.  * the dictionary will be completely reset. The first two bytes of the
  68.  * compressed file are a magic number, and the third byte indicates the
  69.  * maximum number of bits, and whether the CLEAR code is used (older versions
  70.  * of compress didn't have CLEAR).
  71.  *
  72.  * This program works by forking four more copies of itself. The five
  73.  * programs form a pipeline. Copy 0 reads from stdin and writes to
  74.  * copy 1, which writes to copy 2, then to copy 3, then to copy 4 (the
  75.  * original) which writes to stdout. If given a switch -#, where # is a
  76.  * digit from 0 to 4 (example: -2), the program will run as that copy,
  77.  * reading from stdin and writing to stdout. This allows decompressing
  78.  * with very limited RAM because only one of the five passes is in
  79.  * memory at a time.
  80.  *
  81.  * The compressed data is a series of string indices (and a header at
  82.  * the beginning and an occasional CLEAR code). As these indices flow
  83.  * through the pipes, each program decodes the ones it can. The result
  84.  * of each decoding will be indices that the following programs can handle.
  85.  *
  86.  * Each of the 65536 strings in the dictionary is an earlier string with
  87.  * some character added to the end (except for the the 256 predefined
  88.  * single char strings). When new entries are made to the dictionary,
  89.  * the string index part will just be the last index to pass through.
  90.  * But the char part is the first char of the next string, which isn't
  91.  * known yet. So the string can be stored as a pair of indices. When
  92.  * this string is specified, it is converted to this pair of indices,
  93.  * which are flagged so that the first will be decoded in full while
  94.  * the second will be decoded to its first char. The dictionary takes
  95.  * 256k to store (64k strings of 2 indices of 2 bytes each). This is
  96.  * too big for a 64k data segment, so it is divided into 5 equal parts.
  97.  * Copy 0 of the program maintains the high part and copy 4 holds the
  98.  * low part.
  99.  */
  100.  
  101. #define BUFSZ        256        /* size of i/o buffers */
  102. #define BUFSZ_2        (BUFSZ/2)    /* # of unsigned shorts in i/o bufs */
  103. #define DICTSZ        (unsigned)13056    /* # of local dictionary entries */
  104. #define EOF_INDEX    (unsigned short)0xFFFF    /* EOF flag for pipeline */
  105.  
  106. int pipein=0, pipeout=1;    /* file nums for pipeline input and output */
  107. int fildes[2];            /* for use with pipe() */
  108. int ibufp, obufp, ibufe;    /* pointers to bufs, (inp, output, end) */
  109. int ipbufp=BUFSZ_2, opbufp;    /* pointers to pipe bufs */
  110. int pnum= -1;            /* ID of this copy */
  111. unsigned short ipbuf[BUFSZ_2];    /* for buffering input */
  112. unsigned short opbuf[BUFSZ_2];    /* for buffering output */
  113. unsigned char *ibuf=(unsigned char*)ipbuf, *obuf=(unsigned char*)opbuf;
  114.  
  115. unsigned short    dindex[DICTSZ];    /* dictionary: index to substring */
  116. unsigned short    dchar[DICTSZ];    /* dictionary: last char of string */
  117. unsigned iindex, tindex, tindex2;/* holds index being processed */
  118. unsigned base;            /* where in global dict local dict starts */
  119. unsigned tbase;
  120. unsigned locend;        /* where in global dict local dict ends */
  121. unsigned curend=256;        /* current end of global dict */
  122. unsigned maxend;        /* max end of global dict */
  123. int dcharp;            /* ptr to dchar that needs next index entry */
  124. int curbits;            /* number of bits for getbits() to read */
  125. int maxbits;            /* limit on number of bits */
  126. int clearflg;            /* if set, allow CLEAR */
  127. int inmod;            /* mod 8 for getbits() */
  128.  
  129. main(argc, argv) char **argv; {
  130.   int i;
  131.  
  132.   /* check for arguments */
  133.   if(argc>=2){
  134.     if(**++argv != '-' || (pnum = (*argv)[1]-'0') < 0 || pnum > 4)
  135.       die("bad args\n");
  136.   }
  137.  
  138.   if(pnum<=0){                /* if this is pass 0 */
  139.     /* check header of compressed file */
  140.     if(mygetc() != 0x1F || mygetc() != 0x9D)/* check magic number */
  141.       die("not a compressed file\n");
  142.     iindex=mygetc();            /* get compression style */
  143.   } else getpipe();                /* get compression style */
  144.   maxbits = iindex&0x1F;
  145.   clearflg = (iindex&0x80) != 0;
  146.   if(maxbits<9 || maxbits>16)            /* check for valid maxbits */
  147.     die("can't decompress\n");
  148.   if((pnum & ~3) == 0) putpipe(iindex, 0);    /* pass style to next copy */
  149.  
  150.   if(pnum<0){            /* if decompr should set up pipeline */
  151.     /* fork copies and setup pipeline */
  152.     for(pnum=0; pnum<4; pnum++){        /* do four forks */
  153.         if(pipe(fildes)) die("pipe() error\n");
  154.         if((i=fork()) == -1) die("fork() error\n");
  155.         if(i){                /* if this is the copy */
  156.             pipeout = fildes[1];
  157.             break;
  158.         }
  159.         /* if this is the original */
  160.         pipein = fildes[0];
  161.         close(fildes[1]);        /* don't accumulate these */
  162.     }
  163.   }
  164.  
  165.   /* Preliminary inits. Note: end/maxend/curend are highest, not highest+1 */
  166.   base = DICTSZ*(4-pnum) + 256, locend = base+DICTSZ-1;
  167.   maxend = (1<<maxbits)-1;
  168.   if(maxend>locend) maxend=locend;
  169.  
  170.   for(;;){
  171.     curend = 255+clearflg;        /* init dictionary */
  172.     dcharp = DICTSZ;        /* flag for none needed */
  173.     curbits = 9;            /* init curbits (for copy 0) */
  174.     for(;;){    /* for each index in input */
  175.         if(pnum) getpipe();    /* get next index */
  176.         else{            /* get index using getbits() */
  177.             if(curbits<maxbits && (1<<curbits)<=curend){
  178.                 /* curbits needs to be increased */
  179.                 /* due to uglyness in compress, these indices
  180.                  * in the compressed file are wasted */
  181.                 while(inmod) getbits();
  182.                 curbits++;
  183.             }
  184.             getbits();
  185.         }
  186.         if(iindex==256 && clearflg){
  187.             if(pnum<4) putpipe(iindex, 0);
  188.             /* due to uglyness in compress, these indices
  189.              * in the compressed file are wasted */
  190.             while(inmod) getbits();
  191.             break;
  192.         }
  193.         tindex=iindex;
  194.         /* convert the index part, ignoring spawned chars */
  195.         while(tindex>=base) tindex = dindex[tindex-base];
  196.         putpipe(tindex, 0);    /* pass on the index */
  197.         /* save the char of the last added entry, if any */
  198.         if(dcharp<DICTSZ) dchar[dcharp++] = tindex;
  199.         if(curend<maxend)    /* if still building dictionary */
  200.           if(++curend >= base)
  201.             dindex[dcharp=(curend-base)] = iindex;
  202.         /* Do spawned chars. They are naturally produced in the wrong
  203.          * order. To get them in the right order without using memory,
  204.          * a series of passes, progressively less deep, are used */
  205.         tbase = base;
  206.         while((tindex=iindex) >= tbase){/* for each char to spawn */
  207.             while((tindex2=dindex[tindex-base]) >= tbase)
  208.               tindex=tindex2;    /* scan to desired char */
  209.             putpipe(dchar[tindex-base], 1);/* put it to the pipe */
  210.             tbase=tindex+1;
  211.         }
  212.     }
  213.   }
  214. }
  215.  
  216. /* If s, write to stderr. Flush buffers if needed. Then exit. */
  217. die(s) char *s; {
  218.   static int recurseflag=0;
  219.   if(recurseflag++) exit(1);
  220.   if(s) while(*s) write(2, s++, 1);
  221.   if(obufp) write(1, obuf, obufp);       /* flush stdout buf if needed */
  222.   do putpipe(EOF_INDEX, 0); while(opbufp); /* flush pipe if needed */
  223.   exit(s ? 1 : 0);
  224. }
  225.  
  226. /* Put a char to stdout. */
  227. myputc(c){
  228.   obuf[obufp++] = c;
  229.   if(obufp >= BUFSZ){            /* if stdout buf full */
  230.     write(1, obuf, BUFSZ);        /*   flush to stdout */
  231.     obufp=0;
  232.   }
  233. }
  234.  
  235. /* Get a char from stdin. If EOF, then die() and exit. */
  236. mygetc(){
  237.   unsigned u;
  238.   if(ibufp >= ibufe){        /* if stdin buf empty */
  239.     if((ibufe = read(0, ibuf, BUFSZ)) <= 0)
  240.       die(0);        /* if EOF, do normal exit */
  241.     ibufp=0;
  242.   }
  243.   return(ibuf[ibufp++]);
  244. }
  245.  
  246. /* Put curbits bits into index from stdin. Note: only copy 0 uses this.
  247.  * The bits within a byte are in the correct order. But when the bits
  248.  * cross a byte boundry, the lowest bits will be in the higher part of
  249.  * the current byte, and the higher bits will be in the lower part of
  250.  * the next byte. */
  251. getbits(){
  252.   int have;
  253.   static unsigned curbyte;    /* byte having bits extracted from it */
  254.   static int left;        /* how many bits are left in curbyte */
  255.  
  256.   inmod = (inmod+1) & 7;    /* count input mod 8 */
  257.   iindex=curbyte, have=left;
  258.   if(curbits-have > 8) iindex |= (unsigned)mygetc() << have, have+=8;
  259.   iindex |= ((curbyte=mygetc()) << have) & ~((unsigned)0xFFFF << curbits);
  260.   curbyte >>= curbits-have, left = 8 - (curbits-have);
  261. }
  262.  
  263. /* Get an index from the pipeline. If flagged firstonly, handle it here. */
  264. getpipe(){
  265.   static short flags;
  266.   static int n=0;    /* number of flags in flags */
  267.  
  268.   for(;;){        /* while index with firstonly flag set */
  269.     if(n<=0){
  270.         if(ipbufp >= BUFSZ_2){    /* if pipe input buf empty */
  271.             if(read(pipein, (char*)ipbuf, BUFSZ) != BUFSZ)
  272.               die("bad pipe read\n");
  273.             ipbufp=0;
  274.         }
  275.         flags = ipbuf[ipbufp++];
  276.         n = 15;
  277.     }
  278.     iindex = ipbuf[ipbufp++];
  279.     if(iindex>curend)
  280.       die(iindex == EOF_INDEX ? 0 : "invalid data\n");
  281.     flags<<=1, n--;
  282.     /* assume flags<0 if highest remaining flag is set */
  283.     if(flags>=0)        /* if firstonly flag for index is not set */
  284.       return;        /* return with valid non-firstonly index */
  285.     /* handle firstonly case here */
  286.     while(iindex>=base) iindex = dindex[iindex-base];
  287.     putpipe(iindex, 1);
  288.   }
  289. }
  290.  
  291. /* put an index to the pipeline */
  292. putpipe(u, flag) unsigned u; {
  293.   static unsigned short flags, *flagp;
  294.   static int n=0;    /* number of flags in flags */
  295.  
  296.   if(pnum==4){        /* if we should write to stdout */
  297.     myputc(u);    /* index will BE the char value */
  298.     return;
  299.   }
  300.  
  301.   if(n==0)            /* if we need to reserve a flag entry */
  302.     flags=0, flagp = opbuf + opbufp++;
  303.   opbuf[opbufp++] = u;        /* add index to buffer */
  304.   flags = (flags<<1) | flag;    /* add firstonly flag */
  305.   if(++n >= 15){        /* if block of 15 indicies */
  306.     n=0, *flagp=flags;    /*   insert flags entry */
  307.     if(opbufp >= BUFSZ_2){    /* if pipe out buf full */
  308.         opbufp=0;
  309.         if(write(pipeout, (char*)opbuf, BUFSZ) != BUFSZ)
  310.           die("bad pipe write\n");
  311.     }
  312.   }
  313. }
  314.  
  315.