#include #include #include #include #include #include #include #include #include "cleanbench.h" #include "randnum.h" /************************ ** HUFFMAN COMPRESSION ** ************************/ /* ** This constant specifies the maximum number of Huffman ** compression loops the system will try for. This keeps ** the test from going off into the weeds. This is not ** a critical constant, and can be increased if your ** system is a real barn-burner. */ /*#define LOOP_MAX 50000L*/ #define LOOP_MAX 500000L /* ** Following constant sets the size of the arrays to ** be compressed/uncompressed. */ #define ARRAY_SIZE 5000 #define EXCLUDED 32000L /* Big positive value */ typedef struct { unsigned char c; /* Byte value */ float freq; /* Frequency */ int parent; /* Parent node */ int left; /* Left pointer = 0 */ int right; /* Right pointer = 1 */ } huff_node; static huff_node *hufftree; /* The huffman tree */ static void create_text_line(char *dt,long nchars); static void create_text_block(char *tb, unsigned long tblen, unsigned short maxlinlen); static clock_t DoHuffIteration(char *plaintext, char *comparray, char *decomparray, unsigned long nloops, huff_node *hufftree); static void SetCompBit(uint8_t *comparray, uint32_t bitoffset, char bitchar); static int GetCompBit(uint8_t *comparray, uint32_t bitoffset); /************** ** DoHuffman ** *************** ** Execute a huffman compression on a block of plaintext. ** Note that (as with IDEA encryption) an iteration of the ** Huffman test includes a compression AND a decompression. ** Also, the compression cycle includes building the ** Huffman tree. */ double DoHuffman(void) { char* comparray = NULL; char* decomparray = NULL; char* plaintext = NULL; clock_t total_time = 0; int iterations = 0; static bool is_adjusted = false; static int loops = 90; /* 90 since we want it to be 100 for the first iteration and add 10 before the first iteration */ /* ** Allocate memory for the plaintext and the compressed text. ** We'll be really pessimistic here, and allocate equal amounts ** for both (though we know...well, we PRESUME) the compressed ** stuff will take less than the plain stuff. ** Also note that we'll build a 3rd buffer to decompress ** into, and we preallocate space for the huffman tree. ** (We presume that the Huffman tree will grow no larger ** than 512 bytes. This is actually a super-conservative ** estimate...but, who cares?) */ plaintext = malloc(ARRAY_SIZE * sizeof(char)); comparray = malloc(ARRAY_SIZE * sizeof(char)); decomparray = malloc(ARRAY_SIZE * sizeof(char)); hufftree = malloc(sizeof(huff_node) * 512); /* ** Build the plaintext buffer. Since we want this to ** actually be able to compress, we'll use the ** wordcatalog to build the plaintext stuff. */ /* ** Reset random number generator so things repeat. ** added by Uwe F. Mayer */ randnum((int32_t)13); create_text_block(plaintext,ARRAY_SIZE-1,(unsigned short)500); plaintext[ARRAY_SIZE-1L]='\0'; /* ** See if we need to perform self adjustment loop. */ if (is_adjusted == false) { is_adjusted = true; /* ** Do self-adjustment. This involves initializing the ** # of loops and increasing the loop count until we ** get a number of loops that we can use. */ do { loops += 10; } while ((DoHuffIteration(plaintext, comparray, decomparray, loops, hufftree) <= MINIMUM_TICKS) && (loops < LOOP_MAX)); } do { total_time += DoHuffIteration(plaintext, comparray, decomparray, loops, hufftree); iterations += loops; } while (total_time < MINIMUM_SECONDS * CLOCKS_PER_SEC); free(plaintext); free(comparray); free(decomparray); free(hufftree); return (double)(iterations * CLOCKS_PER_SEC) / (double)total_time; } /********************* ** create_text_line ** ********************** ** Create a random line of text, stored at *dt. The line may be ** no more than nchars long. */ static void create_text_line(char *dt, long nchars) { long charssofar = 0; /* # of characters so far */ long tomove; /* # of characters to move */ char myword[40]; /* Local buffer for words */ char *wordptr; /* Pointer to word from catalog */ /* ** Word catalog */ #define WORDCATSIZE 50 char * wordcatarray[WORDCATSIZE] = { "Hello", "He", "Him", "the", "this", "that", "though", "rough", "cough", "obviously", "But", "but", "bye", "begin", "beginning", "beginnings", "of", "our", "ourselves", "yourselves", "to", "together", "togetherness", "from", "either", "I", "A", "return", "However", "that", "example", "yet", "quickly", "all", "if", "were", "includes", "always", "never", "not", "small", "returns", "set", "basic", "Entered", "with", "used", "shown", "you", "know" }; do { /* ** Grab a random word from the wordcatalog */ wordptr=wordcatarray[abs_randwc((int32_t)WORDCATSIZE)]; memmove(myword, wordptr, strlen(wordptr) + 1); /* ** Append a blank. */ tomove=strlen(myword)+1; myword[tomove-1]=' '; /* ** See how long it is. If its length+charssofar > nchars, we have ** to trim it. */ if((tomove+charssofar)>nchars) tomove=nchars-charssofar; /* ** Attach the word to the current line. Increment counter. */ memmove(dt, myword, tomove); charssofar+=tomove; dt+=tomove; /* ** If we're done, bail out. Otherwise, go get another word. */ } while(charssofartblen) linelen=tblen-bytessofar; if(linelen>1) { create_text_line(tb,linelen); } tb+=linelen-1; /* Add the carriage return */ *tb++='\n'; bytessofar+=linelen; } while(bytessofar>3; bitnumb=bitoffset % 8; /* ** Set or clear */ if(bitchar=='1') comparray[byteoffset]|=(1<>3; bitnumb=bitoffset % 8; /* ** Fetch */ return((1<