diff --git a/results/js/Smart.TimeResultFormatting.js b/results/js/Smart.TimeResultFormatting.js index 8996f694e..f69790435 100644 --- a/results/js/Smart.TimeResultFormatting.js +++ b/results/js/Smart.TimeResultFormatting.js @@ -75,6 +75,14 @@ function showDivs(document, divClass, show) { } } +function showDivsByName(document, divName, show) { + const divs = document.getElementsByName(divName); + const displayValue = show ? 'block' : 'none'; + for (const counter in divs) { + divs[counter].style.display = displayValue; + } +} + function findChildWithClassNames(parent, namesOfClass) { const parentChildren = parent.children; for (let counter = 0; counter < parentChildren.length; counter++) { diff --git a/results/style.css b/results/style.css index 3823e4227..7b9d05c56 100755 --- a/results/style.css +++ b/results/style.css @@ -120,6 +120,14 @@ td{ vertical-align:middle; } +.statNames { + background-color: #666666; + font-size: 11px; + text-align:center; + color: #eeeeee; + vertical-align:middle; +} + .didascalia { width: 70px; float: left; @@ -197,6 +205,55 @@ td{ color: #888888; } +.search_stats { + padding: 2px; + width: 60px; + height: 15px; + font-size: 11px; + text-align:center; + border-radius: 8px; + margin-top:3px; + margin-bottom:3px; + color: #000000; + vertical-align:middle; +} + +.search_stats_best { + padding: 2px; + background-color: Honeydew; + width: 60px; + height: 10px; + font-size: 10px; + text-align:center; + border-radius: 4px; + color: #333333; + vertical-align:middle; +} + +.search_stats_worst { + padding: 2px; + background-color: LavenderBlush; + width: 60px; + height: 10px; + font-size: 10px; + text-align:center; + vertical-align:middle; + border-radius: 4px; + color: #333333; +} + +.search_stats_none { + padding: 2px; + background-color: #ffffff; + width: 60px; + height: 15px; + font-size: 10px; + text-align:center; + vertical-align:middle; + border-radius: 4px; + color: #000000; +} + .main_container { width:1020px; } diff --git a/source/algos/hash3.c b/source/algos/hash3.c index a882bd245..faecad852 100755 --- a/source/algos/hash3.c +++ b/source/algos/hash3.c @@ -22,7 +22,9 @@ */ #include "include/define.h" -#include "include/main.h" +#include "include/mainstats.h" // defines the search interface for time and statistics. +#include "include/shiftstats.h" // implements the standard set of shift-table algorithm statistic names. + #define RANK3 3 int search(unsigned char *x, int m, unsigned char *y, int n) { @@ -82,3 +84,76 @@ int search(unsigned char *x, int m, unsigned char *y, int n) { } } } + +struct searchInfo searchStats(unsigned char *x, int m, unsigned char *y, int n) { + int count, j, i, sh, sh1, mMinus1, mMinus2, shift[WSIZE]; + unsigned char h; + if(m<3) return NO_ALGO_RESULTS; + count = 0; + mMinus1 = m-1; + mMinus2 = m-2; + + for (i = 0; i < WSIZE; ++i) + shift[i] = mMinus2; + + h = x[0]; + h = ((h<<1) + x[1]); + h = ((h<<1) + x[2]); + shift[h] = m-RANK3; + for (i=RANK3; i < mMinus1; ++i) { + h = x[i-2]; + h = ((h<<1) + x[i-1]); + h = ((h<<1) + x[i]); + shift[h] = mMinus1-i; + } + h = x[i-2]; + h = ((h<<1) + x[i-1]); + h = ((h<<1) + x[i]); + sh1 = shift[h]; + shift[h] = 0; + if(sh1==0) sh1=1; + + /* Basic search info */ + struct searchInfo results = {0}; + initStats(&results, n, WSIZE, sizeof(int)); + + /* Table stats */ + sumTable(0, &results, shift, WSIZE); + + i = mMinus1; + memcpy(y+n, x, m); + while (1) { + results.mainLoopCount++; + + sh = 1; + while (sh != 0) { + h = y[i-2]; + h = ((h<<1) + y[i-1]); + h = ((h<<1) + y[i]); + results.textBytesRead += 3; + + sh = shift[h]; + results.indexLookupCount++; + + i+=sh; + results.numShifts++; + } + if (i < n) { + results.validationCount++; + j=0; + while(++results.textBytesRead && ++results.validationBytesRead && j=m) { + results.matchCount++; + } + i+=sh1; + results.validationShifts += sh1; + results.numShifts++; + } + else { + return results; + } + } +} + diff --git a/source/algos/hash5.c b/source/algos/hash5.c index 8279af6fb..b9922756b 100755 --- a/source/algos/hash5.c +++ b/source/algos/hash5.c @@ -22,7 +22,9 @@ */ #include "include/define.h" -#include "include/main.h" +#include "include/mainstats.h" // defines the search interface for time and statistics. +#include "include/shiftstats.h" // implements the standard set of shift-table algorithm statistic names. + #define RANK5 5 int search(unsigned char *x, int m, unsigned char *y, int n) { @@ -90,3 +92,85 @@ int search(unsigned char *x, int m, unsigned char *y, int n) { } } } + + +struct searchInfo searchStats(unsigned char *x, int m, unsigned char *y, int n) { + int count,i, j,sh, shift[WSIZE], sh1, mMinus1, mMinus4; + unsigned int h; + if(m<5) return NO_ALGO_RESULTS; + + /* Preprocessing */ + count = 0; + mMinus1 = m-1; + mMinus4 = m-4; + for (i = 0; i < WSIZE; ++i) + shift[i] = mMinus4; + + h = x[0]; + h = ((h<<1) + x[1]); + h = ((h<<1) + x[2]); + h = ((h<<1) + x[3]); + h = ((h<<1) + x[4]); + shift[h%WSIZE] = m-RANK5; + for (i=RANK5; i < mMinus1; ++i) { + h = x[i-4]; + h = ((h<<1) + x[i-3]); + h = ((h<<1) + x[i-2]); + h = ((h<<1) + x[i-1]); + h = ((h<<1) + x[i]); + shift[h%WSIZE] = mMinus1-i; + } + h = x[i-4]; + h = ((h<<1) + x[i-3]); + h = ((h<<1) + x[i-2]); + h = ((h<<1) + x[i-1]); + h = ((h<<1) + x[i]); + sh1 = shift[h%WSIZE]; + shift[h%WSIZE] = 0; + if(sh1==0) sh1=1; + + /* Basic search info */ + struct searchInfo results = {0}; + initStats(&results, n, WSIZE, sizeof(int)); + + /* Table stats */ + sumTable(0, &results, shift, WSIZE); + + i = mMinus1; + memcpy(y+n, x, m); + while (1) { + results.mainLoopCount++; + + sh = 1; + while (sh != 0) { + h = y[i-4]; + h = ((h<<1) + y[i-3]); + h = ((h<<1) + y[i-2]); + h = ((h<<1) + y[i-1]); + h = ((h<<1) + y[i]); + results.textBytesRead += 5; + + sh = shift[h%WSIZE]; + results.indexLookupCount++; + + i+=sh; + results.numShifts++; + } + if (i < n) { + results.validationCount++; + j=0; + while(++results.textBytesRead && ++results.validationBytesRead && j=m) { + results.matchCount++; + } + i+=sh1; + results.validationShifts += sh1; + results.numShifts++; + } + else { + return results; + } + } +} diff --git a/source/algos/hash8.c b/source/algos/hash8.c index 1d9152937..8af579e86 100755 --- a/source/algos/hash8.c +++ b/source/algos/hash8.c @@ -22,7 +22,9 @@ */ #include "include/define.h" -#include "include/main.h" +#include "include/mainstats.h" // defines the search interface for time and statistics. +#include "include/shiftstats.h" // implements the standard set of shift-table algorithm statistic names. + #define RANK8 8 int search(unsigned char *x, int m, unsigned char *y, int n) { @@ -103,3 +105,97 @@ int search(unsigned char *x, int m, unsigned char *y, int n) { } } } + + +struct searchInfo searchStats(unsigned char *x, int m, unsigned char *y, int n) { + int i, j, sh, shift[WSIZE], sh1, mMinus1, mMinus7; + unsigned int h; + if(m<8) return NO_ALGO_RESULTS; + + /* Preprocessing */ + mMinus1 = m-1; + mMinus7 = m-7; + for (i = 0; i < WSIZE; ++i) + shift[i] = mMinus7; + + h = x[0]; + h = ((h<<1) + x[1]); + h = ((h<<1) + x[2]); + h = ((h<<1) + x[3]); + h = ((h<<1) + x[4]); + h = ((h<<1) + x[5]); + h = ((h<<1) + x[6]); + h = ((h<<1) + x[7]); + shift[h%WSIZE] = m-RANK8; + for (i=RANK8; i < mMinus1; ++i) { + h = x[i-7]; + h = ((h<<1) + x[i-6]); + h = ((h<<1) + x[i-5]); + h = ((h<<1) + x[i-4]); + h = ((h<<1) + x[i-3]); + h = ((h<<1) + x[i-2]); + h = ((h<<1) + x[i-1]); + h = ((h<<1) + x[i]); + shift[h%WSIZE] = mMinus1-i; + } + h = x[i-7]; + h = ((h<<1) + x[i-6]); + h = ((h<<1) + x[i-5]); + h = ((h<<1) + x[i-4]); + h = ((h<<1) + x[i-3]); + h = ((h<<1) + x[i-2]); + h = ((h<<1) + x[i-1]); + h = ((h<<1) + x[i]); + sh1 = shift[h%WSIZE]; + shift[h%WSIZE] = 0; + if(sh1==0) sh1=1; + + /* Basic search info */ + struct searchInfo results = {0}; + initStats(&results,n, WSIZE, sizeof(int)); + + /* Table stats */ + sumTable(0, &results, shift, WSIZE); + + /* Searching */ + i = mMinus1; + memcpy(y+n, x, m); + while (1) { + results.mainLoopCount++; + + sh = 1; + while (sh != 0) { + h = y[i-7]; + h = ((h<<1) + y[i-6]); + h = ((h<<1) + y[i-5]); + h = ((h<<1) + y[i-4]); + h = ((h<<1) + y[i-3]); + h = ((h<<1) + y[i-2]); + h = ((h<<1) + y[i-1]); + h = ((h<<1) + y[i]); + results.textBytesRead += 8; + + sh = shift[h%WSIZE]; + results.indexLookupCount++; + + i+=sh; + results.numShifts++; + } + if (i < n) { + results.validationCount++; + j=0; + while(++results.textBytesRead && ++results.validationBytesRead && j=m) { + results.matchCount++; + } + i+=sh1; + results.validationShifts += sh1; + results.numShifts++; + } + else { + return results; + } + } +} diff --git a/source/algos/include/bitstats.h b/source/algos/include/bitstats.h new file mode 100644 index 000000000..050562fa7 --- /dev/null +++ b/source/algos/include/bitstats.h @@ -0,0 +1,17 @@ +// +// Created by matt on 05/05/2022. +// + +#include "../../searchinfo.h" + +#ifndef SMART_BITSTATS_H +#define SMART_BITSTATS_H + +struct algoValueNames getAlgoValueNames() { + struct algoValueNames names = {0}; + setAlgoValueName(&names, 0, "bits", "Count of bits set in index"); + setAlgoValueName(&names, 1, "empty", "Count of empty index entries"); + return names; +} + +#endif //SMART_BITSTATS_H diff --git a/source/algos/include/bitstats2.h b/source/algos/include/bitstats2.h new file mode 100644 index 000000000..1ef7c7221 --- /dev/null +++ b/source/algos/include/bitstats2.h @@ -0,0 +1,18 @@ +// +// Created by matt on 26/05/2022. +// +#include "../../searchinfo.h" + +#ifndef SMARTC_BITSTATS2_H +#define SMARTC_BITSTATS2_H + +struct algoValueNames getAlgoValueNames() { + struct algoValueNames names = {0}; + setAlgoValueName(&names, 0, "bits1", "Count of bits set in index1"); + setAlgoValueName(&names, 1, "empty1", "Count of empty index1 entries"); + setAlgoValueName(&names, 2, "bits2", "Count of bits set in index2"); + setAlgoValueName(&names, 3, "empty2", "Count of empty index2 entries"); + return names; +} + +#endif //SMARTC_BITSTATS2_H diff --git a/source/algos/include/main.h b/source/algos/include/main.h index 8e31b94ff..27f9ace97 100755 --- a/source/algos/include/main.h +++ b/source/algos/include/main.h @@ -44,7 +44,10 @@ int main(int argc, char *argv[]) _timer = (TIMER*) malloc (sizeof(TIMER)); unsigned char *p, *t; int m, n; - if(!strcmp("shared", argv[1])) { + if(argc==2 && !strcmp("-stats", argv[1])) { + return -4; // stats not supported. + } + if(!strcmp("shared", argv[1])) { if(argc < 7) { printf("error in input parameter\nfive parameters needed when used with shared memory\n"); return 1; diff --git a/source/algos/include/mainstats.h b/source/algos/include/mainstats.h new file mode 100644 index 000000000..46820e894 --- /dev/null +++ b/source/algos/include/mainstats.h @@ -0,0 +1,354 @@ +/* + * SMART: string matching algorithms research tool. + * Copyright (C) 2012 Simone Faro and Thierry Lecroq + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + * + * contact the authors at: faro@dmi.unict.it, thierry.lecroq@univ-rouen.fr + * download the tool at: http://www.dmi.unict.it/~faro/smart/ + */ + +#include "timer.h" +#include +#include +#include +#include +#include +#include +#include "../../searchinfo.h" + +#define BEGIN_PREPROCESSING {timer_start(_timer);start = clock();} +#define BEGIN_SEARCHING {timer_start(_timer);start = clock();} +#define END_PREPROCESSING {timer_stop(_timer);end = clock();(*pre_time) = timer_elapsed(_timer)*1000;} +#define END_SEARCHING {timer_stop(_timer);end = clock();(*run_time) = timer_elapsed(_timer)*1000;} + +/* global variables used for computing preprocessing and searching times */ +double *run_time, // searching time +*pre_time; // preprocessing time +clock_t start, end; +TIMER * _timer; + + +/********************************************************************************************************* + * Main interface to implement in each search algorithm supporting runtime statistics. + */ + +/* + * The normal search function, which is timed. + * Use timing macros BEGIN_PREPROCESSING, END_PREPROCESSING, BEGIN_SEARCHING and END_SEARCHING. + * Don't measure any searchInfo stats in this function, or the timings will be negatively affected. + */ +int search(unsigned char* p, int m, unsigned char* t, int n); + +/* + * An instrumented version of the search function that is not timed, but returns running statistics. + * Take a copy of the normal search method and modify it, taking out the timing macros, and + * recording the runtime statistics of the algorithm instead, returning searchInfo rather than int. + */ +struct searchInfo searchStats(unsigned char* p, int m, unsigned char* t, int n); + +/* + * A function that returns any special algorithm statistic names used in the searchStats function. + * If only the standard stats are returned, all the names should be empty. + * If any special stats are defined, return names for those statistics here. + * A standard set of algo value stat names for many bit oriented algorithms is provided in "bitstats.h", + * (a count of empty table slots and a count of total bits set in the table), so if you need to provide + * those stats, just include the header - you don't need to implement this method. + */ +struct algoValueNames getAlgoValueNames(); + + +/********************************************************************************************************* + * Convenience function for testing a pattern against a position in the text an updating searchInfo + * to reflect how many bytes were read and to increment the match count if a match was found. + * + * This should replace calls to memcmp() when testing for a pattern match in algorithms that use it. + * + * It returns the number of matching bytes found when matching the pattern. + */ +int matchTest(struct searchInfo *info, unsigned char *p, int m, unsigned char *t, int n, int pos) { + info->validationCount++; + if (pos + m > n) { + return 0; + } + for (int i = 0; i < m; i++) { + info->textBytesRead++; + info->validationBytesRead++; + if (p[i] != t[pos + i]) { + return i; + } + } + info->matchCount++; + return m; +} + + +/********************************************************************************************************* + * Convenience functions to calculate various table statistics. + */ + +/* + * Counts the bits set in an unsigned integer. + * This is Brian Kernighan's method for counting bits, + * from https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan + */ +int countBitsSet(unsigned int value) { + unsigned int c; // c accumulates the total bits set in v + for (c = 0; value; c++) + { + value &= value - 1; // clear the least significant bit set + } + return c; +} + +/* + * Counts the number of empty table slots and the total bits set in a table of integers, + * and places the results in algorithm statistics with the given indices. + */ +void countEmptySlotsAndBitsSet(int bitValueIndex, int emptyValueIndex, struct searchInfo * searchInfo, int *table, int numEntries) { + for (int i = 0; i < numEntries; i++) { + if (table[i]) { + searchInfo->algoValues[bitValueIndex] += countBitsSet(table[i]); + } else { + searchInfo->algoValues[emptyValueIndex] += 1; + } + } +} + +/* + * Counts the number of empty table slots and the total bits set in a table of unsigned integers, + * and places the results in algorithm statistics with the given indices. + */ +void countEmptySlotsAndBitsSetU(int bitValueIndex, int emptyValueIndex, struct searchInfo * searchInfo, unsigned int *table, int numEntries) { + for (int i = 0; i < numEntries; i++) { + if (table[i]) { + searchInfo->algoValues[bitValueIndex] += countBitsSet(table[i]); + } else { + searchInfo->algoValues[emptyValueIndex] += 1; + } + } +} + +/* + * Counts the number of empty table slots and the total bits set in a table of long, + * and places the results in algorithm statistics with the given indices. + */ +void countEmptySlotsAndBitsSetL(int bitValueIndex, int emptyValueIndex, struct searchInfo * searchInfo, long *table, int numEntries) { + for (int i = 0; i < numEntries; i++) { + if (table[i]) { + searchInfo->algoValues[bitValueIndex] += countBitsSet(table[i]); + } else { + searchInfo->algoValues[emptyValueIndex] += 1; + } + } +} + +/* + * Counts the number of empty table slots and the total bits set in a table of unsigned longs, + * and places the results in algorithm statistics with the given indices. + */ +void countEmptySlotsAndBitsSetUL(int bitValueIndex, int emptyValueIndex, struct searchInfo * searchInfo, unsigned long *table, int numEntries) { + for (int i = 0; i < numEntries; i++) { + if (table[i]) { + searchInfo->algoValues[bitValueIndex] += countBitsSet(table[i]); + } else { + searchInfo->algoValues[emptyValueIndex] += 1; + } + } +} + +/* + * Counts the number of empty table slots and the total bits set in a table of char, + * and places the results in algorithm statistics with the given indices. + */ +void countEmptySlotsAndBitsSetC(int bitValueIndex, int emptyValueIndex, struct searchInfo * searchInfo, char *table, int numEntries) { + for (int i = 0; i < numEntries; i++) { + if (table[i]) { + searchInfo->algoValues[bitValueIndex] += countBitsSet(table[i]); + } else { + searchInfo->algoValues[emptyValueIndex] += 1; + } + } +} + +/* + * Adds up all the integers in a table of integers, and places the result in an algorithm statistic with the given index. + */ +void sumTable(int sumValueIndex, struct searchInfo* searchInfo, int *table, int numEntries) { + int sum = 0; + for (int i = 0; i < numEntries; i++) { + sum += table[i]; + } + searchInfo->algoValues[sumValueIndex] = sum; +} + + +/********************************************************************************************************* + * Main + */ + +int main(int argc, char *argv[]) +{ + _timer = (TIMER*) malloc (sizeof(TIMER)); + unsigned char *p, *t; + int m, n; + if(argc==2 && !strcmp("-stats", argv[1])) { + return 0; + } + if(!strcmp("-statnames", argv[1])) { // invoke with just -statnames to print a list of the names of any algo stats provided. + struct algoValueNames names = getAlgoValueNames(); + printAlgoValueNames("%s\n", &names); + } else if(!strcmp("shared", argv[1])) { + if (argc == 4 && !strcmp("-statnames", argv[2])) { //{progname} shared -statnames {shared mem for algo names struct} + struct algoValueNames *algoNames; + int snshmid; + key_t snkey = atoi(argv[3]); + if ((snshmid = shmget(snkey, sizeof(struct algoValueNames), 0666)) < 0) { + perror("shmget"); + return 1; + } + /* Now we attach the segment to our data space. */ + if ((algoNames = shmat(snshmid, NULL, 0)) == (struct algoValueNames *) -1) { + perror("shmat"); + return 1; + } + struct algoValueNames names = getAlgoValueNames(); + // printf("\nGot names:\n"); + // printAlgoValueNames("%s\n", &names); + + (*algoNames) = names; + return 0; + } + if(argc != 8 && argc != 9) { + printf("error in input parameter:\nfour, six or seven parameters needed when used with shared memory\n"); + return 1; + } + int pshmid, tshmid, eshmid, preshmid, sishmid; + /* Locate the pattern. */ + key_t pkey = atoi(argv[2]); //segment name for the pattern + m = atoi(argv[3]); //segment size for the pattern + if ((pshmid = shmget(pkey, m, 0666)) < 0) { + perror("shmget"); + return 1; + } + /* Now we attach the segment to our data space. */ + if ((p = shmat(pshmid, NULL, 0)) == (unsigned char *) -1) { + perror("shmat"); + return 1; + } + + /* Locate the text. */ + key_t tkey = atoi(argv[4]); //segment name for the text + n = atoi(argv[5]); //segment size for the text + if ((tshmid = shmget(tkey, n, 0666)) < 0) { + perror("shmget"); + return 1; + } + /* Now we attach the segment to our data space. */ + if ((t = shmat(tshmid, NULL, 0)) == (unsigned char *) -1) { + perror("shmat"); + return 1; + } + + /* 8 arguments are for statistics: {progname}, 'shared', pattern, pattern_length, text, text_length, '-stats', searchInfo */ + if (argc == 8) { + if (strcmp("-stats", argv[6])) { + printf("error in input parameter:\nthe sixth parameter should be '-stats' with seven parameters.\n"); + return 1; + } + + struct searchInfo *searchInfo; + key_t skey = atoi(argv[7]); // segment name for search info. + if ((sishmid = shmget(skey, sizeof(struct searchInfo), 0666)) < 0) { + perror("shmget"); + return 1; + } + /* Now we attach the segment to our search info variable space. */ + if ((searchInfo = shmat(sishmid, NULL, 0)) == (struct searchInfo *) -1) { + perror("shmat"); + return 1; + } + + (*searchInfo) = searchStats(p, m, t, n); + return 0; + + } else { // 9 arguments are for benchmarking: {progname}, 'shared', pattern, pattern_length, text, text_length, result, search time, pre processing time. + /* Locate the running time variable */ + key_t ekey = atoi(argv[7]); //segment name for the running time + if ((eshmid = shmget(ekey, 8, 0666)) < 0) { + perror("shmget"); + return 1; + } + /* Now we attach the segment to our time variable space. */ + if ((run_time = shmat(eshmid, NULL, 0)) == (double *) -1) { + perror("shmat"); + return 1; + } + + /* Locate the preprocessing running time variable */ + key_t prekey = atoi(argv[8]); //segment name for the preprocessing running time + if ((preshmid = shmget(prekey, 8, 0666)) < 0) { + perror("shmget"); + return 1; + } + /* Now we attach the segment to our time variable space. */ + if ((pre_time = shmat(preshmid, NULL, 0)) == (double *) -1) { + perror("shmat"); + return 1; + } + + //timer_start(_timer); + //start = clock(); + int count = search(p,m,t,n); + //timer_stop(_timer); + //end = clock(); + //(*run_time) = timer_elapsed(_timer)*1000; + + int rshmid, *result; + key_t rkey = atoi(argv[6]); //segment name for the occurrences + // Locate the int value. + if ((rshmid = shmget(rkey, 4, 0666)) < 0) { + perror("shmget"); + return 1; + } + // Now we attach the segment to our data space. + if ((result = shmat(rshmid, NULL, 0)) == (int *) -1) { + perror("shmat"); + return 1; + } + *result = count; + return 0; + } + } + else { + if(argc < 5) { + printf("error in input parameter\nfour parameters needed in standard mode\n"); + return 1; + } + p = (unsigned char*) argv[1]; + m = atoi(argv[2]); + t = (unsigned char*) argv[3]; + n = atoi(argv[4]); + if (argc == 6 && !strcmp("-stats", argv[5])) { + const struct searchInfo searchInfo = searchStats(p, m, t, n); + const struct algoValueNames names = getAlgoValueNames(); + printSearchInfo("%-32s\t%d\n", &searchInfo, &names); + } else { + int occ = search(p, m, t, n); + printf("found %d occurrences\n", occ); + return 0; + } + } +} + + + diff --git a/source/algos/include/shiftstats.h b/source/algos/include/shiftstats.h new file mode 100644 index 000000000..bb37a58e4 --- /dev/null +++ b/source/algos/include/shiftstats.h @@ -0,0 +1,16 @@ +// +// Created by matt on 09/05/2022. +// + +#include "../../searchinfo.h" + +#ifndef SMART_SHIFTSTATS_H +#define SMART_SHIFTSTATS_H + +struct algoValueNames getAlgoValueNames() { + struct algoValueNames names = {0}; + setAlgoValueName(&names, 0, "shiftsum", "Sum of shifts in the table"); + return names; +} + +#endif //SMART_SHIFTSTATS_H diff --git a/source/algos/qf23.c b/source/algos/qf23.c index 9a6a5d4f0..63d8d254c 100755 --- a/source/algos/qf23.c +++ b/source/algos/qf23.c @@ -24,7 +24,9 @@ */ #include "include/define.h" -#include "include/main.h" +#include "include/mainstats.h" // defines the search interface for time and statistics. +#include "include/bitstats.h" // implements the standard set of bit algorithm statistic names. + #define Q 2 #define S 3 @@ -83,3 +85,76 @@ int search(unsigned char *x, int m, unsigned char *y, int n) END_SEARCHING return count; } + + +struct searchInfo searchStats(unsigned char *x, int m, unsigned char *y, int n) +{ + int i, j, k, mq1=m-Q+1, B[ASIZE]; + unsigned int D, ch, mask=AMASK; + if(m <= Q) return NO_ALGO_RESULTS; + if((WORD*8) < Q) abort(); + if(ASIZE > BSIZE) return NO_ALGO_RESULTS; + + /* Preprocessing */ + for(i=0; i= 0; i--) { + ch = ((ch << S) + x[i]) & mask; + if(i < mq1) + B[ch] |= (1<<((m-i) % Q)); + } + + /* Basic search info */ + struct searchInfo results = {0}; + initStats(&results, n, ASIZE, sizeof(int)); + + /* Table stats */ + countEmptySlotsAndBitsSetU(0, 1, &results, B, ASIZE); + + /* Searching */ + int lastPos; + for(i=mq1-1; i<=n-Q; i+=mq1) { + results.mainLoopCount++; + lastPos = i; + + D = B[((y[i+1] << S) + y[i]) & mask]; + results.textBytesRead += 2; + results.indexLookupCount++; + + if( D ) { + j = i-mq1+Q; + more: + results.slowPathCount++; + i = i-Q; + if(i >= j) { + D &= B[((y[i+1] << S) + y[i]) & mask]; + results.textBytesRead += 2; + results.indexLookupCount++; + + if(D == 0) { + results.slowPathShifts += (i + mq1 - lastPos); + results.numShifts++; + continue; + } + else goto more; + } + else { /* verify potential matches */ + i = j; + k = j-Q+1; + if(j > n-m) j = n-m; + for( ; k <= j; k++) { + matchTest(&results, x, m, y, n, k); + } + results.validationShifts += (i + mq1 - lastPos); + results.numShifts++; + } + } else { + results.fastPathCount++; + results.fastPathShifts += mq1; + results.numShifts++; + } + } + return results; +} + + diff --git a/source/algos/qf24.c b/source/algos/qf24.c index 3592fb704..bf1d77020 100755 --- a/source/algos/qf24.c +++ b/source/algos/qf24.c @@ -24,7 +24,9 @@ */ #include "include/define.h" -#include "include/main.h" +#include "include/mainstats.h" // defines the search interface for time and statistics. +#include "include/bitstats.h" // implements the standard set of bit algorithm statistic names. + #define Q 2 #define S 4 @@ -83,3 +85,75 @@ int search(unsigned char *x, int m, unsigned char *y, int n) END_SEARCHING return count; } + + +struct searchInfo searchStats(unsigned char *x, int m, unsigned char *y, int n) +{ + int i, j, k, mq1=m-Q+1, B[ASIZE]; + unsigned int D, ch, mask=AMASK; + if(m <= Q) return NO_ALGO_RESULTS; + if((WORD*8) < Q) abort(); + if(ASIZE > BSIZE) return NO_ALGO_RESULTS; + + /* Preprocessing */ + for(i=0; i= 0; i--) { + ch = ((ch << S) + x[i]) & mask; + if(i < mq1) + B[ch] |= (1<<((m-i) % Q)); + } + + /* Basic search info */ + struct searchInfo results = {0}; + initStats(&results,n, ASIZE, sizeof(int)); + + /* Table stats */ + countEmptySlotsAndBitsSetU(0, 1, &results, B, ASIZE); + + /* Searching */ + int lastPos; + for(i=mq1-1; i<=n-Q; i+=mq1) { + results.mainLoopCount++; + lastPos = i; + + D = B[((y[i+1] << S) + y[i]) & mask]; + results.textBytesRead += 2; + results.indexLookupCount++; + + if( D ) { + j = i-mq1+Q; + more: + i = i-Q; + results.slowPathCount++; + if(i >= j) { + D &= B[((y[i+1] << S) + y[i]) & mask]; + results.textBytesRead += 2; + results.indexLookupCount++; + + if(D == 0) { + results.slowPathShifts += (i + mq1 - lastPos); + results.numShifts++; + continue; + } + else goto more; + } + else { /* verify potential matches */ + i = j; + k = j-Q+1; + if(j > n-m) j = n-m; + for( ; k <= j; k++) { + matchTest(&results, x, m, y, n, k); + } + results.validationShifts += (i + mq1 - lastPos); + results.numShifts++; + } + } else { + results.fastPathCount++; + results.fastPathShifts += mq1; + results.numShifts++; + } + } + return results; +} + diff --git a/source/algos/qf26.c b/source/algos/qf26.c index 6dfe3b166..5c2792345 100755 --- a/source/algos/qf26.c +++ b/source/algos/qf26.c @@ -24,7 +24,9 @@ */ #include "include/define.h" -#include "include/main.h" +#include "include/mainstats.h" // defines the search interface for time and statistics. +#include "include/bitstats.h" // implements the standard set of bit algorithm statistic names. + #define Q 2 #define S 6 @@ -83,3 +85,74 @@ int search(unsigned char *x, int m, unsigned char *y, int n) END_SEARCHING return count; } + + +struct searchInfo searchStats(unsigned char *x, int m, unsigned char *y, int n) +{ + int i, j, k, mq1=m-Q+1, B[ASIZE]; + unsigned int D, ch, mask=AMASK; + if(m <= Q) return NO_ALGO_RESULTS; + if((WORD*8) < Q) abort(); + if(ASIZE > BSIZE) return NO_ALGO_RESULTS; + + /* Preprocessing */ + for(i=0; i= 0; i--) { + ch = ((ch << S) + x[i]) & mask; + if(i < mq1) + B[ch] |= (1<<((m-i) % Q)); + } + + /* Basic search info */ + struct searchInfo results = {0}; + initStats(&results, n, ASIZE, sizeof(int)); + + /* Table stats */ + countEmptySlotsAndBitsSetU(0, 1, &results, B, ASIZE); + + /* Searching */ + int lastPos; + for(i=mq1-1; i<=n-Q; i+=mq1) { + results.mainLoopCount++; + lastPos = i; + + D = B[((y[i+1] << S) + y[i]) & mask]; + results.textBytesRead += 2; + results.indexLookupCount++; + + if( D ) { + j = i-mq1+Q; + more: + i = i-Q; + results.slowPathCount++; + if(i >= j) { + D &= B[((y[i+1] << S) + y[i]) & mask]; + results.textBytesRead += 2; + results.indexLookupCount++; + + if(D == 0) { + results.slowPathShifts += (i + mq1 - lastPos); + results.numShifts++; + continue; + } + else goto more; + } + else { /* verify potential matches */ + i = j; + k = j-Q+1; + if(j > n-m) j = n-m; + for( ; k <= j; k++) { + matchTest(&results, x, m, y, n, k); + } + results.validationShifts += (i + mq1 - lastPos); + results.numShifts++; + } + } else { + results.fastPathCount++; + results.fastPathShifts += mq1; + results.numShifts++; + } + } + return results; +} diff --git a/source/algos/qf28.c b/source/algos/qf28.c index aebd6b47d..d3dc07342 100755 --- a/source/algos/qf28.c +++ b/source/algos/qf28.c @@ -24,7 +24,9 @@ */ #include "include/define.h" -#include "include/main.h" +#include "include/mainstats.h" // defines the search interface for time and statistics. +#include "include/bitstats.h" // implements the standard set of bit algorithm statistic names. + #define Q 2 #define S 8 @@ -83,3 +85,75 @@ int search(unsigned char *x, int m, unsigned char *y, int n) END_SEARCHING return count; } + + +struct searchInfo searchStats(unsigned char *x, int m, unsigned char *y, int n) +{ + int count = 0; + int i, j, k, mq1=m-Q+1, B[ASIZE]; + unsigned int D, ch, mask=AMASK; + if(m <= Q) return NO_ALGO_RESULTS; + if((WORD*8) < Q) abort(); + if(ASIZE > BSIZE) return NO_ALGO_RESULTS; + + /* Preprocessing */ + for(i=0; i= 0; i--) { + ch = ((ch << S) + x[i]) & mask; + if(i < mq1) + B[ch] |= (1<<((m-i) % Q)); + } + + /* Basic search info */ + struct searchInfo results = {0}; + initStats(&results, n, ASIZE, sizeof(int)); + + /* Table stats */ + countEmptySlotsAndBitsSetU(0, 1, &results, B, ASIZE); + + /* Searching */ + int lastPos; + for(i=mq1-1; i<=n-Q; i+=mq1) { + results.mainLoopCount++; + lastPos = i; + + D = B[((y[i+1] << S) + y[i]) & mask]; + results.textBytesRead += 2; + results.indexLookupCount++; + + if( D ) { + j = i-mq1+Q; + more: + results.slowPathCount++; + i = i-Q; + if(i >= j) { + D &= B[((y[i+1] << S) + y[i]) & mask]; + results.textBytesRead += 2; + results.indexLookupCount++; + + if(D == 0) { + results.slowPathShifts += (i + mq1 - lastPos); + results.numShifts++; + continue; + } + else goto more; + } + else { /* verify potential matches */ + i = j; + k = j-Q+1; + if(j > n-m) j = n-m; + for( ; k <= j; k++) { + matchTest(&results, x, m, y, n, k); + } + results.validationShifts += (i + mq1 - lastPos); + results.numShifts++; + } + } else { + results.fastPathCount++; + results.fastPathShifts += mq1; + results.numShifts++; + } + } + return results; +} diff --git a/source/algos/qf33.c b/source/algos/qf33.c index a0f19ddb5..f8021b236 100755 --- a/source/algos/qf33.c +++ b/source/algos/qf33.c @@ -24,7 +24,9 @@ */ #include "include/define.h" -#include "include/main.h" +#include "include/mainstats.h" // defines the search interface for time and statistics. +#include "include/bitstats.h" // implements the standard set of bit algorithm statistic names. + #define Q 3 #define S 3 @@ -85,3 +87,83 @@ int search(unsigned char *x, int m, unsigned char *y, int n) END_SEARCHING return count; } + +struct searchInfo searchStats(unsigned char *x, int m, unsigned char *y, int n) +{ + int i, j, k, mq1=m-Q+1, B[ASIZE]; + unsigned int D, ch, mask=AMASK; + if(m <= Q) return NO_ALGO_RESULTS; + if((WORD*8) < Q) abort(); + if(ASIZE > BSIZE) return NO_ALGO_RESULTS; + + /* Preprocessing */ + for(i=0; i= 0; i--) { + ch = ((ch << S) + x[i]) & mask; + if(i < mq1) + B[ch] |= (1<<((m-i) % Q)); + } + + /* Basic search info */ + struct searchInfo results = {0}; + initStats(&results, n, ASIZE, sizeof(int)); + + /* Table stats */ + countEmptySlotsAndBitsSetU(0, 1, &results, B, ASIZE); + + /* Searching */ + int lastPos; + for(i=mq1-1; i<=n-Q; i+=mq1) { + results.mainLoopCount++; + lastPos = i; + + ch = y[i+2]; + ch = (ch<= j) { + ch = y[i+2]; + ch = (ch< n-m) j = n-m; + for( ; k <= j; k++) { + matchTest(&results, x, m, y, n, k); + } + results.validationShifts += (i + mq1 - lastPos); + results.numShifts++; + } + } else { + results.fastPathCount++; + results.fastPathShifts += mq1; + results.numShifts++; + } + } + return results; +} + + diff --git a/source/algos/qf34.c b/source/algos/qf34.c index 4cd898d66..539373f14 100755 --- a/source/algos/qf34.c +++ b/source/algos/qf34.c @@ -24,7 +24,9 @@ */ #include "include/define.h" -#include "include/main.h" +#include "include/mainstats.h" // defines the search interface for time and statistics. +#include "include/bitstats.h" // implements the standard set of bit algorithm statistic names. + #define Q 3 #define S 4 @@ -85,3 +87,81 @@ int search(unsigned char *x, int m, unsigned char *y, int n) END_SEARCHING return count; } + +struct searchInfo searchStats(unsigned char *x, int m, unsigned char *y, int n) +{ + int i, j, k, mq1=m-Q+1, B[ASIZE]; + unsigned int D, ch, mask=AMASK; + if(m <= Q) return NO_ALGO_RESULTS; + if((WORD*8) < Q) abort(); + if(ASIZE > BSIZE) return NO_ALGO_RESULTS; + + /* Preprocessing */ + for(i=0; i= 0; i--) { + ch = ((ch << S) + x[i]) & mask; + if(i < mq1) + B[ch] |= (1<<((m-i) % Q)); + } + + /* Basic search info */ + struct searchInfo results = {0}; + initStats(&results, n, ASIZE, sizeof(int)); + + /* Table stats */ + countEmptySlotsAndBitsSetU(0, 1, &results, B, ASIZE); + + /* Searching */ + int lastPos; + for(i=mq1-1; i<=n-Q; i+=mq1) { + results.mainLoopCount++; + lastPos = i; + + ch = y[i+2]; + ch = (ch<= j) { + ch = y[i+2]; + ch = (ch< n-m) j = n-m; + for( ; k <= j; k++) { + matchTest(&results, x, m, y, n, k); + } + results.validationShifts += (i + mq1 - lastPos); + results.numShifts++; + } + } else { + results.fastPathCount++; + results.fastPathShifts += mq1; + results.numShifts++; + } + } + return results; +} diff --git a/source/algos/qf36.c b/source/algos/qf36.c index e497190ff..24652f7f0 100755 --- a/source/algos/qf36.c +++ b/source/algos/qf36.c @@ -24,7 +24,9 @@ */ #include "include/define.h" -#include "include/main.h" +#include "include/mainstats.h" // defines the search interface for time and statistics. +#include "include/bitstats.h" // implements the standard set of bit algorithm statistic names. + #define Q 3 #define S 6 @@ -85,3 +87,82 @@ int search(unsigned char *x, int m, unsigned char *y, int n) END_SEARCHING return count; } + + +struct searchInfo searchStats(unsigned char *x, int m, unsigned char *y, int n) +{ + int i, j, k, mq1=m-Q+1, B[ASIZE]; + unsigned int D, ch, mask=AMASK; + if(m <= Q) return NO_ALGO_RESULTS; + if((WORD*8) < Q) abort(); + if(ASIZE > BSIZE) return NO_ALGO_RESULTS; + + /* Preprocessing */ + for(i=0; i= 0; i--) { + ch = ((ch << S) + x[i]) & mask; + if(i < mq1) + B[ch] |= (1<<((m-i) % Q)); + } + + /* Basic search info */ + struct searchInfo results = {0}; + initStats(&results,n, ASIZE, sizeof(int)); + + /* Table stats */ + countEmptySlotsAndBitsSetU(0, 1, &results, B, ASIZE); + + /* Searching */ + int lastPos; + for(i=mq1-1; i<=n-Q; i+=mq1) { + results.mainLoopCount++; + lastPos = i; + + ch = y[i+2]; + ch = (ch<= j) { + ch = y[i+2]; + ch = (ch< n-m) j = n-m; + for( ; k <= j; k++) { + matchTest(&results, x, m, y, n, k); + } + results.validationShifts += (i + mq1 - lastPos); + results.numShifts++; + } + } else { + results.fastPathCount++; + results.fastPathShifts += mq1; + results.numShifts++; + } + } + return results; +} diff --git a/source/algos/qf42.c b/source/algos/qf42.c index 2d2ff471f..487882b69 100755 --- a/source/algos/qf42.c +++ b/source/algos/qf42.c @@ -24,7 +24,9 @@ */ #include "include/define.h" -#include "include/main.h" +#include "include/mainstats.h" // defines the search interface for time and statistics. +#include "include/bitstats.h" // implements the standard set of bit algorithm statistic names. + #define Q 4 #define S 2 @@ -87,3 +89,85 @@ int search(unsigned char *x, int m, unsigned char *y, int n) END_SEARCHING return count; } + + +struct searchInfo searchStats(unsigned char *x, int m, unsigned char *y, int n) +{ + int i, j, k, mq1=m-Q+1, B[ASIZE]; + unsigned int D, ch, mask=AMASK; + if(m <= Q) return NO_ALGO_RESULTS; + if((WORD*8) < Q) abort(); + if(ASIZE > BSIZE) return NO_ALGO_RESULTS; + + /* Preprocessing */ + for(i=0; i= 0; i--) { + ch = ((ch << S) + x[i]) & mask; + if(i < mq1) + B[ch] |= (1<<((m-i) % Q)); + } + + /* Basic search info */ + struct searchInfo results = {0}; + initStats(&results, n, ASIZE, sizeof(int)); + + /* Table stats */ + countEmptySlotsAndBitsSetU(0, 1, &results, B, ASIZE); + + /* Searching */ + int lastPos; + for(i=mq1-1; i<=n-Q; i+=mq1) { + results.mainLoopCount++; + lastPos = i; + + ch = y[i+3]; + ch = (ch<= j) { + ch = y[i+3]; + ch = (ch< n-m) j = n-m; + for( ; k <= j; k++) { + matchTest(&results, x, m, y, n, k); + } + results.validationShifts += (i + mq1 - lastPos); + results.numShifts++; + } + } else { + results.fastPathCount++; + results.fastPathShifts += mq1; + results.numShifts++; + } + } + return results; +} + diff --git a/source/algos/qf43.c b/source/algos/qf43.c index bff52f8d4..1fbfba5f6 100755 --- a/source/algos/qf43.c +++ b/source/algos/qf43.c @@ -12,19 +12,21 @@ * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see - * + * * contact the authors at: faro@dmi.unict.it, thierry.lecroq@univ-rouen.fr * download the tool at: http://www.dmi.unict.it/~faro/smart/ * * This is an implementation of the QF (Q-gram Filtering) algorithm - * in Branislav Durian1, Hannu Peltola, Leena Salmela and Jorma Tarhio2 + * in Branislav Durian1, Hannu Peltola, Leena Salmela and Jorma Tarhio2 * Bit-Parallel Search Algorithms for Long Patterns * International Symposium on Experimental Algorithms (SEA 2010) * Q is the dimension of q-grams */ #include "include/define.h" -#include "include/main.h" +#include "include/mainstats.h" // defines the search interface for time and statistics. +#include "include/bitstats.h" // implements the standard set of bit algorithm statistic names. + #define Q 4 #define S 3 @@ -34,56 +36,135 @@ int search(unsigned char *x, int m, unsigned char *y, int n) { - int count = 0; - int i, j, k, mq1=m-Q+1, B[ASIZE]; - unsigned int D, ch, mask=AMASK; - if(m <= Q) return -1; - if((WORD*8) < Q) abort(); - if(ASIZE > BSIZE) return -1; - - /* Preprocessing */ - BEGIN_PREPROCESSING - for(i=0; i= 0; i--) { - ch = ((ch << S) + x[i]) & mask; - if(i < mq1) - B[ch] |= (1<<((m-i) % Q)); - } - END_PREPROCESSING - - /* Searching */ - BEGIN_SEARCHING - for(i=mq1-1; i<=n-Q; i+=mq1) { - ch = y[i+3]; - ch = (ch<= j) { - ch = y[i+3]; - ch = (ch< n-m) j = n-m; - for( ; k <= j; k++) { - if(memcmp(y+k,x,m) == 0) - count++; - } - } - } - } - END_SEARCHING - return count; + int count = 0; + int i, j, k, mq1=m-Q+1, B[ASIZE]; + unsigned int D, ch, mask=AMASK; + if(m <= Q) return -1; + if((WORD*8) < Q) abort(); + if(ASIZE > BSIZE) return -1; + + /* Preprocessing */ + BEGIN_PREPROCESSING + for(i=0; i= 0; i--) { + ch = ((ch << S) + x[i]) & mask; + if(i < mq1) + B[ch] |= (1<<((m-i) % Q)); + } + END_PREPROCESSING + + /* Searching */ + BEGIN_SEARCHING + for(i=mq1-1; i<=n-Q; i+=mq1) { + ch = y[i+3]; + ch = (ch<= j) { + ch = y[i+3]; + ch = (ch< n-m) j = n-m; + for( ; k <= j; k++) { + if(memcmp(y+k,x,m) == 0) + count++; + } + } + } + } + END_SEARCHING + return count; +} + +struct searchInfo searchStats(unsigned char *x, int m, unsigned char *y, int n) { + int i, j, k, mq1=m-Q+1, B[ASIZE]; + unsigned int D, ch, mask=AMASK; + if(m <= Q) return NO_ALGO_RESULTS; + if((WORD*8) < Q) abort(); + if(ASIZE > BSIZE) return NO_ALGO_RESULTS; + + /* Preprocessing */ + for(i=0; i= 0; i--) { + ch = ((ch << S) + x[i]) & mask; + if(i < mq1) + B[ch] |= (1<<((m-i) % Q)); + } + + /* Basic search info */ + struct searchInfo results = {0}; + initStats(&results, n, ASIZE, sizeof(int)); + + /* Table stats */ + countEmptySlotsAndBitsSetU(0, 1, &results, B, ASIZE); + + /* Instrumented Searching */ + int lastPos = mq1 - 1; + for(i=mq1-1; i<=n-Q; i+=mq1) { + results.mainLoopCount++; + lastPos = i; + + ch = y[i+3]; + ch = (ch<= j) { + ch = y[i+3]; + ch = (ch< n-m) j = n-m; + for( ; k <= j; k++) { + matchTest(&results, x, m, y, n, k); + } + results.validationShifts += ((i + mq1) - lastPos); + results.numShifts++; + } + } else { + results.fastPathCount++; + results.fastPathShifts += mq1; + results.numShifts++; + } + } + return results; } diff --git a/source/algos/qf44.c b/source/algos/qf44.c index 0f8e3eebd..83fb38f23 100755 --- a/source/algos/qf44.c +++ b/source/algos/qf44.c @@ -24,7 +24,9 @@ */ #include "include/define.h" -#include "include/main.h" +#include "include/mainstats.h" // defines the search interface for time and statistics. +#include "include/bitstats.h" // implements the standard set of bit algorithm statistic names. + #define Q 4 #define S 4 @@ -87,3 +89,83 @@ int search(unsigned char *x, int m, unsigned char *y, int n) END_SEARCHING return count; } + +struct searchInfo searchStats(unsigned char *x, int m, unsigned char *y, int n) +{ + int i, j, k, mq1=m-Q+1, B[ASIZE]; + unsigned int D, ch, mask=AMASK; + if(m <= Q) return NO_ALGO_RESULTS; + if((WORD*8) < Q) abort(); + if(ASIZE > BSIZE) return NO_ALGO_RESULTS; + + /* Preprocessing */ + for(i=0; i= 0; i--) { + ch = ((ch << S) + x[i]) & mask; + if(i < mq1) + B[ch] |= (1<<((m-i) % Q)); + } + + /* Basic search info */ + struct searchInfo results = {0}; + initStats(&results, n, ASIZE, sizeof(int)); + + /* Table stats */ + countEmptySlotsAndBitsSetU(0, 1, &results, B, ASIZE); + + /* Searching */ + int lastPos; + for(i=mq1-1; i<=n-Q; i+=mq1) { + results.mainLoopCount++; + lastPos = i; + + ch = y[i+3]; + ch = (ch<= j) { + ch = y[i+3]; + ch = (ch< n-m) j = n-m; + for( ; k <= j; k++) { + matchTest(&results, x, m, y, n, k); + } + results.validationShifts += (i + mq1 - lastPos); + results.numShifts++; + } + } else { + results.fastPathCount++; + results.fastPathShifts += mq1; + results.numShifts++; + } + } + return results; +} diff --git a/source/algos/qf62.c b/source/algos/qf62.c index 9fa0d5fec..05a1c6449 100755 --- a/source/algos/qf62.c +++ b/source/algos/qf62.c @@ -24,7 +24,9 @@ */ #include "include/define.h" -#include "include/main.h" +#include "include/mainstats.h" // defines the search interface for time and statistics. +#include "include/bitstats.h" // implements the standard set of bit algorithm statistic names. + #define Q 6 #define S 2 @@ -91,3 +93,88 @@ int search(unsigned char *x, int m, unsigned char *y, int n) END_SEARCHING return count; } + + +struct searchInfo searchStats(unsigned char *x, int m, unsigned char *y, int n) +{ + int i, j, k, mq1=m-Q+1, B[ASIZE]; + unsigned int D, ch, mask=AMASK; + if(m <= Q) return NO_ALGO_RESULTS; + if((WORD*8) < Q) abort(); + if(ASIZE > BSIZE) return NO_ALGO_RESULTS; + + /* Preprocessing */ + for(i=0; i= 0; i--) { + ch = ((ch << S) + x[i]) & mask; + if(i < mq1) + B[ch] |= (1<<((m-i) % Q)); + } + + /* Basic search info */ + struct searchInfo results = {0}; + initStats(&results,n, ASIZE, sizeof(int)); + + /* Table stats */ + countEmptySlotsAndBitsSetU(0, 1, &results, B, ASIZE); + + /* Searching */ + int lastPos; + for(i=mq1-1; i<=n-Q; i+=mq1) { + results.mainLoopCount++; + lastPos = i; + + ch = y[i+5]; + ch = (ch<= j) { + ch = y[i+5]; + ch = (ch< n-m) j = n-m; + for( ; k <= j; k++) { + matchTest(&results, x, m, y, n, k); + } + results.validationShifts += (i + mq1 - lastPos); + results.numShifts++; + } + } else { + results.fastPathCount++; + results.fastPathShifts += mq1; + results.numShifts++; + } + } + return results; +} diff --git a/source/algos/qf63.c b/source/algos/qf63.c index 24daa1931..4e5e8c58c 100755 --- a/source/algos/qf63.c +++ b/source/algos/qf63.c @@ -24,7 +24,9 @@ */ #include "include/define.h" -#include "include/main.h" +#include "include/mainstats.h" // defines the search interface for time and statistics. +#include "include/bitstats.h" // implements the standard set of bit algorithm statistic names. + #define Q 6 #define S 3 @@ -91,3 +93,88 @@ int search(unsigned char *x, int m, unsigned char *y, int n) END_SEARCHING return count; } + + +struct searchInfo searchStats(unsigned char *x, int m, unsigned char *y, int n) +{ + int i, j, k, mq1=m-Q+1, B[ASIZE]; + unsigned int D, ch, mask=AMASK; + if(m <= Q) return NO_ALGO_RESULTS; + if((WORD*8) < Q) abort(); + if(ASIZE > BSIZE) return NO_ALGO_RESULTS; + + /* Preprocessing */ + for(i=0; i= 0; i--) { + ch = ((ch << S) + x[i]) & mask; + if(i < mq1) + B[ch] |= (1<<((m-i) % Q)); + } + + /* Basic search info */ + struct searchInfo results = {0}; + initStats(&results,n, ASIZE, sizeof(int)); + + /* Table stats */ + countEmptySlotsAndBitsSetU(0, 1, &results, B, ASIZE); + + /* Searching */ + int lastPos; + for(i=mq1-1; i<=n-Q; i+=mq1) { + results.mainLoopCount++; + lastPos = i; + + ch = y[i+5]; + ch = (ch<= j) { + ch = y[i+5]; + ch = (ch< n-m) j = n-m; + for( ; k <= j; k++) { + matchTest(&results, x, m, y, n, k); + } + results.validationShifts += (i + mq1 - lastPos); + results.numShifts++; + } + } else { + results.fastPathCount++; + results.fastPathShifts += mq1; + results.numShifts++; + } + } + return results; +} diff --git a/source/output.h b/source/output.h index ec4af3e64..26c242a1f 100755 --- a/source/output.h +++ b/source/output.h @@ -16,6 +16,11 @@ * contact the authors at: faro@dmi.unict.it, thierry.lecroq@univ-rouen.fr * download the tool at: http://www.dmi.unict.it/~faro/smart/ */ +#include "searchinfo.h" + +#define STAT_NAME_COLUMN_SIZE 20 +#define STAT_TYPE_COLUMN_SIZE 6 +#define STAT_VALUE_COLUMN_SIZE 9 char colors[100][8]; int num_colors = 100; @@ -112,6 +117,12 @@ int outputPHP(double TIME[NumAlgo][NumPatt], double BEST[NumAlgo][NumPatt], doub return 1; } +void outputPaddedAlgoName(FILE *fp, char *algoName) { + fprintf(fp, "%s", str2upper(algoName)); + size_t length = strlen(algoName); + for (int i = 0; i < 20 - length; i++) fprintf(fp, " "); +} + int outputTXT(double TIME[NumAlgo][NumPatt], int alpha, char *filename, char *expcode, char *time_format) { int i, il, algo; @@ -150,6 +161,157 @@ int outputTXT(double TIME[NumAlgo][NumPatt], int alpha, char *filename, char *ex return 1; } +void outputStatRow(FILE *fp, int algo, int maxAlgoName, int maxAlgoStatNameLen, enum searchInfoStats statType, int algoStatIndex, char *resultType, + struct searchInfo INFO[NumAlgo][NumPatt], + struct algoValueNames ALGO_STAT_NAMES[NumAlgo]) { + fprintf(fp, "%-*s", maxAlgoName, str2upper(ALGO_NAME[algo])); + const struct algoValueNames *names = &(ALGO_STAT_NAMES[algo]); + const char * longName = names->longName[algoStatIndex]; + const char *statName = statType == ALGO_VALUES ? longName[0] != '\0' ? longName : names->shortName[algoStatIndex] : getStatName(statType); + fprintf(fp, "\t%-*s", maxAlgoStatNameLen, statName); + fprintf(fp, "\t%-*s", STAT_TYPE_COLUMN_SIZE, resultType); + char statValue[32]; + for(int il=0; il=MINLEN && PATT_SIZE[il]<=MAXLEN) { + struct searchInfo *info = &(INFO[algo][il]); + if (info->hasStats) { + long value = statType == ALGO_VALUES ? info->algoValues[algoStatIndex] : getStatValue(statType, info); + sprintf(statValue, "%ld", value); + fprintf(fp, "\t%*s", STAT_VALUE_COLUMN_SIZE, statValue); + } else { + fprintf(fp, "\t%*s", STAT_VALUE_COLUMN_SIZE, "-"); + } + } + fprintf(fp, "\n"); +} + +void outputStatRows(FILE *fp, int algo, int maxAlgoName, int maxAlgoStatNameLen, enum searchInfoStats statType, int algoStatIndex, + struct searchInfo AVG[NumAlgo][NumPatt], + struct searchInfo BEST[NumAlgo][NumPatt], + struct searchInfo WORST[NumAlgo][NumPatt], + struct algoValueNames ALGO_STAT_NAMES[NumAlgo]) { + outputStatRow(fp, algo, maxAlgoName, maxAlgoStatNameLen, statType, algoStatIndex, "Best", BEST, ALGO_STAT_NAMES); + outputStatRow(fp, algo, maxAlgoName, maxAlgoStatNameLen, statType, algoStatIndex, "Mean", AVG, ALGO_STAT_NAMES); + outputStatRow(fp, algo, maxAlgoName, maxAlgoStatNameLen, statType, algoStatIndex, "Worst", WORST, ALGO_STAT_NAMES); +} + +void outputTimeStatRow(FILE *fp, int algo, int maxAlgoName, int maxAlgoStatNameLen, char *resultType, double TIME[NumAlgo][NumPatt]) { + fprintf(fp, "%-*s", maxAlgoName, str2upper(ALGO_NAME[algo])); + fprintf(fp, "\t%-*s", maxAlgoStatNameLen, "Running time (ms)"); + fprintf(fp, "\t%-*s", STAT_TYPE_COLUMN_SIZE, resultType); + char statValue[32]; + for(int il=0; il=MINLEN && PATT_SIZE[il]<=MAXLEN) { + double time = TIME[algo][il]; + if (time > 0.0) { + sprintf(statValue, "%.2f", time); + fprintf(fp, "\t%*s", STAT_VALUE_COLUMN_SIZE, statValue); + } else { + fprintf(fp, "\t%*s", STAT_VALUE_COLUMN_SIZE, "-"); + } + } + fprintf(fp, "\n"); +} + +void outputTimeStatRows(FILE *fp, int algo, int maxAlgoName, int maxAlgoStatNameLen, + double MEAN_TIME[NumAlgo][NumPatt], double BEST_TIME[NumAlgo][NumPatt], double WORST_TIME[NumAlgo][NumPatt]) { + outputTimeStatRow(fp, algo, maxAlgoName, maxAlgoStatNameLen, "Best", BEST_TIME); + outputTimeStatRow(fp, algo, maxAlgoName, maxAlgoStatNameLen, "Mean", MEAN_TIME); + outputTimeStatRow(fp, algo, maxAlgoName, maxAlgoStatNameLen, "Worst", WORST_TIME); +} + + +void outputAlgoStats(FILE *fp, int algo, int maxAlgoNameLen, int maxAlgoStatNameLen, + struct searchInfo AVG[NumAlgo][NumPatt], + struct searchInfo BEST[NumAlgo][NumPatt], + struct searchInfo WORST[NumAlgo][NumPatt], + struct algoValueNames ALGO_STAT_NAMES[NumAlgo]) { + outputStatRows(fp, algo, maxAlgoNameLen, maxAlgoStatNameLen, TEXT_LENGTH, -1, AVG, BEST, WORST, ALGO_STAT_NAMES); + outputStatRows(fp, algo, maxAlgoNameLen, maxAlgoStatNameLen, SEARCH_INDEX_BYTES, -1, AVG, BEST, WORST, ALGO_STAT_NAMES); + outputStatRows(fp, algo, maxAlgoNameLen, maxAlgoStatNameLen, SEARCH_INDEX_ENTRIES, -1, AVG, BEST, WORST, ALGO_STAT_NAMES); + outputStatRows(fp, algo, maxAlgoNameLen, maxAlgoStatNameLen, SEARCH_INDEX2_ENTRIES, -1, AVG, BEST, WORST, ALGO_STAT_NAMES); + outputStatRows(fp, algo, maxAlgoNameLen, maxAlgoStatNameLen, MAIN_LOOP_COUNT, -1, AVG, BEST, WORST, ALGO_STAT_NAMES); + outputStatRows(fp, algo, maxAlgoNameLen, maxAlgoStatNameLen, NUM_SHIFTS, -1, AVG, BEST, WORST, ALGO_STAT_NAMES); + outputStatRows(fp, algo, maxAlgoNameLen, maxAlgoStatNameLen, INDEX_LOOKUP_COUNT, -1, AVG, BEST, WORST, ALGO_STAT_NAMES); + outputStatRows(fp, algo, maxAlgoNameLen, maxAlgoStatNameLen, FAST_PATH_COUNT, -1, AVG, BEST, WORST, ALGO_STAT_NAMES); + outputStatRows(fp, algo, maxAlgoNameLen, maxAlgoStatNameLen, SLOW_PATH_COUNT, -1, AVG, BEST, WORST, ALGO_STAT_NAMES); + outputStatRows(fp, algo, maxAlgoNameLen, maxAlgoStatNameLen, VALIDATION_COUNT, -1, AVG, BEST, WORST, ALGO_STAT_NAMES); + outputStatRows(fp, algo, maxAlgoNameLen, maxAlgoStatNameLen, MATCH_COUNT, -1, AVG, BEST, WORST, ALGO_STAT_NAMES); + outputStatRows(fp, algo, maxAlgoNameLen, maxAlgoStatNameLen, FAST_PATH_SHIFTS, -1, AVG, BEST, WORST, ALGO_STAT_NAMES); + outputStatRows(fp, algo, maxAlgoNameLen, maxAlgoStatNameLen, SLOW_PATH_SHIFTS, -1, AVG, BEST, WORST, ALGO_STAT_NAMES); + outputStatRows(fp, algo, maxAlgoNameLen, maxAlgoStatNameLen, VALIDATION_SHIFTS, -1, AVG, BEST, WORST, ALGO_STAT_NAMES); + outputStatRows(fp, algo, maxAlgoNameLen, maxAlgoStatNameLen, TEXT_BYTES_READ, -1, AVG, BEST, WORST, ALGO_STAT_NAMES); + outputStatRows(fp, algo, maxAlgoNameLen, maxAlgoStatNameLen, VALIDATION_BYTES_READ, -1, AVG, BEST, WORST, ALGO_STAT_NAMES); + for (int valueIndex = 0; valueIndex < MAX_ALGO_VALUES; valueIndex++) { + struct algoValueNames * names = &(ALGO_STAT_NAMES[algo]); + if (names->shortName[valueIndex][0] != '\0') { + outputStatRows(fp, algo, maxAlgoNameLen, maxAlgoStatNameLen, ALGO_VALUES, valueIndex, AVG, BEST, WORST, ALGO_STAT_NAMES); + } + } +} + +int outputStats(struct searchInfo AVG[NumAlgo][NumPatt], struct searchInfo BEST[NumAlgo][NumPatt], struct searchInfo WORST[NumAlgo][NumPatt], + double MEAN_TIME[NumAlgo][NumPatt], double BEST_TIME[NumAlgo][NumPatt], double WORST_TIME[NumAlgo][NumPatt], + char SUPPORTS_STATS[NumAlgo], + struct algoValueNames ALGO_STAT_NAMES[NumAlgo], + char *filename, char *expcode) { + int i, il, algo; + FILE *fp; + char outname[256]; + //printing results in txt format + strcpy(outname, "results/"); + strcat(outname, expcode); + //mkdir(outname,S_IROTH); + strcat(outname, "/"); + strcat(outname, filename); + strcat(outname, ".stats.txt"); + printf("\tSaving data on %s/%s.stats.txt\n",expcode,filename); + if ( !(fp = fopen(outname,"w") ) ) { + printf("\tError in writing file %s/%s.stats.txt\n",expcode,filename); + return 0; + } + + // Determine max width of algo names and algo stat names: + int maxAlgoNameLen = 0; + int maxAlgoStatNameLen = STAT_NAME_COLUMN_SIZE; + for (int algo = 0; algo < NumAlgo; algo++) if (EXECUTE[algo]) { + char *algoName = ALGO_NAME[algo]; + size_t len = strlen(algoName); + if (len > maxAlgoNameLen) maxAlgoNameLen = len; + if (SUPPORTS_STATS[algo]) { + struct algoValueNames *names = &(ALGO_STAT_NAMES[algo]); + for (int i = 0; i < MAX_ALGO_VALUES; i++) { + const char * shortName = names->shortName[i]; + const char * longName = names->longName[i]; + size_t shortLen = strlen(shortName); + size_t longLen = strlen(longName); + if (shortLen > maxAlgoStatNameLen) maxAlgoStatNameLen = shortLen; + if (longLen > maxAlgoStatNameLen) maxAlgoStatNameLen = longLen; + } + } + } + + // output table column headers + fprintf(fp, "%-*s", maxAlgoNameLen, "Algo"); + fprintf(fp, "\t%-*s", maxAlgoStatNameLen, "Statistic"); + fprintf(fp, "\t%-*s", STAT_TYPE_COLUMN_SIZE, "Type"); + char value[32]; + for(il=0; il=MINLEN && PATT_SIZE[il]<=MAXLEN) { + sprintf(value, "%d", PATT_SIZE[il]); + fprintf(fp, "\t%-*s", STAT_VALUE_COLUMN_SIZE, value); + } + fprintf(fp,"\n"); + + // output rows: + for(algo = 0; algo < NumAlgo; algo++) { + if(EXECUTE[algo] && SUPPORTS_STATS[algo]) { + outputTimeStatRows(fp, algo, maxAlgoNameLen, maxAlgoStatNameLen, MEAN_TIME, BEST_TIME, WORST_TIME); + outputAlgoStats(fp, algo, maxAlgoNameLen, maxAlgoStatNameLen, AVG, BEST, WORST, ALGO_STAT_NAMES); + } + } + + fclose(fp); + return 1; +} + int outputLatex(double TIME[NumAlgo][NumPatt], int alpha, char *filename, char *expcode, char* time_format) { int i, j,il, algo; FILE *fp; @@ -379,6 +541,120 @@ void printSTD( double TIME[NumAlgo][NumPatt], fprintf(fp,"}"); } +void printPatternStatsRow(struct searchInfo AVG_INFO[NumAlgo][NumPatt], + struct searchInfo BEST_INFO[NumAlgo][NumPatt], + struct searchInfo WORST_INFO[NumAlgo][NumPatt], + struct algoValueNames ALGO_STAT_NAMES[NumAlgo], + int algo, int tableNo, enum searchInfoStats statType, FILE *fp) { + + if (statType == ALGO_VALUES) { + struct algoValueNames *names = &(ALGO_STAT_NAMES[algo]); + for (int valueIndex = 0; valueIndex < MAX_ALGO_VALUES; valueIndex++) { + const char *shortName = names->shortName[valueIndex]; + if (shortName[0] != '\0') { + const char *longName = names->longName[valueIndex]; + const char *displayName = longName[0] != '\0' ? longName : shortName; + fprintf(fp, "%s\n", displayName); + for (int il = 0; il < NumPatt; il++) + if (PATT_SIZE[il] >= MINLEN && PATT_SIZE[il] <= MAXLEN) { + fprintf(fp, "
"); + struct searchInfo *avg = &(AVG_INFO[algo][il]); + struct searchInfo *best = &(BEST_INFO[algo][il]); + struct searchInfo *worst = &(WORST_INFO[algo][il]); + fprintf(fp, "
%ld
", tableNo, best->algoValues[valueIndex]); + if (avg->hasStats) { + fprintf(fp, "
%ld
", avg->algoValues[valueIndex]); + } else { + fprintf(fp, "
-
"); + } + fprintf(fp, "
%ld
", tableNo, worst->algoValues[valueIndex]); + fprintf(fp, "
"); + } + fprintf(fp, "\n"); + } + } + } else { + fprintf(fp, "%s\n", getStatName(statType)); + for (int il = 0; il < NumPatt; il++) + if (PATT_SIZE[il] >= MINLEN && PATT_SIZE[il] <= MAXLEN) { + fprintf(fp, "
"); + struct searchInfo *avg = &(AVG_INFO[algo][il]); + struct searchInfo *best = &(BEST_INFO[algo][il]); + struct searchInfo *worst = &(WORST_INFO[algo][il]); + fprintf(fp, "
%ld
", tableNo, getStatValue(statType, best)); + if (avg->hasStats) { + fprintf(fp, "
%ld
", getStatValue(statType, avg)); + } else { + fprintf(fp, "
-
"); + } + fprintf(fp, "
%ld
", tableNo, getStatValue(statType, worst)); + fprintf(fp, "
"); + } + fprintf(fp, "\n"); + } +} + +void printTimeStatsRow(double MEAN_TIME[NumAlgo][NumPatt], + double BEST_TIME[NumAlgo][NumPatt], + double WORST_TIME[NumAlgo][NumPatt], + int algo, int tableNo, FILE *fp) { + fprintf(fp, "Running time (ms)\n"); + for (int il = 0; il < NumPatt; il++) + if (PATT_SIZE[il] >= MINLEN && PATT_SIZE[il] <= MAXLEN) { + fprintf(fp, "
"); + double time = BEST_TIME[algo][il]; + if (time > 0.0) { + fprintf(fp, "
%.2f
", + tableNo, time); + } else { + fprintf(fp, "
", + tableNo); + } + time = MEAN_TIME[algo][il]; + if (time > 0.0) { + fprintf(fp, "
%.2f
", time); + } else { + fprintf(fp, "
-
"); + } + time = WORST_TIME[algo][il]; + if (time > 0.0) { + fprintf(fp, "
%.2f
", tableNo, time); + } else { + fprintf(fp, "
", tableNo); + } + fprintf(fp, "
"); + } + fprintf(fp, "\n"); +} + +void printSTATS(struct searchInfo AVERAGE_INFO[NumAlgo][NumPatt], + struct searchInfo BEST_INFO[NumAlgo][NumPatt], + struct searchInfo WORST_INFO[NumAlgo][NumPatt], + struct algoValueNames ALGO_STAT_NAMES[NumAlgo], + double MEAN_TIME[NumAlgo][NumPatt], + double BEST_TIME[NumAlgo][NumPatt], + double WORST_TIME[NumAlgo][NumPatt], + int algo, int tableNo, int volte, char *expcode, FILE *fp) { + printTimeStatsRow(MEAN_TIME, BEST_TIME, WORST_TIME, algo, tableNo, fp); + printPatternStatsRow(AVERAGE_INFO, BEST_INFO, WORST_INFO, ALGO_STAT_NAMES, algo, tableNo, TEXT_LENGTH, fp); + printPatternStatsRow(AVERAGE_INFO, BEST_INFO, WORST_INFO, ALGO_STAT_NAMES, algo, tableNo, SEARCH_INDEX_BYTES, fp); + printPatternStatsRow(AVERAGE_INFO, BEST_INFO, WORST_INFO, ALGO_STAT_NAMES, algo, tableNo, SEARCH_INDEX_ENTRIES, fp); + printPatternStatsRow(AVERAGE_INFO, BEST_INFO, WORST_INFO, ALGO_STAT_NAMES, algo, tableNo, SEARCH_INDEX2_ENTRIES, fp); + printPatternStatsRow(AVERAGE_INFO, BEST_INFO, WORST_INFO, ALGO_STAT_NAMES, algo, tableNo, MAIN_LOOP_COUNT, fp); + printPatternStatsRow(AVERAGE_INFO, BEST_INFO, WORST_INFO, ALGO_STAT_NAMES, algo, tableNo, NUM_SHIFTS, fp); + printPatternStatsRow(AVERAGE_INFO, BEST_INFO, WORST_INFO, ALGO_STAT_NAMES, algo, tableNo, INDEX_LOOKUP_COUNT, fp); + printPatternStatsRow(AVERAGE_INFO, BEST_INFO, WORST_INFO, ALGO_STAT_NAMES, algo, tableNo, FAST_PATH_COUNT, fp); + printPatternStatsRow(AVERAGE_INFO, BEST_INFO, WORST_INFO, ALGO_STAT_NAMES, algo, tableNo, SLOW_PATH_COUNT, fp); + printPatternStatsRow(AVERAGE_INFO, BEST_INFO, WORST_INFO, ALGO_STAT_NAMES, algo, tableNo, VALIDATION_COUNT, fp); + printPatternStatsRow(AVERAGE_INFO, BEST_INFO, WORST_INFO, ALGO_STAT_NAMES, algo, tableNo, MATCH_COUNT, fp); + printPatternStatsRow(AVERAGE_INFO, BEST_INFO, WORST_INFO, ALGO_STAT_NAMES, algo, tableNo, FAST_PATH_SHIFTS, fp); + printPatternStatsRow(AVERAGE_INFO, BEST_INFO, WORST_INFO, ALGO_STAT_NAMES, algo, tableNo, SLOW_PATH_SHIFTS, fp); + printPatternStatsRow(AVERAGE_INFO, BEST_INFO, WORST_INFO, ALGO_STAT_NAMES, algo, tableNo, VALIDATION_SHIFTS, fp); + printPatternStatsRow(AVERAGE_INFO, BEST_INFO, WORST_INFO, ALGO_STAT_NAMES, algo, tableNo, TEXT_BYTES_READ, fp); + printPatternStatsRow(AVERAGE_INFO, BEST_INFO, WORST_INFO, ALGO_STAT_NAMES, algo, tableNo, VALIDATION_BYTES_READ, fp); + printPatternStatsRow(AVERAGE_INFO, BEST_INFO, WORST_INFO, ALGO_STAT_NAMES, algo, tableNo, ALGO_VALUES, fp); +} + void printMulti( double TIME[NumAlgo][NumPatt], FILE *fp, int w, int h, char *title, int code) { @@ -444,8 +720,13 @@ int outputHTML2( double PRE_TIME[NumAlgo][NumPatt], double TIME[NumAlgo][NumPatt], double BEST[NumAlgo][NumPatt], double WORST[NumAlgo][NumPatt], - double STD[NumAlgo][NumPatt], - int pre, int dif, int alpha, int n, int volte, char *filename, char *expcode, char *time_format) { + double STD[NumAlgo][NumPatt], + char SUPPORTS_STATS[NumAlgo], + struct searchInfo TOTAL_INFO[NumAlgo][NumPatt], + struct searchInfo BEST_INFO[NumAlgo][NumPatt], + struct searchInfo WORST_INFO[NumAlgo][NumPatt], + struct algoValueNames ALGO_VALUE_NAMES[NumAlgo], + int pre, int dif, int alpha, int n, int volte, int stats, char *filename, char *expcode, char *time_format) { int i, il, algo; FILE *fp; char outname[100]; @@ -550,6 +831,7 @@ int outputHTML2( double PRE_TIME[NumAlgo][NumPatt], "
\n"); fprintf(fp,"\n", (dif? "checked" : "")); fprintf(fp,"

\n"); + fprintf(fp,"

Average Running Times
\n"); fprintf(fp,"[No canvas support]"); fprintf(fp,"
"); @@ -566,9 +848,32 @@ int outputHTML2( double PRE_TIME[NumAlgo][NumPatt], printMulti( WORST, fp, 480, 250, "Worst Running Times", 2); printMulti( BEST, fp, 480, 250, "Best Running Times", 3); + int tableNo = 2; for(algo=0; algo\n"); + fprintf(fp,"\n"); + fprintf(fp,"",PATT_SIZE[il]); + } + fprintf(fp,""); + printSTATS(TOTAL_INFO, BEST_INFO, WORST_INFO, ALGO_VALUE_NAMES, TIME, BEST, WORST, algo, tableNo, volte, expcode, fp); + fprintf(fp,"
%s", ALGO_NAME[algo]); + for(int il=0; il=MINLEN && PATT_SIZE[il]<=MAXLEN) { + fprintf(fp,"%d
\n"); + fprintf(fp, "
Table %d. Average running measurements of experimental tests n.%s for the %s algorithm. Each value is the mean of %d runs.
\n",tableNo, expcode, ALGO_NAME[algo], volte); + fprintf(fp, "If the appropriate checkboxes are selected, the measurements of the run with the best running time are shown above the mean, and the stats with the worst running time below it. \n"); + fprintf(fp, "
\n
"); + fprintf(fp, "", tableNo, tableNo, tableNo); + fprintf(fp, "
\n", tableNo); + fprintf(fp, "
"); + fprintf(fp, "", tableNo, tableNo, tableNo); + fprintf(fp, "
\n", tableNo); + fprintf(fp, "

\n"); + tableNo++; + } + } } double dymax = 0.0; @@ -624,9 +929,7 @@ int outputHTML2( double PRE_TIME[NumAlgo][NumPatt], } fprintf(fp,"multiChart2(); multiChart3();\n"); fprintf(fp,"});"); - - - fprintf(fp,"

"); + fprintf(fp,""); fprintf(fp,""); fclose(fp); return 1; diff --git a/source/searchinfo.h b/source/searchinfo.h new file mode 100644 index 000000000..39f586106 --- /dev/null +++ b/source/searchinfo.h @@ -0,0 +1,459 @@ +// +// Created by matt on 29/04/2022. +// + +#ifndef SMART_SEARCHINFO_H +#define SMART_SEARCHINFO_H + +#include +#include + +#define MAX_ALGO_VALUES 8 +#define MAX_ALGO_VALUE_NAME_LEN 32 + +/* + * A struct holding information about the operation of a search algorithm when searching a text. + * + * Notes on adapting search algorithms to gather searchInfo: + * ========================================================= + * + * Pattern validation with memcmp() + * ================================ + * Many algorithms use memcmp() to efficiently test for a pattern match. + * We usually want to count the number of bytes read for validation, so calls to memcmp should be replaced + * by calls to matchTest(), defined in mainstats.h: + * + * if(memcmp(y+k,x,m) == 0) count++; + * + * should be replaced with: + * + * matchTest(&searchInfo, x, m, y, n, k); + * + * passing in the address of your searchInfo struct, along with the pattern, pattern length, text, text length and pos + * to match at. This will increment the appropriate measurements in the searchInfo, including the match count if a + * match is found. It returns the number of bytes that successfully matched, so if you want to do something else with + * a match other than increment the match count, you can write: + * + * if (matchTest(&searchInfo, x, m, y, n, k) == m) { + * ... do whatever ... + * } + * + * + * while loop counting + * =================== + * Many algorithms use a while loop in which text bytes or index lookups are made in the main while condition, e.g. + * + * while (F[y[i]] == 0) { + * ... + * } + * + * To accurately count the text bytes read and index lookups made, they should be pre-incremented in the while condition, + * as the *first* conditions to appear. If you count them *inside* the loop, you will fail to count reads made when the + * main while test condition failed. + * + * while (++results.textBytesRead && ++results.indexLookupCount && F[y[i]] == 0) { + * ... + * } + * + */ +struct searchInfo { + /* + * Whether the struct contains any searchInfo. + * 0 indicates no searchInfo, 1 indicates there is info. + */ + char hasStats; + + /* + * The length of the text searched. + */ + long textLength; + + /* + * The number of bytes used by any search indices. + */ + long searchIndexBytes; + + /* + * The number of entries available in the main search index. + */ + long searchIndexEntries; + + /* + * The number of entries available in any secondary search index, or zero if no such entries are used. + */ + long searchIndex2Entries; + + /* + * How many times the main search loop executes. + */ + long mainLoopCount; + + /* + * The total bytes read in the text by the search algorithm. + * This should include bytes read in both the searching and validation phases of the algorithm. + */ + long textBytesRead; + + /* + * The number of times a search index is accessed. + */ + long indexLookupCount; + + /* + * How many times the algorithm follows its fast path. + * If the fast path is taken repeatedly in a loop inside the main loop, each iteration of the fast path + * loop should be counted to better understand how much work is being done (rather than just counting + * that a fast path was entered once). + * Not all algorithms have a special fast path, but many do. + */ + long fastPathCount; + + /* + * The sum of shifts obtained when the algorithm operates in its fast path. + */ + long fastPathShifts; + + /* + * How many times the algorithm follows its slow path. + * If the slow path is taken repeatedly in a loop inside the main loop, each iteration of the slow path + * loop should be counted to better understand how much work is being done (rather than just counting + * that a slow path was entered once). + * Not all algorithms have a slow path, but many do. + */ + long slowPathCount; + + /* + * The sum of shifts obtained when the algorithm operates in its slow path. + */ + long slowPathShifts; + + /* + * The number of times a match validation occurs, regardless of whether a match is found. + */ + long validationCount; + + /* + * The number of bytes read during pattern validation. + * Note: a lot of algorithms use memcmp() to determine a match quickly, but this doesn't tell us how many + * bytes have been read. + * mainstats.h defines a utility function "matchTest()" which performs all match validation at a position + * in the text and updates all of searchInfo fields appropriately. This should always be used in preference + * to memcmp(), but it's usually easier to use it even if memcmp isn't being used, just because it updates + * all the relevant searchInfo fields itself. + */ + long validationBytesRead; + + /* + * The sum of shifts obtained after the algorithm has performed a validation. + */ + long validationShifts; + + /* + * The count of the number of times the algorithm shifts ahead (not the sum of the shifts themselves). + * When the number of shifts made is low, then the average length of the shifts obtained must be large, + * and vice versa. Knowing the total shifts made is not interesting, as it always adds up to about the + * text length by the end of the search. Knowing how many times a shift was made lets us understand + * the average shifts obtained in the run. + * + * Note: we only count a shift made when the algorithm makes use of it. + * If an algorithm during its main loop adds up a few different shifts to get the final shift, we only count + * them once. It's not interesting that a final shift is determined over several calculations. + * It is interesting how many times the algorithm gets to actually use a shift. + */ + long numShifts; + + /* + * The number of occurrences found by the algorithm. + */ + int matchCount; + + /* + * Per algorithm statistic values. + * Set any of these values, and set a corresponding algorithm name in the getAlgoValueNames() function. + * If a name is set, then the statistic will be processed. + */ + long algoValues[MAX_ALGO_VALUES]; +}; + +/* + * An enum for each of the different stat types. + */ +enum searchInfoStats { + TEXT_LENGTH, + SEARCH_INDEX_BYTES, + SEARCH_INDEX_ENTRIES, + SEARCH_INDEX2_ENTRIES, + MAIN_LOOP_COUNT, + TEXT_BYTES_READ, + INDEX_LOOKUP_COUNT, + FAST_PATH_COUNT, + FAST_PATH_SHIFTS, + SLOW_PATH_COUNT, + SLOW_PATH_SHIFTS, + VALIDATION_COUNT, + VALIDATION_BYTES_READ, + VALIDATION_SHIFTS, + NUM_SHIFTS, + MATCH_COUNT, + ALGO_VALUES +}; + +/* + * Returns the name of a stat given the enum for the stat. + * If you want the actual names of the per algorithm algo values, this must be obtained from the algoValueNames struct. + */ +const char* getStatName(enum searchInfoStats stat) { + switch (stat) { + case TEXT_LENGTH: return "Text length"; + case SEARCH_INDEX_BYTES: return "Search index bytes"; + case SEARCH_INDEX_ENTRIES: return "Search index entries"; + case SEARCH_INDEX2_ENTRIES: return "Search index 2 entries"; + case MAIN_LOOP_COUNT: return "Main loop count"; + case TEXT_BYTES_READ: return "Text bytes read"; + case INDEX_LOOKUP_COUNT: return "Index lookup count"; + case FAST_PATH_COUNT: return "Fast path count"; + case FAST_PATH_SHIFTS: return "Fast path shifts"; + case SLOW_PATH_COUNT: return "Slow path count"; + case SLOW_PATH_SHIFTS: return "Slow path shifts"; + case VALIDATION_COUNT: return "Validation count"; + case VALIDATION_BYTES_READ: return "Validation bytes read"; + case VALIDATION_SHIFTS: return "Validation shifts"; + case NUM_SHIFTS: return "Number of shifts"; + case MATCH_COUNT: return "Number of matches"; + case ALGO_VALUES: return "Per algorithm stats"; + } + return "{Statname not defined}"; +} + +/* + * Returns the value of a stat in search info, given an enum for the stat. + * If you want the per algorithm stat values for the ALGO_VALUES enum, you must get that from the appropriate + * index in the searchStruct.algoValues[] array. -1 will be returned if you ask for the ALGO_VALUES stat values. + */ +const long getStatValue(enum searchInfoStats stat, struct searchInfo* info) { + switch (stat) { + case TEXT_LENGTH: return info->textLength; + case SEARCH_INDEX_BYTES: return info->searchIndexBytes; + case SEARCH_INDEX_ENTRIES: return info->searchIndexEntries; + case SEARCH_INDEX2_ENTRIES : return info->searchIndex2Entries; + case MAIN_LOOP_COUNT: return info->mainLoopCount; + case TEXT_BYTES_READ: return info->textBytesRead; + case INDEX_LOOKUP_COUNT: return info->indexLookupCount; + case FAST_PATH_COUNT: return info->fastPathCount; + case FAST_PATH_SHIFTS: return info->fastPathShifts; + case SLOW_PATH_COUNT: return info->slowPathCount; + case SLOW_PATH_SHIFTS: return info->slowPathShifts; + case VALIDATION_COUNT: return info->validationCount; + case VALIDATION_BYTES_READ: return info->validationBytesRead; + case VALIDATION_SHIFTS: return info->validationShifts; + case NUM_SHIFTS: return info->numShifts; + case MATCH_COUNT: return info->matchCount; + } + return -1; +} + +/* + * A struct holding an array of names for algorithm-specific stats. + */ +struct algoValueNames { + /* + * A short name for the statistic, which appears in the console output when benchmarking. + * The short name controls whether a statistic is processed. + * If it is empty, no stats will be reported, even if a long name is set. + */ + char shortName[MAX_ALGO_VALUES][MAX_ALGO_VALUE_NAME_LEN]; + + /* + * A slightly longer name, which appears in the final report. + */ + char longName[MAX_ALGO_VALUES][MAX_ALGO_VALUE_NAME_LEN]; +}; + + +/* + * A default struct indicating no results are available. + */ +struct searchInfo NO_ALGO_RESULTS = {0}; + + +/* + * A default struct indicating no algorithm stat names. + */ +struct algoValueNames NO_ALGO_NAMES = {0}; + + +/* + * A convenience method to initialise the stats with a number of entries and the size of each entry. + */ +void initStats(struct searchInfo* info, int n, int entries, int entrySize) { + info->hasStats = 1; + info->textLength = n; + info->searchIndexEntries = entries; + info->searchIndexBytes = entries * entrySize; +} + +/* + * A convenience method to initialise the stats with a number of entries and the size of each entry, + * for both a main search index and a secondary search index. + */ +void initStats2(struct searchInfo* info, int n, int entries, int entrySize, int entries2, int entry2Size) { + info->hasStats = 1; + info->textLength = n; + info->searchIndexEntries = entries; + info->searchIndex2Entries = entries2; + info->searchIndexBytes = (entries * entrySize) + (entries2 * entry2Size); +} + + +/* + * A convenience method to initialize stats with the number of entries and the total number of bytes. + * This is for times when the memory size isn't computable by a single set of entries with a single size + * (e.g. some algorithms have two tables using different entry sizes for each). + */ +void initStatsBytes(struct searchInfo* info, int n, int entries, int bytes) { + info->hasStats = 1; + info->textLength = n; + info->searchIndexEntries = entries; + info->searchIndexBytes = bytes; +} + + +/* + * A convenience method to set an algorithm stat name. + */ +int setAlgoValueName(struct algoValueNames *names, int index, const char *shortName, const char *longName) { + if (index >= 0 && index < MAX_ALGO_VALUES) { + strncpy(names->shortName[index], shortName, MAX_ALGO_VALUE_NAME_LEN); + strncpy(names->longName[index], longName, MAX_ALGO_VALUE_NAME_LEN); + return 0; + } + printf("WARNING: cannot set algo name at index %d, valid range is 0 to %d", index, MAX_ALGO_VALUES - 1); + return 1; +} + + +/* + * A method to initialize a stat struct with default values. + */ +void clearSearchInfo(struct searchInfo *info) { + info->hasStats = 0; + info->textLength = 0; + info->searchIndexBytes=0; + info->searchIndexEntries=0; + info->searchIndex2Entries=0; + info->mainLoopCount=0; + info->textBytesRead=0; + info->indexLookupCount=0; + info->fastPathCount=0; + info->fastPathShifts=0; + info->slowPathCount=0; + info->slowPathShifts=0; + info->validationCount=0; + info->validationBytesRead=0; + info->validationShifts=0; + info->numShifts=0; + info->matchCount=0; + for (int i = 0; i < MAX_ALGO_VALUES; i++) { + info->algoValues[i] = 0; + } +} + +/* + * Calculates the average stat info given a set of totals and the number of samples. + * The average results are placed in the averageResuts struct passed in. + */ +void buildAverageSearchInfo(struct searchInfo *infoTotals, int samples, struct searchInfo *averageResults) { + averageResults->hasStats = 1; + averageResults->textLength = infoTotals->textLength / samples; + averageResults->searchIndexBytes = infoTotals->searchIndexBytes / samples; + averageResults->searchIndexEntries = infoTotals->searchIndexEntries / samples; + averageResults->searchIndex2Entries = infoTotals->searchIndex2Entries / samples; + averageResults->mainLoopCount = infoTotals->mainLoopCount / samples; + averageResults->textBytesRead = infoTotals->textBytesRead / samples; + averageResults->indexLookupCount = infoTotals->indexLookupCount / samples; + averageResults->fastPathCount = infoTotals->fastPathCount / samples; + averageResults->fastPathShifts = infoTotals->fastPathShifts / samples; + averageResults->slowPathCount = infoTotals->slowPathCount / samples; + averageResults->slowPathShifts = infoTotals->slowPathShifts / samples; + averageResults->validationCount = infoTotals->validationCount / samples; + averageResults->validationBytesRead = infoTotals->validationBytesRead / samples; + averageResults->validationShifts = infoTotals->validationShifts / samples; + averageResults->numShifts = infoTotals->numShifts / samples; + averageResults->matchCount = infoTotals->matchCount / samples; + for (int i=0;i < MAX_ALGO_VALUES; i++) { + averageResults->algoValues[i] = infoTotals->algoValues[i] / samples; + } +} + + +/* + * Adds the values in one stat struct to another. + */ +void addSearchInfoTo(struct searchInfo *toAdd, struct searchInfo *addTo) { + addTo->hasStats = 1; + addTo->textLength += toAdd->textLength; + addTo->searchIndexBytes += toAdd->searchIndexBytes; + addTo->searchIndexEntries += toAdd->searchIndexEntries; + addTo->searchIndex2Entries += toAdd->searchIndex2Entries; + addTo->mainLoopCount += toAdd->mainLoopCount; + addTo->textBytesRead += toAdd->textBytesRead; + addTo->indexLookupCount += toAdd->indexLookupCount; + addTo->fastPathCount += toAdd->fastPathCount; + addTo->fastPathShifts += toAdd->fastPathShifts; + addTo->slowPathCount += toAdd->slowPathCount; + addTo->slowPathShifts += toAdd->slowPathShifts; + addTo->validationCount += toAdd->validationCount; + addTo->validationBytesRead += toAdd->validationBytesRead; + addTo->validationShifts += toAdd->validationShifts; + addTo->numShifts += toAdd->numShifts; + addTo->matchCount += toAdd->matchCount; + for (int i = 0; i < MAX_ALGO_VALUES; i++) { + addTo->algoValues[i] += toAdd->algoValues[i]; + } +} + + +/* + * Prints the algo value names to the console. + */ +void printAlgoValueNames(const char *format, const struct algoValueNames *valueNames) { + for (int i = 0; i < MAX_ALGO_VALUES; i++) { + const char * valueName = valueNames->shortName[i]; + if (valueName[0] != '\0') { + printf(format, valueName); + } + } +} + + +/* + * Prints all search info to the console. + */ +void printSearchInfo(const char *format, const struct searchInfo *searchInfo, const struct algoValueNames *valueNames) { + printf(format, "Text length", searchInfo->textLength); + printf(format, "Index bytes", searchInfo->searchIndexBytes); + printf(format, "Index entries", searchInfo->searchIndexEntries); + printf(format, "Index2 entries", searchInfo->searchIndex2Entries); + printf(format, "Main loop count", searchInfo->mainLoopCount); + printf(format, "Text bytes read", searchInfo->textBytesRead); + printf(format, "Index lookup count", searchInfo->indexLookupCount); + printf(format, "Fast path count", searchInfo->fastPathCount); + printf(format, "Fast path shifts", searchInfo->fastPathShifts); + printf(format, "Slow path count", searchInfo->slowPathCount); + printf(format, "Slow path shifts", searchInfo->slowPathShifts); + printf(format, "Validation count", searchInfo->validationCount); + printf(format, "Validation bytes read", searchInfo->validationBytesRead); + printf(format, "Validation shifts", searchInfo->validationShifts); + printf(format, "Num shifts", searchInfo->numShifts); + printf(format, "Match count", searchInfo->matchCount); + for (int i = 0; i < MAX_ALGO_VALUES; i++) { + const char * shortName = valueNames->shortName[i]; + if (shortName[0] != '\0') { + const char * longName = valueNames->longName[i]; + const char * nameToUse = longName[0] != '\0'? longName : shortName; + printf(format, nameToUse, searchInfo->algoValues[i]); + } + } +} + +#endif //SMART_SEARCHINFO_H diff --git a/source/smart.c b/source/smart.c index 961e511b5..f0293694c 100755 --- a/source/smart.c +++ b/source/smart.c @@ -43,7 +43,7 @@ unsigned int MINLEN = 1, MAXLEN = 4200; // min length and max length of pattern #include #include #include - +#include "searchinfo.h" void printManual() { int i=system("./logo"); @@ -64,6 +64,7 @@ void printManual() { printf("\t-dif prints the number the best and the worst running time (they refer to searching time if the -pre option is selected)\n"); printf("\t-std prints the standard deviations of the running times (it refers to searching time if the -pre option is selected)\n"); printf("\t-txt output results in txt tabular format\n"); + printf("\t-stats gather algorithm statistics (on algorithms that provide them)\n"); printf("\t-tex output results in latex tabular format\n"); printf("\t-simple P T executes a single run searching T (max 1000 chars) for occurrences of P (max 100 chars)\n"); printf("\t-h gives this help list\n"); @@ -145,6 +146,30 @@ int execute(int algo, key_t pkey, int m, key_t tkey, int n, key_t rkey, key_t ek else return -1; } +int supportsStats(int algo) { + char command[100]; + sprintf(command, "./source/bin/%s -stats",str2lower(ALGO_NAME[algo])); + int res = system(command); + if(!res) return 0; + else return -1; +} + +int getStats(int algo, key_t pkey, int m, key_t tkey, int n, key_t sikey) { + char command[100]; + sprintf(command, "./source/bin/%s shared %d %d %d %d -stats %d",str2lower(ALGO_NAME[algo]),pkey,m,tkey,n,sikey); + int res = system(command); + if(!res) return 0; + else return -1; +} + +int getStatNames(int algo, key_t snkey) { + char command[100]; + sprintf(command, "./source/bin/%s shared -statnames %d",str2lower(ALGO_NAME[algo]), snkey); + int res = system(command); + if(!res) return 0; + else return -1; +} + void setOfRandomPatterns(unsigned char **setP, int m, unsigned char *T, int n, int numpatt, unsigned char* simplePattern) { int i,j,k; for(i=0; ihasStats) { // algorithm supports stats and has set results. + addSearchInfoTo(searchInfo, &(TOTAL_INFO[algo][il])); + gotStats = 1; + } + } + + if(!pre) (*e_time) += (*pre_time); STDTIME[k] = (*e_time); TIME[algo][il] += (*e_time); PRE_TIME[algo][il] += (*pre_time); - if (BEST[algo][il]>(*e_time)) BEST[algo][il] = (*e_time); - if (WORST[algo][il]<(*e_time)) WORST[algo][il] = (*e_time); + if (BEST[algo][il]>(*e_time)) { + BEST[algo][il] = (*e_time); + if (obtainStats) BEST_INFO[algo][il] = (*searchInfo); + } + if (WORST[algo][il]<(*e_time)) { + WORST[algo][il] = (*e_time); + if (obtainStats) WORST_INFO[algo][il] = (*searchInfo); + } total_occur += occur; if(occur<=0 && (!SIMPLE)) { //timer_stop(_timer); TIME[algo][il]=0; PRE_TIME[algo][il]=0; + clearSearchInfo(&(TOTAL_INFO[algo][il])); total_occur = occur; break; } @@ -338,18 +437,33 @@ int run_setting(char *filename, key_t tkey, unsigned char* T, int n, //timer_stop(_timer); TIME[algo][il]=0; PRE_TIME[algo][il]=0; - total_occur = -2; + clearSearchInfo(&(TOTAL_INFO[algo][il])); + total_occur = -2; + gotStats = 0; break; } - } - + + if (gotStats) { + (*statNames) = NO_ALGO_NAMES; + int nameReturn = getStatNames(algo, snkey); + } + TIME[algo][il] /= (double)VOLTE; PRE_TIME[algo][il] /= (double)VOLTE; for(k=1; k<=VOLTE; k++) STD[algo][il] += pow(STDTIME[k]-TIME[algo][il],2.0); STD[algo][il] /= (double)VOLTE; STD[algo][il] = sqrt(STD[algo][il]); - + + if (gotStats) { + struct searchInfo averageSearchInfo; + buildAverageSearchInfo(&(TOTAL_INFO[algo][il]), VOLTE, &averageSearchInfo); + TOTAL_INFO[algo][il] = averageSearchInfo; + ALGO_VALUE_NAMES[algo] = (*statNames); + } else { + TOTAL_INFO[algo][il] = NO_ALGO_RESULTS; + } + if(total_occur>0 || (total_occur>=0 && SIMPLE)) { int nchar = 15; if(dif) nchar += 20; @@ -370,7 +484,24 @@ int run_setting(char *filename, key_t tkey, unsigned char* T, int n, printf("%s",data); for(i=0; i<15-strlen(data); i++) printf(" "); } - if(occ) printf("\tocc \%d",total_occur/VOLTE); + if(occ) printf("\tocc %d",total_occur/VOLTE); + if(gotStats) { + struct searchInfo averageSearchInfo = TOTAL_INFO[algo][il]; + printf("\tmem=%ld", averageSearchInfo.searchIndexBytes); + printf(", size=%ld", averageSearchInfo.searchIndexEntries); + if (averageSearchInfo.searchIndex2Entries > 0) { + printf(", size2=%ld", averageSearchInfo.searchIndex2Entries); + } + printf(", bytes=%ld", averageSearchInfo.textBytesRead); + printf(", shifts=%ld", averageSearchInfo.numShifts); + printf(", tests=%ld", averageSearchInfo.validationCount); + for (int i=0; ishortName[i]; + if(valueName[0] != '\0') { + printf(", %s=%ld", valueName, averageSearchInfo.algoValues[i]); + } + } + } printf("\n"); } else if(total_occur==0) printf("\b\b\b\b\b\b\b\b.[ERROR] \n"); @@ -385,15 +516,22 @@ int run_setting(char *filename, key_t tkey, unsigned char* T, int n, fclose(stream); printf("\tOUTPUT RUNNING TIMES %s\n", code); if(txt) outputTXT(TIME, alpha, filename, code, time_format); + if(stats) outputStats(TOTAL_INFO, BEST_INFO, WORST_INFO, TIME, BEST, WORST, SUPPORTS_STATS, ALGO_VALUE_NAMES, filename, code); outputXML(TIME, alpha, filename, code); - outputHTML2(PRE_TIME, TIME, BEST, WORST, STD, pre, dif, alpha, n, VOLTE, filename, code, time_format); + outputHTML2(PRE_TIME, TIME, BEST, WORST, STD, SUPPORTS_STATS, TOTAL_INFO, BEST_INFO, WORST_INFO, ALGO_VALUE_NAMES, pre, dif, alpha, n, VOLTE, stats, filename, code, time_format); if(tex) outputLatex(TIME, alpha, filename, code, time_format); if(php) outputPHP(TIME, BEST, WORST, STD, alpha, filename, code, dif, std); } //free shared memory shmctl(pshmid, IPC_RMID,0); shmctl(rshmid, IPC_RMID,0); - + shmctl(eshmid, IPC_RMID, 0); + shmctl(preshmid, IPC_RMID, 0); + if (stats) { + shmctl(sishmid, IPC_RMID, 0); + shmctl(snshmid, IPC_RMID, 0); + } + //free memory allocated for patterns for(i=0; i